""" Load and process shelter data from the pipeline-ready CSV. Schema: shelter_name, union, upazila, district, shelter_type, capacity Source: data/raw/shelters/shelters_coxs_bazar_pipeline_ready.csv (610 records) """ import pandas as pd import logging from src.config import SHELTER_DATA_FILE, PROCESSED_SHELTERS, PROCESSED_DIR logger = logging.getLogger(__name__) EXPECTED_COLUMNS = [ "shelter_name", "union", "upazila", "district", "shelter_type", "capacity" ] def load_shelters() -> pd.DataFrame: """ Load shelter CSV, validate schema, and return a clean DataFrame. Also saves a processed GeoJSON stub (tabular, no geometry yet) for downstream spatial joins with union boundaries. Returns: pd.DataFrame with 610 shelter records. """ logger.info("Loading shelter data...") if not SHELTER_DATA_FILE.exists(): raise FileNotFoundError( f"Shelter data file not found: {SHELTER_DATA_FILE}\n" "Expected the pipeline-ready CSV at this path." ) df = pd.read_csv(SHELTER_DATA_FILE) logger.info(f"Loaded {len(df)} shelter records from {SHELTER_DATA_FILE.name}") # ── Schema validation ───────────────────────────────────────────────── missing = [c for c in EXPECTED_COLUMNS if c not in df.columns] if missing: raise ValueError( f"Shelter CSV missing required columns: {missing}\n" f"Found columns: {list(df.columns)}" ) # ── Type enforcement ────────────────────────────────────────────────── df["capacity"] = pd.to_numeric(df["capacity"], errors="coerce").fillna(0).astype(int) # ── Strip whitespace from string columns ────────────────────────────── for col in ["shelter_name", "union", "upazila", "district", "shelter_type"]: df[col] = df[col].astype(str).str.strip() # ── Summary stats ───────────────────────────────────────────────────── total_capacity = df["capacity"].sum() types = df["shelter_type"].value_counts().to_dict() upazilas = sorted(df["upazila"].unique()) logger.info(f" Total capacity: {total_capacity:,}") logger.info(f" Shelter types: {types}") logger.info(f" Upazilas ({len(upazilas)}): {upazilas}") # ── Save processed CSV ──────────────────────────────────────────────── PROCESSED_DIR.mkdir(parents=True, exist_ok=True) processed_csv = PROCESSED_DIR / "shelters_processed.csv" df.to_csv(processed_csv, index=False) logger.info(f"Saved processed shelters → {processed_csv}") return df if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") shelters = load_shelters() print(f"\n✅ {len(shelters)} shelters loaded successfully") print(f" Total capacity: {shelters['capacity'].sum():,}") print(f" Types: {shelters['shelter_type'].nunique()}") print(f" Upazilas: {shelters['upazila'].nunique()}")