""" The production model being audited: logistic regression over 7 synthetic credit-application features. Logistic regression is a deliberate choice for a compliance dashboard, not just a simplification -- it's the closed form that makes exact, closed-form attribution possible (see explain/shap_exact.py) rather than requiring a sampling-based approximation. In production this slot is an arbitrary model (XGBoost, a neural net); the explanation layer in this repo is built to swap over to KernelSHAP/LIME without assuming linearity -- see the production upgrade path in the README. """ from __future__ import annotations import os from dataclasses import dataclass import numpy as np import pandas as pd from sklearn.linear_model import LogisticRegression FEATURES = [ "annual_income_k", "debt_to_income_pct", "credit_history_years", "num_late_payments_2y", "employment_years", "loan_amount_k", "num_open_accounts", ] FEATURE_LABELS = { "annual_income_k": "Annual income ($k)", "debt_to_income_pct": "Debt-to-income (%)", "credit_history_years": "Credit history (years)", "num_late_payments_2y": "Late payments (last 2y)", "employment_years": "Employment length (years)", "loan_amount_k": "Loan amount requested ($k)", "num_open_accounts": "Open credit accounts", } @dataclass class TrainedModel: model: LogisticRegression feature_means: pd.Series train_accuracy: float coefficients: dict def train(csv_path: str) -> TrainedModel: df = pd.read_csv(csv_path) X = df[FEATURES] y = df["approved"] model = LogisticRegression(max_iter=1000) model.fit(X, y) acc = float(model.score(X, y)) coefs = dict(zip(FEATURES, model.coef_[0])) return TrainedModel( model=model, feature_means=X.mean(), train_accuracy=acc, coefficients=coefs, ) def predict_proba(trained: TrainedModel, applicant: dict) -> float: x = pd.DataFrame([applicant])[FEATURES] return float(trained.model.predict_proba(x)[0][1])