"""Central configuration: column schema, feature metadata, and file paths. Kept in one place so the training pipeline, the API, and the frontend all agree on exactly which fields exist and how they are named. """ from pathlib import Path # ---------------------------------------------------------------------------- # Paths # ---------------------------------------------------------------------------- PACKAGE_ROOT = Path(__file__).resolve().parent PROJECT_ROOT = PACKAGE_ROOT.parents[1] DATA_PATH = PROJECT_ROOT / "data" / "chronic_kidney_disease.csv" MODELS_DIR = PROJECT_ROOT / "models" MODEL_PATH = MODELS_DIR / "ckd_pipeline.joblib" METRICS_PATH = MODELS_DIR / "metrics.json" # ---------------------------------------------------------------------------- # Column schema (UCI Chronic Kidney Disease dataset, ID 336) # ---------------------------------------------------------------------------- NUMERIC_COLUMNS = [ "age", "bp", "sg", "al", "su", "bgr", "bu", "sc", "sod", "pot", "hemo", "pcv", "wbcc", "rbcc", ] CAT_COLUMNS = ["rbc", "pc", "pcc", "ba", "htn", "dm", "cad", "appet", "pe", "ane"] ENGINEERED_COLUMNS = ["kidney_stress_index", "anemia_risk", "age_bp_risk", "age_group"] MODEL_COLUMNS = NUMERIC_COLUMNS + CAT_COLUMNS + ENGINEERED_COLUMNS RAW_INPUT_COLUMNS = NUMERIC_COLUMNS + CAT_COLUMNS # Human-readable labels + valid category values, consumed by the API/frontend. FEATURE_LABELS = { "age": "Age (years)", "bp": "Blood Pressure (mm/Hg)", "sg": "Specific Gravity", "al": "Albumin (0-5)", "su": "Sugar (0-5)", "bgr": "Blood Glucose Random (mgs/dl)", "bu": "Blood Urea (mgs/dl)", "sc": "Serum Creatinine (mgs/dl)", "sod": "Sodium (mEq/L)", "pot": "Potassium (mEq/L)", "hemo": "Hemoglobin (gms)", "pcv": "Packed Cell Volume", "wbcc": "White Blood Cell Count (cells/cmm)", "rbcc": "Red Blood Cell Count (millions/cmm)", "rbc": "Red Blood Cells", "pc": "Pus Cell", "pcc": "Pus Cell Clumps", "ba": "Bacteria", "htn": "Hypertension", "dm": "Diabetes Mellitus", "cad": "Coronary Artery Disease", "appet": "Appetite", "pe": "Pedal Edema", "ane": "Anemia", } # Allowed values for categorical inputs (normalized, lowercase). CATEGORICAL_CHOICES = { "rbc": ["normal", "abnormal"], "pc": ["normal", "abnormal"], "pcc": ["present", "notpresent"], "ba": ["present", "notpresent"], "htn": ["yes", "no"], "dm": ["yes", "no"], "cad": ["yes", "no"], "appet": ["good", "poor"], "pe": ["yes", "no"], "ane": ["yes", "no"], } # Reference ranges for the lightweight, rule-based "why" explanation shown with # each prediction. Ranges are typical adult clinical reference intervals; they # power an intuitive flag ("low"/"high") without a heavy SHAP dependency in the # serving path. Deeper SHAP analysis lives in notebooks/analysis.ipynb. REFERENCE_RANGES = { "hemo": (13.5, 17.5, "gms"), "sc": (0.6, 1.3, "mgs/dl"), "bu": (7, 20, "mgs/dl"), "pcv": (40, 54, "%"), "rbcc": (4.5, 5.9, "millions/cmm"), "sod": (135, 145, "mEq/L"), "pot": (3.5, 5.1, "mEq/L"), "bgr": (70, 140, "mgs/dl"), "bp": (60, 120, "mm/Hg"), } RANDOM_STATE = 42 TEST_SIZE = 0.2