BankBot-AI / backend /app /ai /loan_predictor.py
mohsin-devs's picture
Deploy to HF
a282d4b
Raw
History Blame Contribute Delete
10.9 kB
"""
AI Loan Eligibility Predictor for BankBot
Predicts loan approval chance and EMI affordability using ML
"""
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
import pickle
import os
from datetime import datetime
import json
LOAN_MODEL_FILE = "loan_prediction_model.pkl"
class LoanEligibilityPredictor:
"""ML-based loan eligibility prediction"""
def __init__(self):
self.classifier = None
self.scaler = StandardScaler()
self.feature_names = [
'salary', 'credit_score', 'existing_loans',
'employment_years', 'age', 'loan_amount'
]
self.load_model()
def load_model(self):
"""Load saved model or create new one"""
if os.path.exists(LOAN_MODEL_FILE):
try:
with open(LOAN_MODEL_FILE, "rb") as f:
model_data = pickle.load(f)
self.classifier = model_data.get("classifier")
self.scaler = model_data.get("scaler", StandardScaler())
except Exception as e:
print(f"Error loading loan model: {e}")
self._initialize_model()
else:
self._initialize_model()
def _initialize_model(self):
"""Initialize Random Forest for loan prediction"""
# Create synthetic training data
X_train = np.array([
[100000, 750, 0, 5, 35, 500000], # Approved
[150000, 800, 1, 10, 42, 1000000], # Approved
[200000, 780, 2, 8, 45, 1500000], # Approved
[50000, 600, 3, 2, 28, 300000], # Rejected
[80000, 650, 2, 3, 32, 400000], # Rejected
[120000, 700, 1, 6, 38, 600000], # Approved
[45000, 580, 4, 1, 25, 250000], # Rejected
[180000, 770, 0, 12, 50, 900000], # Approved
[70000, 620, 3, 2, 30, 350000], # Rejected
[160000, 790, 1, 9, 44, 800000], # Approved
])
y_train = np.array([1, 1, 1, 0, 0, 1, 0, 1, 0, 1]) # 1=Approved, 0=Rejected
# Normalize features
X_train_scaled = self.scaler.fit_transform(X_train)
# Train classifier
self.classifier = RandomForestClassifier(n_estimators=100, random_state=42)
self.classifier.fit(X_train_scaled, y_train)
self.save_model()
def save_model(self):
"""Save trained model to disk"""
try:
with open(LOAN_MODEL_FILE, "wb") as f:
pickle.dump({
"classifier": self.classifier,
"scaler": self.scaler
}, f)
except Exception as e:
print(f"Error saving loan model: {e}")
def predict_eligibility(self, salary, credit_score, existing_loans,
employment_years, age, loan_amount):
"""
Predict loan eligibility
Returns: Approval probability (0-100), risk level, recommendations
"""
try:
# Prepare features
features = np.array([[
salary, credit_score, existing_loans,
employment_years, age, loan_amount
]])
# Normalize
features_scaled = self.scaler.transform(features)
# Predict probability
approval_prob = self.classifier.predict_proba(features_scaled)[0][1] * 100
# Calculate risk level
if approval_prob >= 80:
risk_level = "LOW RISK ✅"
elif approval_prob >= 60:
risk_level = "MEDIUM RISK ⚠️"
elif approval_prob >= 40:
risk_level = "HIGH RISK ❌"
else:
risk_level = "VERY HIGH RISK ❌"
return approval_prob, risk_level
except Exception as e:
print(f"Error in prediction: {e}")
return 50, "UNKNOWN RISK"
def check_eligibility_rules(self, salary, credit_score, existing_loans,
employment_years, age, loan_amount):
"""
Check basic eligibility rules
Returns: Boolean and list of issues
"""
issues = []
# Age check
if age < 21:
issues.append("Age must be at least 21 years")
if age > 65:
issues.append("Age exceeds maximum limit (65 years)")
# Employment check
if employment_years < 1:
issues.append("Minimum 1 year employment required")
# Credit score check
if credit_score < 600:
issues.append("Credit score too low (minimum 600 required)")
# Salary check
if salary < 25000:
issues.append("Salary too low for loan eligibility")
# Loan amount vs salary ratio
emi_amount = calculate_emi(loan_amount, 12, 10) # Assume 12% rate, 10 years
if (emi_amount / salary) > 0.5: # EMI shouldn't exceed 50% of salary
issues.append(f"EMI of ₹{emi_amount:.2f} exceeds 50% of salary")
# Existing loans check
if existing_loans > 3:
issues.append("Too many existing loans")
is_eligible = len(issues) == 0
return is_eligible, issues
def calculate_loan_score(self, salary, credit_score, existing_loans,
employment_years, age, loan_amount):
"""
Calculate comprehensive loan score (0-100)
Considers multiple factors
"""
score = 0
# Credit score weight (40%)
credit_component = (min(credit_score, 850) / 850) * 40
score += credit_component
# Salary weight (30%)
salary_component = min((salary / 500000) * 30, 30)
score += salary_component
# Employment years weight (15%)
employment_component = min((employment_years / 30) * 15, 15)
score += employment_component
# Existing loans weight (10%) - negative impact
loan_penalty = min(existing_loans * 2, 10)
score -= loan_penalty
# Age factor (5%) - younger is better
age_component = min(((65 - age) / 45) * 5, 5)
score += age_component
# Loan affordability (penalties if high)
emi = calculate_emi(loan_amount, 12, 10)
if (emi / salary) > 0.5:
score -= 15
elif (emi / salary) > 0.4:
score -= 10
return max(0, min(score, 100))
def calculate_emi(principal, rate_per_annum=10, years=10):
"""
Calculate EMI (Equated Monthly Installment)
Formula: EMI = P * r * (1+r)^n / ((1+r)^n - 1)
"""
monthly_rate = rate_per_annum / 100 / 12
months = years * 12
if monthly_rate == 0:
return principal / months
emi = principal * monthly_rate * ((1 + monthly_rate) ** months) / (
((1 + monthly_rate) ** months) - 1
)
return emi
def calculate_loan_eligibility(salary, credit_score, existing_loans,
employment_years, age, loan_amount):
"""Main function to calculate loan eligibility"""
predictor = LoanEligibilityPredictor()
# Check basic eligibility
is_eligible, issues = predictor.check_eligibility_rules(
salary, credit_score, existing_loans, employment_years, age, loan_amount
)
# Get ML prediction
approval_prob, risk_level = predictor.predict_eligibility(
salary, credit_score, existing_loans, employment_years, age, loan_amount
)
# Calculate loan score
loan_score = predictor.calculate_loan_score(
salary, credit_score, existing_loans, employment_years, age, loan_amount
)
# Calculate EMI
emi = calculate_emi(loan_amount, 12, 10)
# Get recommendations
recommendations = get_loan_recommendations(
approval_prob, salary, credit_score, existing_loans, employment_years, emi
)
result = {
"approval_probability": round(approval_prob, 1),
"approval_status": "APPROVED ✅" if approval_prob >= 60 else "REJECTED ❌" if approval_prob < 40 else "UNDER REVIEW ⏳",
"risk_level": risk_level,
"loan_score": round(loan_score, 1),
"is_rule_eligible": is_eligible,
"issues": issues,
"emi": round(emi, 2),
"total_amount": round(loan_amount + (emi * 12 * 10) - loan_amount, 2),
"monthly_emi": round(emi, 2),
"tenure_years": 10,
"rate_per_annum": 12,
"recommendations": recommendations
}
return result
def get_loan_recommendations(approval_prob, salary, credit_score,
existing_loans, employment_years, emi):
"""Generate personalized loan recommendations"""
recommendations = []
if approval_prob >= 80:
recommendations.append("✅ You are likely to get approved for this loan amount")
elif approval_prob < 40:
recommendations.append("❌ Your approval chances are low. Consider these options:")
if credit_score < 700:
recommendations.append(" • Improve your credit score to 700+")
if existing_loans > 2:
recommendations.append(" • Pay off existing loans to improve your profile")
recommendations.append(" • Apply for a smaller loan amount")
recommendations.append(" • Increase your employment tenure")
else:
recommendations.append("⏳ Your application will be under review")
# EMI affordability
emi_ratio = (emi / salary) * 100
if emi_ratio > 50:
recommendations.append(f"⚠️ Your EMI (₹{emi:.2f}) is {emi_ratio:.1f}% of salary. Consider reducing loan amount.")
elif emi_ratio < 30:
recommendations.append(f"✅ Your EMI to salary ratio ({emi_ratio:.1f}%) is very healthy")
return recommendations
def generate_loan_comparison(loan_amount, rates=[9, 10, 11, 12, 13], tenure_years=[5, 7, 10]):
"""Generate EMI comparison for different rates and tenures"""
comparison_data = []
for rate in rates:
for tenure in tenure_years:
emi = calculate_emi(loan_amount, rate, tenure)
total_amount = (emi * 12 * tenure)
interest = total_amount - loan_amount
comparison_data.append({
"rate": f"{rate}%",
"tenure": f"{tenure} years",
"emi": round(emi, 2),
"total_amount": round(total_amount, 2),
"interest": round(interest, 2)
})
return comparison_data