{ "best_model": "XGBoost", "results": { "LogisticRegression": { "cv_auc": 0.9217, "cv_gini": 0.8434, "cv_brier": 0.1127, "holdout_auc": 0.9228, "holdout_gini": 0.8456, "holdout_brier": 0.1114 }, "XGBoost": { "cv_auc": 0.9226, "cv_gini": 0.8452, "cv_brier": 0.1113, "holdout_auc": 0.9241, "holdout_gini": 0.8483, "holdout_brier": 0.1098 }, "XGBoost_cal": { "cv_auc": 0.9225, "cv_gini": 0.8449, "cv_brier": 0.0897, "holdout_auc": 0.9243, "holdout_gini": 0.8486, "holdout_brier": 0.0883 }, "LightGBM": { "cv_auc": 0.9225, "cv_gini": 0.8449, "cv_brier": 0.1111, "holdout_auc": 0.9239, "holdout_gini": 0.8477, "holdout_brier": 0.1097 }, "LightGBM_cal": { "cv_auc": 0.9225, "cv_gini": 0.8451, "cv_brier": 0.0896, "holdout_auc": 0.9242, "holdout_gini": 0.8484, "holdout_brier": 0.0883 } }, "best_xgb_params": { "n_estimators": 563, "max_depth": 3, "learning_rate": 0.04448759145940924, "subsample": 0.5705311592018347, "colsample_bytree": 0.761636704321766, "min_child_weight": 6, "gamma": 0.8972162546507014, "reg_alpha": 2.9651828345346862, "reg_lambda": 4.2804546466141 }, "best_lgbm_params": { "n_estimators": 628, "num_leaves": 54, "max_depth": 3, "learning_rate": 0.04550221443019292, "subsample": 0.8675755613520427, "colsample_bytree": 0.5811729741100575, "min_child_samples": 32, "reg_alpha": 8.55907729876928, "reg_lambda": 3.292460209578426 }, "top_features": [ { "feature": "affordability_surplus", "importance": 0.742099940776825 }, { "feature": "combined_risk", "importance": 0.5698344707489014 }, { "feature": "credit_score", "importance": 0.3508100211620331 }, { "feature": "expense_understatement_flag", "importance": 0.324170857667923 }, { "feature": "worst_status_12m", "importance": 0.21787478029727936 }, { "feature": "affordability_margin", "importance": 0.20726099610328674 }, { "feature": "worst_status_3m", "importance": 0.18635587394237518 }, { "feature": "debit_order_returns_3m", "importance": 0.1527206152677536 }, { "feature": "affordability_surplus_ratio", "importance": 0.1525910347700119 }, { "feature": "age", "importance": 0.11965403705835342 } ], "scale_pos_weight": 3.26, "n_train_samples": 133108, "n_holdout_samples": 33278, "train_default_rate": 0.2346, "holdout_default_rate": 0.2346, "excluded_proxy_score_features": [ "origination_score", "client_management_score", "early_stage_cure_score", "late_stage_recovery_score", "score_band" ], "excluded_policy_rule_features": [ "nca_affordability_pass" ], "policy_rule": { "name": "nca_affordability_pass", "description": "Applicants failing affordability are declined outside the model." }, "feature_rationale": { "gross_income": "Primary repayment capacity indicator.", "net_income": "Disposable income after statutory deductions.", "discretionary_income": "Cash remaining after living expenses and debt obligations.", "debt_service_ratio": "Debt obligations relative to net income; core affordability measure.", "living_to_income": "Share of income absorbed by living expenses.", "discretionary_ratio": "Free-cash-flow ratio after living expenses.", "gross_to_net_ratio": "Relationship between gross and take-home pay.", "combined_risk": "Simple interaction between credit score risk and debt burden.", "credit_score": "Core bureau-style payment-risk signal.", "score_norm": "Normalised credit score for model stability.", "score_risk": "Inverse credit score representation.", "living_expenses": "Declared household expense burden.", "food_ratio": "Food spend relative to income.", "housing_ratio": "Housing spend relative to income.", "transport_ratio": "Transport spend relative to income.", "food_expense": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "transport_expense": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "accommodation_expense": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "utilities_expense": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "medical_expense": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "credit_bureau_monthly_debt": "Estimated third-party debt repayment obligation.", "bureau_open_accounts": "Credit exposure breadth.", "bureau_utilisation": "Credit utilisation stress indicator.", "minimum_living_expense": "Normative affordability floor.", "affordability_expense_basis": "Verified expense basis used for affordability.", "affordability_surplus": "Residual affordability after verified expenses and debt.", "affordability_margin": "Residual affordability as a share of income.", "expense_understatement_flag": "Flags declared expenses that appear understated.", "bureau_debt_to_income": "Bureau debt burden ratio.", "affordability_surplus_ratio": "Residual affordability scaled by income.", "affordability_basis_ratio": "Verified expense basis scaled by income.", "expense_gap_ratio": "Gap between verified and declared expenses.", "norm_to_declared_ratio": "Norm-based living expense pressure.", "predicted_monthly_income": "Alternative income estimate for consistency checking.", "household_gross_income": "Broader household affordability signal.", "cpa_commitments": "Estimated committed deductions / payment obligations.", "nlr_commitments": "Non-loan recurring commitments proxy.", "contactability_index": "Collections and operational contactability proxy.", "likely_payment_day": "Likely point in the month when repayment cash flow arrives.", "payment_gap_days": "Expected delay between due date and payment timing.", "income_prediction_gap": "Gap between declared and estimated income.", "household_to_income_ratio": "Household support buffer relative to applicant income.", "cpa_to_income_ratio": "Committed deductions pressure on income.", "nlr_to_income_ratio": "Recurring commitments pressure on income.", "contactability_risk_gap": "Composite operational risk based on contactability and utilisation.", "monthly_instalment": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "loan_amount_requested": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "loan_term_months": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "worst_status_3m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "worst_status_12m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "worst_status_24m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "times_30_dpd_12m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "times_60_dpd_12m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "times_90_dpd_12m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "months_since_worst": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "consecutive_on_time": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "paid_up_accounts": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "written_off_accounts": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "income_variance_pct": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "credit_history_months": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "no_credit_history_flag": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "salary_consistency_3m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "debit_order_returns_3m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "debit_order_returns_12m": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "cash_withdrawals_pct": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "gambling_transactions_flag": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "garnishee_order_flag": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "legal_action_flag": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "fraud_indicator_score": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "instalment_to_income": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "debt_to_income_multiple": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "assets_to_income_multiple": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "avg_balance_to_income": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "min_balance_to_income": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "credit_history_years": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "age": "Lifecycle and employment stability proxy.", "income_band": "Segment view of affordability.", "salary_frequency": "Repayment timing alignment proxy.", "employment_type": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "education_level": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "dependants": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "residence_type": "Feature retained because it contributes to credit risk segmentation and can be explained operationally.", "loan_product_type": "Feature retained because it contributes to credit risk segmentation and can be explained operationally." }, "adverse_action_reasons": [ { "feature": "norm_to_declared_ratio", "coefficient": 0.6329, "reason": "Elevated risk contribution from norm to declared ratio." }, { "feature": "expense_gap_ratio", "coefficient": 0.488, "reason": "Elevated risk contribution from expense gap ratio." }, { "feature": "affordability_basis_ratio", "coefficient": 0.4851, "reason": "Elevated risk contribution from affordability basis ratio." }, { "feature": "employment_type_unemployed", "coefficient": 0.4754, "reason": "Elevated risk contribution from employment type unemployed." }, { "feature": "expense_understatement_flag", "coefficient": 0.4322, "reason": "Declared expenses appear understated versus verified expense basis." }, { "feature": "instalment_to_income", "coefficient": 0.4282, "reason": "Elevated risk contribution from instalment to income." }, { "feature": "debt_service_ratio", "coefficient": 0.4001, "reason": "High debt obligations relative to income." }, { "feature": "combined_risk", "coefficient": 0.3837, "reason": "Elevated risk contribution from combined risk." } ], "fairness_summary": { "gender": [ { "group": "Female", "sample_size": 16547, "observed_default_rate": 0.2337, "mean_predicted_pd": 0.35120001435279846, "approval_rate": 0.3619, "auc": 0.9242 }, { "group": "Male", "sample_size": 16731, "observed_default_rate": 0.2356, "mean_predicted_pd": 0.35010001063346863, "approval_rate": 0.3655, "auc": 0.9241 } ], "province": [ { "group": "Eastern Cape", "sample_size": 3522, "observed_default_rate": 0.2785, "mean_predicted_pd": 0.3783000111579895, "approval_rate": 0.3339, "auc": 0.9252 }, { "group": "Free State", "sample_size": 2116, "observed_default_rate": 0.2585, "mean_predicted_pd": 0.3671000003814697, "approval_rate": 0.3327, "auc": 0.9161 }, { "group": "Gauteng", "sample_size": 8758, "observed_default_rate": 0.1955, "mean_predicted_pd": 0.3158999979496002, "approval_rate": 0.4064, "auc": 0.927 }, { "group": "KwaZulu-Natal", "sample_size": 5303, "observed_default_rate": 0.2285, "mean_predicted_pd": 0.3465999960899353, "approval_rate": 0.3696, "auc": 0.9221 }, { "group": "Limpopo", "sample_size": 2918, "observed_default_rate": 0.2834, "mean_predicted_pd": 0.4041000008583069, "approval_rate": 0.3036, "auc": 0.9278 }, { "group": "Mpumalanga", "sample_size": 2456, "observed_default_rate": 0.2492, "mean_predicted_pd": 0.3691999912261963, "approval_rate": 0.3359, "auc": 0.9208 }, { "group": "North West", "sample_size": 2095, "observed_default_rate": 0.2625, "mean_predicted_pd": 0.3747999966144562, "approval_rate": 0.3403, "auc": 0.9184 }, { "group": "Northern Cape", "sample_size": 1749, "observed_default_rate": 0.2813, "mean_predicted_pd": 0.3968000113964081, "approval_rate": 0.3145, "auc": 0.9188 }, { "group": "Western Cape", "sample_size": 4361, "observed_default_rate": 0.2006, "mean_predicted_pd": 0.3190000057220459, "approval_rate": 0.3972, "auc": 0.9228 } ], "marital_status": [ { "group": "Divorced", "sample_size": 8471, "observed_default_rate": 0.2375, "mean_predicted_pd": 0.349700003862381, "approval_rate": 0.3726, "auc": 0.9259 }, { "group": "Married", "sample_size": 8084, "observed_default_rate": 0.2381, "mean_predicted_pd": 0.3571000099182129, "approval_rate": 0.358, "auc": 0.9251 }, { "group": "Single", "sample_size": 8458, "observed_default_rate": 0.2319, "mean_predicted_pd": 0.3481000065803528, "approval_rate": 0.3574, "auc": 0.922 }, { "group": "Widowed", "sample_size": 8265, "observed_default_rate": 0.2311, "mean_predicted_pd": 0.3481000065803528, "approval_rate": 0.3668, "auc": 0.9235 } ], "age_band": [ { "group": "18-25", "sample_size": 4186, "observed_default_rate": 0.489, "mean_predicted_pd": 0.6173999905586243, "approval_rate": 0.1285, "auc": 0.9294 }, { "group": "26-35", "sample_size": 10747, "observed_default_rate": 0.2934, "mean_predicted_pd": 0.41530001163482666, "approval_rate": 0.2871, "auc": 0.929 }, { "group": "36-45", "sample_size": 11946, "observed_default_rate": 0.1549, "mean_predicted_pd": 0.27079999446868896, "approval_rate": 0.434, "auc": 0.895 }, { "group": "46-55", "sample_size": 5376, "observed_default_rate": 0.1112, "mean_predicted_pd": 0.21119999885559082, "approval_rate": 0.5227, "auc": 0.9013 }, { "group": "56-69", "sample_size": 1023, "observed_default_rate": 0.1554, "mean_predicted_pd": 0.24629999697208405, "approval_rate": 0.477, "auc": 0.8965 } ] }, "logistic_top_coefficients": [ { "feature": "num__norm_to_declared_ratio", "coefficient": 0.632876030698465, "abs_coefficient": 0.632876030698465 }, { "feature": "num__affordability_surplus_ratio", "coefficient": -0.566326020731039, "abs_coefficient": 0.566326020731039 }, { "feature": "num__affordability_margin", "coefficient": -0.5633530644186399, "abs_coefficient": 0.5633530644186399 }, { "feature": "num__expense_gap_ratio", "coefficient": 0.4880477657244633, "abs_coefficient": 0.4880477657244633 }, { "feature": "num__affordability_basis_ratio", "coefficient": 0.4850638030279616, "abs_coefficient": 0.4850638030279616 }, { "feature": "num__discretionary_ratio", "coefficient": -0.47951119867144354, "abs_coefficient": 0.47951119867144354 }, { "feature": "cat__employment_type_unemployed", "coefficient": 0.4753633249003756, "abs_coefficient": 0.4753633249003756 }, { "feature": "num__expense_understatement_flag", "coefficient": 0.43216524370028375, "abs_coefficient": 0.43216524370028375 }, { "feature": "num__instalment_to_income", "coefficient": 0.4281508092747665, "abs_coefficient": 0.4281508092747665 }, { "feature": "num__debt_service_ratio", "coefficient": 0.4000660671070147, "abs_coefficient": 0.4000660671070147 }, { "feature": "num__combined_risk", "coefficient": 0.38374024083432967, "abs_coefficient": 0.38374024083432967 }, { "feature": "num__minimum_living_expense", "coefficient": -0.2978228162072123, "abs_coefficient": 0.2978228162072123 }, { "feature": "num__affordability_surplus", "coefficient": 0.2972818784366496, "abs_coefficient": 0.2972818784366496 }, { "feature": "num__nlr_to_income_ratio", "coefficient": -0.27900972083655295, "abs_coefficient": 0.27900972083655295 }, { "feature": "num__written_off_accounts", "coefficient": 0.27178552357998814, "abs_coefficient": 0.27178552357998814 }, { "feature": "num__debit_order_returns_3m", "coefficient": 0.2567028708006428, "abs_coefficient": 0.2567028708006428 }, { "feature": "num__worst_status_12m", "coefficient": 0.25415366744494733, "abs_coefficient": 0.25415366744494733 }, { "feature": "num__monthly_instalment", "coefficient": -0.2516098365573718, "abs_coefficient": 0.2516098365573718 }, { "feature": "num__age", "coefficient": -0.24622515365377046, "abs_coefficient": 0.24622515365377046 }, { "feature": "cat__employment_type_student", "coefficient": -0.2195824956393162, "abs_coefficient": 0.2195824956393162 } ], "runtime_seconds": 5245.32, "runtime_human": "87m 25s" }