FinEase gives small personal loans through its app. Some borrowers stop paying (they default), and every default is money the company loses.
The credit team has 300 past applicants and knows who repaid and who defaulted. They want a model that looks at a new application and says how likely this person is to default, so risky applications go to a human for a second look.
Goal: Predict defaulted (Yes / No) for a new applicant, with a probability. The answer is a category, so this is a classification problem, and Logistic Regression is the first model to try.
300 past applicants, one row per loan.
| applicant_id | age | monthly_income_k | loan_amount_k | credit_score | years_employed | existing_loans | defaulted |
|---|---|---|---|---|---|---|---|
| 5001 | 44 | 88 | 510 | 781 | 18 | 2 | No |
| 5002 | 46 | 50 | 120 | 734 | 15 | 1 | No |
| 5003 | 50 | 97 | 770 | 820 | 21 | 0 | No |
| 5004 | 45 | 42 | 330 | 793 | 11 | 2 | No |
| 5005 | 34 | 76 | 430 | 694 | 4 | 2 | No |
| 5006 | 40 | 53 | 450 | 782 | 10 | 0 | No |
First 6 of 300 rows · realistic practice data
Press Run on each step in order, or run them all at once. You can change any code and run it again.
Starting Python…
First look at the data, and check how many applicants defaulted. If defaults are rare, a model can look accurate just by saying "No" to everyone, so this number matters.
A ₹5 lakh loan is small for someone earning ₹2 lakh a month and huge for someone earning ₹20,000. So we make one new column: loan_to_income, the loan divided by a year of income. Making useful columns like this is called feature engineering.
Then we compare: do defaulters have a lower credit score and a heavier loan?
Each dot is one applicant. Look where the orange crosses (defaults) sit: low credit score, heavy loan. A straight line can roughly separate the two groups, and that line is what Logistic Regression finds.
We keep 25% of applicants hidden for the test. stratify=y keeps the same share of defaults in both parts.
The inputs are on very different scales (credit score in hundreds, loan_to_income below 2). StandardScaler puts them all on one scale so the model treats them fairly. It learns the scale from the training part only, so the test stays truly unseen.
Logistic Regression does not just say Yes or No. It gives a probability between 0 and 1, using the S-shaped sigmoid curve. predict_proba returns two columns: the chance of "No" and the chance of "Yes". We keep the second one.
By default the model says "default" when the probability is above 0.5. The confusion matrix shows exactly where it is right and wrong:
For a lender, a missed defaulter (lost money) usually hurts more than an extra manual check.
0.5 is only a default. If the credit team wants to catch more defaulters, they can send everyone above, say, 0.3 for a manual check. Recall goes up and precision goes down. Picking the threshold is a business decision, not a maths one.
Each coefficient says which way an input pushes the chance of default. Because the inputs were scaled, the sizes can be compared: a bigger number (either sign) means a stronger effect. Positive pushes towards default, negative pushes towards repaying.
A 29-year-old with a credit score of 640, earning ₹35,000 a month, asks for ₹3 lakh and already pays one loan. Change the numbers and run again. New data must go through the same scaler before the model sees it.
20 questions on new data. You write the code; hints point the way without giving it.