Spaces:
Runtime error
Runtime error
File size: 8,627 Bytes
90b0598 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
import gradio as gr
import pandas as pd
import numpy as np
import joblib
import os
# Load the saved model pipeline
model_path = 'credit_risk_assessment_model.pkl'
if os.path.exists(model_path):
model = joblib.load(model_path)
print(f"✅ Model loaded successfully from {model_path}")
else:
print(f"⚠️ Model file not found at {model_path}. Upload it to this Space.")
model = None
# ---- HELPER FUNCTIONS ----
def get_age_group(age):
if age < 30: return '20-30'
elif age < 40: return '30-40'
elif age < 50: return '40-50'
elif age < 60: return '50-60'
elif age < 70: return '60-70'
else: return '70+'
def get_credit_amount_group(amount):
if amount < 2000: return 'Low'
elif amount < 5000: return 'Medium'
elif amount < 10000: return 'High'
else: return 'Very High'
def get_duration_group(duration):
if duration <= 12: return 'Short'
elif duration <= 36: return 'Medium'
else: return 'Long'
def get_employment_stability(emp):
return {
'A71': 'Unstable', 'A72': 'Unstable', 'A73': 'Moderate',
'A74': 'Stable', 'A75': 'Very Stable'
}.get(emp, 'Moderate')
def get_savings_status(savings):
return {
'A61': 'None/Low', 'A62': 'Moderate', 'A63': 'Moderate',
'A64': 'High', 'A65': 'None/Low'
}.get(savings, 'None/Low')
def get_credit_history_simple(history):
return {
'A30': 'Poor', 'A31': 'Good', 'A32': 'Good',
'A33': 'Fair', 'A34': 'Poor'
}.get(history, 'Fair')
def calculate_risk_flags(age, credit_amount, duration, checking_account):
return {
'young_high_credit_flag': int(age < 30 and credit_amount > 5000),
'high_exposure_flag': int(credit_amount > 7500 and duration > 24),
'critical_high_amount_flag': int(credit_amount > 10000),
'no_checking_high_credit_flag': int(checking_account == 'A14' and credit_amount > 5000),
'checking_risk': int(checking_account in ['A13', 'A14'])
}
def calculate_additional_risk_flags(credit_history, savings_account):
history_risk = int(credit_history in ['A30', 'A34'])
savings_risk = int(savings_account in ['A61', 'A65'])
combined_account_risk = history_risk + savings_risk
return {
'history_risk': history_risk,
'savings_risk': savings_risk,
'combined_account_risk': combined_account_risk
}
# ---- PREDICTION WRAPPER ----
def predict_credit_risk(checking_account, duration, credit_history, purpose, credit_amount, savings_account, employment_since, installment_rate, personal_status_sex, other_debtors, present_residence, property, age, other_installment_plans, housing, number_credits, job, people_liable, telephone, foreign_worker):
# If model isn't loaded, show error
if model is None:
return """
<div style='padding: 1rem; border-radius: 0.5rem; background-color: #f44336; color: white;'>
<h2>Error: Model not loaded</h2>
<p>The credit risk model has not been loaded. Please check the server logs.</p>
</div>
"""
try:
# Calculate derived features
age_group = get_age_group(age)
credit_amount_group = get_credit_amount_group(credit_amount)
duration_group = get_duration_group(duration)
employment_stability = get_employment_stability(employment_since)
savings_status = get_savings_status(savings_account)
credit_history_simple = get_credit_history_simple(credit_history)
credit_per_month = credit_amount / duration if duration > 0 else 0
age_to_credit_ratio = credit_amount / age if age > 0 else 0
debt_burden = credit_per_month * 100 / 2000
credit_to_duration_ratio = credit_amount / duration if duration > 0 else 0
# Calculate risk flags
risk_flags = calculate_risk_flags(age, credit_amount, duration, checking_account)
additional_flags = calculate_additional_risk_flags(credit_history, savings_account)
# Create input data dictionary with all features
input_data = {
'index': 0, # Add index column to fix the error
'checking_account': checking_account,
'duration': duration,
'credit_history': credit_history,
'purpose': purpose,
'credit_amount': credit_amount,
'savings_account': savings_account,
'employment_since': employment_since,
'installment_rate': installment_rate,
'personal_status_sex': personal_status_sex,
'other_debtors': other_debtors,
'present_residence': present_residence,
'property': property,
'age': age,
'other_installment_plans': other_installment_plans,
'housing': housing,
'number_credits': number_credits,
'job': job,
'people_liable': people_liable,
'telephone': telephone,
'foreign_worker': foreign_worker,
'age_group': age_group,
'credit_amount_group': credit_amount_group,
'duration_group': duration_group,
'credit_per_month': credit_per_month,
'employment_stability': employment_stability,
'savings_status': savings_status,
'credit_history_simple': credit_history_simple,
'age_to_credit_ratio': age_to_credit_ratio,
'debt_burden': debt_burden,
'credit_to_duration_ratio': credit_to_duration_ratio,
'duration_history_interaction': int(duration > 24 and credit_history in ['A30', 'A33', 'A34']),
'amount_checking_interaction': int(credit_amount > 5000 and checking_account in ['A13', 'A14']),
**risk_flags,
**additional_flags
}
# Convert to DataFrame for prediction
df = pd.DataFrame([input_data])
# Make prediction using the pipeline
try:
# For debugging
print(f"Input DataFrame shape: {df.shape}")
print(f"Input DataFrame columns: {df.columns.tolist()}")
y_proba = model.predict_proba(df)[0][1]
# Determine risk level based on probability
if y_proba > 0.7:
risk = "High Risk"
color = "#f44336" # Red
approval = "Loan Rejected"
icon = "❌"
elif y_proba > 0.4:
risk = "Medium Risk"
color = "#ff9800" # Orange
approval = "Further Review Required"
icon = "⚠️"
else:
risk = "Low Risk"
color = "#4caf50" # Green
approval = "Loan Approved"
icon = "✅"
# Format a detailed response
return f"""
<div style='padding: 1.5rem; border-radius: 0.5rem; background-color: {color}; color: white;'>
<h2 style='margin-top: 0;'>{icon} {risk}: {approval}</h2>
<p style='font-size: 1.2rem;'>Risk Score: {y_proba:.2%}</p>
<hr style='border-color: rgba(255,255,255,0.3);'>
<div style='margin-top: 1rem;'>
<p><strong>Key Risk Factors:</strong></p>
<ul>
<li>Credit Amount: £{credit_amount:,.2f} ({credit_amount_group})</li>
<li>Loan Duration: {duration} months ({duration_group})</li>
<li>Monthly Payment: £{credit_per_month:,.2f}</li>
<li>Credit History: {credit_history_simple}</li>
<li>Debt Burden: {debt_burden:.2f}%</li>
</ul>
</div>
</div>
"""
except Exception as inner_e:
print(f"Prediction error: {inner_e}")
print(f"DataFrame columns: {df.columns.tolist()}")
return f"""
<div style='padding: 1rem; border-radius: 0.5rem; background-color: #f44336; color: white;'>
<h2>Error in Prediction</h2>
<p>{str(inner_e)}</p>
<p>Please check the server logs for details.</p>
</div>
"""
except Exception as e:
print(f"Error in processing: {e}")
return f"""
<div style='padding: 1rem; border-radius: 0.5rem; background-color: #f44336; color: white;'>
<h2>Error Processing Request</h2>
<p>{str(e)}</p>
<p>Please check the server logs for details.</p>
</div>
""" |