# Author: Simon-Pierre Boucher — contact@spboucher.ai """ Central configuration: project paths and pipeline constants. Every path is derived from the repository root so the pipeline can run from any working directory. Output directories are created on import. """ from pathlib import Path # ── repository layout ──────────────────────────────────────────────────────── ROOT = Path(__file__).resolve().parent.parent DATA_RAW = ROOT / "data" / "raw" DATA_PROCESSED = ROOT / "data" / "processed" FIG_DIR = ROOT / "figures" TABLE_DIR = ROOT / "results" / "tables" LOG_DIR = ROOT / "results" / "logs" # Raw inputs (not distributed with the repository; see data/raw/README.md) AIRBNB_RAW = DATA_RAW / "airbnb.csv" RENT_RAW = DATA_RAW / "rent.json" # Processed datasets AIRBNB_CLEAN = DATA_PROCESSED / "airbnb_clean.parquet" RENT_CLEAN = DATA_PROCESSED / "rent_clean.parquet" MERGED_SPATIAL = DATA_PROCESSED / "merged_spatial.parquet" MERGED_NEIGHBORHOOD = DATA_PROCESSED / "merged_neighborhood.parquet" MERGED_ANALYSIS = DATA_PROCESSED / "merged_analysis.parquet" # ── pipeline constants ─────────────────────────────────────────────────────── # Buffer radii (km) for the spatial merge and robustness checks BUFFER_KM = [0.25, 0.5, 1.0, 2.0] # Rental rows per chunk in the vectorised Haversine merge CHUNK_SIZE = 500 EARTH_RADIUS_KM = 6_371.0 # Random seed for the ML robustness models (train/test split and estimators) RANDOM_STATE = 42 for _d in (DATA_PROCESSED, FIG_DIR, TABLE_DIR, LOG_DIR): _d.mkdir(parents=True, exist_ok=True) def require(path: Path, hint: str) -> Path: """Return *path* if it exists, otherwise abort with a clear message.""" if not path.exists(): raise SystemExit( f"Missing input: {path}\n{hint}" ) return path