Spaces:
Runtime error
Runtime error
| """ | |
| Generates SYNTHETIC credit-application data with a KNOWN ground-truth | |
| relationship between features and outcome. This is deliberate: because we | |
| know the true generating weights, we can later verify that the model | |
| recovers a sensible approximation of them, and that the explanation layer | |
| (SHAP-style + LIME-style) correctly attributes the decision to the features | |
| that actually drove it -- a property you can't verify against messy real | |
| data. No real applicant, credit bureau, or financial data is used. | |
| """ | |
| import csv | |
| import os | |
| import random | |
| random.seed(7) | |
| N = 600 | |
| FEATURES = [ | |
| "annual_income_k", "debt_to_income_pct", "credit_history_years", | |
| "num_late_payments_2y", "employment_years", "loan_amount_k", "num_open_accounts", | |
| ] | |
| # True (synthetic) generating weights -- unknown to the model at training time, | |
| # used only to label the data and later sanity-check what the model/explainer recovers. | |
| TRUE_WEIGHTS = { | |
| "annual_income_k": 0.028, | |
| "debt_to_income_pct": -0.055, | |
| "credit_history_years": 0.09, | |
| "num_late_payments_2y": -0.65, | |
| "employment_years": 0.05, | |
| "loan_amount_k": -0.012, | |
| "num_open_accounts": -0.04, | |
| } | |
| TRUE_INTERCEPT = -1.0 | |
| def sigmoid(x): | |
| import math | |
| return 1 / (1 + math.exp(-x)) | |
| def make_row(): | |
| income = max(18, random.gauss(65, 28)) | |
| dti = max(2, min(70, random.gauss(28, 12))) | |
| history = max(0, random.gauss(9, 6)) | |
| late = max(0, int(random.gauss(1.1, 1.4))) | |
| employment = max(0, random.gauss(6, 5)) | |
| loan = max(3, random.gauss(18, 12)) | |
| open_accts = max(0, int(random.gauss(5, 2.5))) | |
| features = { | |
| "annual_income_k": round(income, 1), | |
| "debt_to_income_pct": round(dti, 1), | |
| "credit_history_years": round(history, 1), | |
| "num_late_payments_2y": late, | |
| "employment_years": round(employment, 1), | |
| "loan_amount_k": round(loan, 1), | |
| "num_open_accounts": open_accts, | |
| } | |
| logit = TRUE_INTERCEPT + sum(TRUE_WEIGHTS[k] * v for k, v in features.items()) | |
| logit += random.gauss(0, 0.4) # irreducible noise | |
| p_approve = sigmoid(logit) | |
| approved = 1 if random.random() < p_approve else 0 | |
| features["approved"] = approved | |
| return features | |
| def main(): | |
| rows = [make_row() for _ in range(N)] | |
| out_path = os.path.join(os.path.dirname(__file__), "data", "credit_applications.csv") | |
| with open(out_path, "w", newline="") as f: | |
| writer = csv.DictWriter(f, fieldnames=FEATURES + ["approved"]) | |
| writer.writeheader() | |
| writer.writerows(rows) | |
| approve_rate = sum(r["approved"] for r in rows) / len(rows) | |
| print(f"Wrote {len(rows)} synthetic applications to {out_path} (approve rate: {approve_rate:.1%})") | |
| if __name__ == "__main__": | |
| main() | |