mzansiscore-api / features_runtime.py
Pieter182's picture
Deploy MzansiScore API Space
2fc9309 verified
Raw
History Blame Contribute Delete
3.9 kB
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