Agentic AI DevOps: ML Training – Classification Model (Loan Approval)

Recap of the previous session

  • With many features, there is one weight per feature and a single bias.
  • Plot features against the target to see which matter, and one-hot encode categorical data so the model only sees numbers.
  • Never test on the training data. Split it with train_test_split, randomly, with a random_state.
  • The model is judged on the test set with a score such as R². A score of about 0.75 was not good enough, so you experiment.

In this session

  • The classification use case: loan approval
  • Analysing the dataset: info, describe and unique counts
  • Cleaning and feature engineering: spaces, useless columns, duplicates, missing values, combining columns
  • Encoding two-category columns, and scaling big numbers with log
  • Splitting into X and y, training a logistic regression model, and measuring accuracy

In one sentence: most of the work in a real ML project is preparing the data. Once it is clean and numeric, training is the same few lines as before.

1. The use case: loan approval


Logistic regression: a linear equation plus the sigmoid

Think of how a loan used to work: you fill in a form, a manager reviews it, and you wait a few days. Now an ML model reviews the application and answers immediately. For that, the model is trained on past applications.

The dataset has one row per previous applicant: number of dependents, education, self-employed (yes or no), annual income, loan amount, loan term, credit score, four asset values (residential, commercial, luxury, bank), and the loan status (approved or rejected).

  • It is structured data, and supervised learning, because the loan status (the target) is in the data.
  • Because the answer is a category, this is a classification problem.

2. Analyse the data first

import pandas as pd

data = pd.read_csv("../data/loan_data.csv")
data.shape        # (4270, 13)
data.info()       # types
data.head()
data.describe()   # statistics
  • About 4,270 past applicants and 13 columns.
  • info() shows that education, self-employed and loan status are strings: categorical data that must be encoded.
  • describe() gives the count, minimum, maximum, mean and quartiles for each numeric column. For the credit score, the minimum is 300, the maximum is 900 and the mean is about 600. This tells you whether the data is balanced. For example, you would not want nearly all credit scores to be 300.

You do not need to plot every feature again. You did that for regression, and the data scientists normally handle it.

3. Cleaning and feature engineering

The data you receive is never ready. These are the steps used here. Not every dataset needs all of them: analyse first, then decide.

a. Remove leading spaces from the column names

The column names start with a space, so data["loan_status"] fails with a key error.

data.columns = [i.strip() for i in data.columns]

b. Drop a feature that cannot help

data.nunique() shows the number of unique values per column. The loan ID has 4,269 unique values for about 4,270 records: every applicant has a different one, so there is no pattern to learn. Credit score has about 600 unique values and repeats across applicants, so it can carry a pattern. Remove features that do not influence the target. They only add complexity.

data.drop(columns=["loan_id"], inplace=True)

inplace=True updates the original DataFrame. Without it, the original is not changed.

c. Remove duplicate records

data.duplicated().sum()
data.drop_duplicates(keep="first", inplace=True)

Duplicates give some applicants extra weight and dominate the training, like practising the same question ten times.

d. Remove spaces from the categorical values

Text values often have leading spaces too (” Graduate”). Numbers do not.

data["education"] = data["education"].str.strip()
data["self_employed"] = data["self_employed"].str.strip()
data["loan_status"] = data["loan_status"].str.strip()

e. Handle missing values

data.isnull().sum()      # credit_score has 4 missing values

Training needs a value everywhere. You can delete the affected rows, or fill them. You cannot get the real credit scores, so fill with the average (about 600):

data["credit_score"] = data["credit_score"].fillna(data["credit_score"].mean())

With 4 missing values out of about 4,000 the effect is small. If many were missing, it would matter. Train both ways and compare the accuracy: that is an experiment.

f. Combine columns

The four asset columns describe the same thing. The bank only needs the total, so combine them and drop the four originals. Fewer features means simpler training.

data["total_assets"] = (data["residential_assets_value"] + data["commercial_assets_value"]
                        + data["luxury_assets_value"] + data["bank_asset_value"])
data.drop(columns=["residential_assets_value", "commercial_assets_value",
                   "luxury_assets_value", "bank_asset_value"], inplace=True)

The dataset is now down to 9 columns.

g. Encode the categorical columns

In session 6, one-hot encoding suited job title because it had five categories. Here each column has only two categories, so a simple 0/1 mapping is enough (this is called label encoding).

data["education"] = data["education"].map({"Graduate": 1, "Not Graduate": 0})
data["self_employed"] = data["self_employed"].map({"No": 1, "Yes": 0})
data["loan_status"] = data["loan_status"].map({"Approved": 1, "Rejected": 0})

The meaning is not lost, only the representation changes. Scikit-learn also has a LabelEncoder, but it chooses which category becomes 0 or 1 for you. Writing the mapping yourself lets you decide that Approved = 1.

Remember these mappings. When the model is used later, the same encoding must be applied to new data.

h. Scale down large numbers

Annual income, loan amount and total assets are in the millions, while other features are tiny. The model struggles to find a pattern with such different sizes. The model does not care what the number means. It only looks for patterns, so you can represent the numbers on a smaller scale without losing the pattern. Use NumPy’s log:

import numpy as np

data["income_annum"] = np.log(data["income_annum"])
data["loan_amount"] = np.log(data["loan_amount"])
data["total_assets"] = np.log(data["total_assets"])

Analogy: 1/2 + 1/2 and 0.5 + 0.5 are the same sum, but the second is easier to compute. It is the same value in an easier form.

4. Features and target

X = data.drop(columns=["loan_status"])   # everything except the answer
y = data["loan_status"]                  # approved (1) or rejected (0)

x and y are only variable names. They are the standard notation, so anyone reading your code understands them. At inference time you send only the input features (like X) and the model returns the loan status.

5. Training and measuring accuracy

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

An 80/20 split: 80% of the records to train and 20% to test.

For classification, scikit-learn offers several algorithms. Here we use logistic regression. (Session 5 used linear regression, because that was a regression problem.) The steps are the same: import, create the object, fit, predict.

from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
model.fit(x_train, y_train)                # training
predictions = model.predict(x_test)        # 1 = approved, 0 = rejected

To judge the model, compare the predictions with the truth (y_test) using accuracy_score:

from sklearn.metrics import accuracy_score

accuracy_score(y_test, predictions)        # about 0.91

An accuracy of about 91% means that out of 100 applicants, about 91 get the correct decision and about 9 do not. If this is not good enough, go back to the data, features or algorithm. How to improve it is the next session.

6. A learner’s question: how does it work for a new applicant?

A new applicant has no loan status yet. Think of a loan manager: they study past applications to learn when loans were approved or rejected. When a new applicant arrives, they decide using what they learned. The model does the same. It trains on previous applicants (with the answers) and then predicts the loan status for a new applicant from the input features alone.

Summary

Key takeaways

  • Loan approval is a binary classification problem, using supervised data.
  • Analyse the data first: shape, info, describe, nunique.
  • Clean it: strip spaces, drop useless columns, remove duplicates, fill missing values, combine similar columns.
  • Encode categories as numbers: a 0/1 mapping for two categories, one-hot for more.
  • Scale down big numbers with log.
  • Split into X and y, then train_test_split, LogisticRegression, fit, predict and accuracy_score.
  • About 91% accuracy on the first attempt.

Quick revision

Term Meaning
Binary classification Two possible answers (approved or rejected)
nunique() Number of unique values in each column
Duplicate The same record repeated, which gives it extra weight
Missing value An empty cell. Delete the row or fill it (for example with the mean)
Label encoding Mapping two categories to 0 and 1
np.log Compresses large numbers into a smaller range
Accuracy Share of predictions that match the truth

Remember: clean the data, make it numeric, then train.

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like