|
|
import streamlit as st |
|
|
import joblib |
|
|
import numpy as np |
|
|
|
|
|
st.set_page_config(page_title="Loan Default Predictor", layout="centered") |
|
|
|
|
|
st.title("Loan Default Predictor β Give Me Some Credit") |
|
|
st.write("Enter applicant features below and click **Predict** to get `SeriousDlqin2yrs` prediction.") |
|
|
|
|
|
@st.cache_resource |
|
|
def load_model(path="model.pkl"): |
|
|
return joblib.load(path) |
|
|
|
|
|
try: |
|
|
model = load_model("model.pkl") |
|
|
except Exception as e: |
|
|
st.error(f"Unable to load model.pkl β check file path. Error: {e}") |
|
|
st.stop() |
|
|
|
|
|
st.subheader("Applicant features") |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
with col1: |
|
|
RevolvingUtilizationOfUnsecuredLines = st.number_input( |
|
|
"Revolving Utilization Of Unsecured Lines", value=0.769413, format="%.6f" |
|
|
) |
|
|
age = st.number_input("age", value=32, min_value=18, max_value=120, step=1) |
|
|
NumberOfTime30_59DaysPastDueNotWorse = st.number_input( |
|
|
"Number Of Time 30-59 Days Past Due Not Worse", value=2, step=1 |
|
|
) |
|
|
DebtRatio = st.number_input("DebtRatio", value=0.161342, format="%.6f") |
|
|
MonthlyIncome = st.number_input("MonthlyIncome", value=45000.0, format="%.2f") |
|
|
|
|
|
with col2: |
|
|
NumberOfOpenCreditLinesAndLoans = st.number_input( |
|
|
"Number Of Open Credit Lines And Loans", value=6.0, step=1.0 |
|
|
) |
|
|
NumberOfTimes90DaysLate = st.number_input( |
|
|
"Number Of Times 90 Days Late", value=1.0, step=1.0 |
|
|
) |
|
|
NumberRealEstateLoansOrLines = st.number_input( |
|
|
"Number Real Estate Loans Or Lines", value=6.0, step=1.0 |
|
|
) |
|
|
NumberOfTime60_89DaysPastDueNotWorse = st.number_input( |
|
|
"Number Of Time 60-89 Days Past Due Not Worse", value=0.0, step=1.0 |
|
|
) |
|
|
NumberOfDependents = st.number_input( |
|
|
"Number Of Dependents", value=0.999883, format="%.6f" |
|
|
) |
|
|
|
|
|
col3, col4 = st.columns(2) |
|
|
with col3: |
|
|
TotalPastDue = st.number_input("Total Past Due", value=2.0, step=1.0) |
|
|
DebtRatioPerDependent = st.number_input("DebtRatio Per Dependent", value=25.1344) |
|
|
UtilizationPerLine = st.number_input("Utilization Per Line", value=0.217371) |
|
|
with col4: |
|
|
IncomeDebtRatio = st.number_input("IncomeDebtRatio", value=3003.393701) |
|
|
HasDependents = st.selectbox("HasDependents", options=[0, 1], index=1) |
|
|
HighDebtRatio = st.selectbox("HighDebtRatio", options=[0, 1], index=0) |
|
|
HighUtilization = st.selectbox("HighUtilization", options=[0, 1], index=0) |
|
|
|
|
|
feature_order = [ |
|
|
RevolvingUtilizationOfUnsecuredLines, |
|
|
age, |
|
|
NumberOfTime30_59DaysPastDueNotWorse, |
|
|
DebtRatio, |
|
|
MonthlyIncome, |
|
|
NumberOfOpenCreditLinesAndLoans, |
|
|
NumberOfTimes90DaysLate, |
|
|
NumberRealEstateLoansOrLines, |
|
|
NumberOfTime60_89DaysPastDueNotWorse, |
|
|
NumberOfDependents, |
|
|
TotalPastDue, |
|
|
DebtRatioPerDependent, |
|
|
UtilizationPerLine, |
|
|
IncomeDebtRatio, |
|
|
HasDependents, |
|
|
HighDebtRatio, |
|
|
HighUtilization, |
|
|
] |
|
|
|
|
|
X_input = np.array(feature_order).reshape(1, -1) |
|
|
|
|
|
if st.button("Predict"): |
|
|
try: |
|
|
pred = model.predict(X_input)[0] |
|
|
except Exception as e: |
|
|
st.error(f"Prediction failed. Check feature order/types. Error: {e}") |
|
|
st.stop() |
|
|
|
|
|
label_map = {0: "No Default (Good Credit)", 1: "Default (High Risk)"} |
|
|
meaning = label_map.get(int(pred), str(pred)) |
|
|
|
|
|
proba_str = "" |
|
|
try: |
|
|
proba = model.predict_proba(X_input)[0] |
|
|
if len(proba) == 2: |
|
|
proba_str = f" β P(Default) = {proba[1]:.4f}" |
|
|
else: |
|
|
proba_str = " β probabilities: " + ", ".join(f"{p:.4f}" for p in proba) |
|
|
except Exception: |
|
|
proba_str = "" |
|
|
|
|
|
if int(pred) == 1: |
|
|
st.error(f"Prediction: {pred} β {meaning}{proba_str}") |
|
|
else: |
|
|
st.success(f"Prediction: {pred} β {meaning}{proba_str}") |
|
|
|
|
|
with st.expander("Show raw inputs and model output"): |
|
|
st.write("Input vector (order):", feature_order) |
|
|
st.write("Raw prediction:", int(pred)) |
|
|
if proba_str: |
|
|
st.write("Raw probabilities:", proba if 'proba' in locals() else None) |
|
|
|
|
|
st.caption("Model expects features in a specific order. If predictions seem off, verify the feature order and preprocessing used during training.") |