""" 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