Spaces:
Sleeping
Sleeping
| import numpy as np | |
| import pandas as pd | |
| def build_features(df): | |
| df = df.copy() | |
| df['living_to_income'] = df['living_expenses'] / df['net_income'].replace(0, np.nan) | |
| df['discretionary_ratio'] = df['discretionary_income'] / df['net_income'].replace(0, np.nan) | |
| df['gross_to_net_ratio'] = df['net_income'] / df['gross_income'].replace(0, np.nan) | |
| df['score_norm'] = df['credit_score'] / 850 | |
| df['score_risk'] = 1 - df['score_norm'] | |
| df['combined_risk'] = df['score_risk'] + df['debt_service_ratio'] | |
| df['food_ratio'] = df['food_expense'] / df['net_income'].replace(0, np.nan) | |
| df['housing_ratio'] = df['accommodation_expense'] / df['net_income'].replace(0, np.nan) | |
| df['transport_ratio'] = df['transport_expense'] / df['net_income'].replace(0, np.nan) | |
| if 'credit_bureau_monthly_debt' in df.columns: | |
| df['bureau_debt_to_income'] = df['credit_bureau_monthly_debt'] / df['net_income'].replace(0, np.nan) | |
| if 'affordability_surplus' in df.columns: | |
| df['affordability_surplus_ratio'] = df['affordability_surplus'] / df['net_income'].replace(0, np.nan) | |
| if 'affordability_expense_basis' in df.columns: | |
| df['affordability_basis_ratio'] = df['affordability_expense_basis'] / df['net_income'].replace(0, np.nan) | |
| if {'affordability_expense_basis', 'living_expenses'}.issubset(df.columns): | |
| df['expense_gap_ratio'] = ( | |
| (df['affordability_expense_basis'] - df['living_expenses']) / | |
| df['net_income'].replace(0, np.nan) | |
| ) | |
| if {'minimum_living_expense', 'living_expenses'}.issubset(df.columns): | |
| df['norm_to_declared_ratio'] = df['minimum_living_expense'] / df['living_expenses'].replace(0, np.nan) | |
| if 'predicted_monthly_income' in df.columns: | |
| df['income_prediction_gap'] = ( | |
| (df['predicted_monthly_income'] - df['gross_income']) / | |
| df['gross_income'].replace(0, np.nan) | |
| ) | |
| if 'household_gross_income' in df.columns: | |
| df['household_to_income_ratio'] = df['household_gross_income'] / df['gross_income'].replace(0, np.nan) | |
| if {'cpa_commitments', 'net_income'}.issubset(df.columns): | |
| df['cpa_to_income_ratio'] = df['cpa_commitments'] / df['net_income'].replace(0, np.nan) | |
| if {'nlr_commitments', 'net_income'}.issubset(df.columns): | |
| df['nlr_to_income_ratio'] = df['nlr_commitments'] / df['net_income'].replace(0, np.nan) | |
| if {'contactability_index', 'bureau_utilisation'}.issubset(df.columns): | |
| df['contactability_risk_gap'] = (100 - df['contactability_index']) / 100 + df['bureau_utilisation'] | |
| if {'monthly_instalment', 'net_income'}.issubset(df.columns): | |
| df['instalment_to_income'] = df['monthly_instalment'] / df['net_income'].replace(0, np.nan) | |
| if {'total_debt_outstanding_zar', 'gross_income'}.issubset(df.columns): | |
| df['debt_to_income_multiple'] = df['total_debt_outstanding_zar'] / df['gross_income'].replace(0, np.nan) | |
| if {'asset_total_zar', 'gross_income'}.issubset(df.columns): | |
| df['assets_to_income_multiple'] = df['asset_total_zar'] / df['gross_income'].replace(0, np.nan) | |
| if {'avg_bank_balance_30d_zar', 'net_income'}.issubset(df.columns): | |
| df['avg_balance_to_income'] = df['avg_bank_balance_30d_zar'] / df['net_income'].replace(0, np.nan) | |
| if {'min_bank_balance_30d_zar', 'net_income'}.issubset(df.columns): | |
| df['min_balance_to_income'] = df['min_bank_balance_30d_zar'] / df['net_income'].replace(0, np.nan) | |
| if {'credit_history_months'}.issubset(df.columns): | |
| df['credit_history_years'] = df['credit_history_months'] / 12 | |
| df['income_band'] = pd.cut( | |
| df['gross_income'], | |
| bins=[0, 8000, 15000, 25000, 45000, 80000, np.inf], | |
| labels=['very_low', 'low', 'lower_mid', 'middle', 'upper_mid', 'high'], | |
| ) | |
| return df | |