Как разработать модель классификации одобрения потребительского кредита и легко создавать итерации с помощью PyCaret

Контекст:

Dummy Bank заметил, что у него растет объем безнадежных кредитов, и хочет отреагировать на него, построив модель машинного обучения на основе своих исторических данных о «хороших» и «плохих» кредитах. Кроме того, компания просит найти факторы, обуславливающие эти безнадежные кредиты, чтобы бизнес мог предпринять необходимые действия в будущем.

Набор данных:

Доступ к набору данных Dummy Bank можно получить по этой ссылке Kaggle: https://www.kaggle.com/datasets/mrferozi/loan-data-for-dummy-bank?select=loan_final313.csv

Цель:

  1. Разработать модель классификации с приоритетом отзыва, которая представляет собой показатель, ориентированный на сокращение ложноотрицательных результатов (избегая случая прогнозирования хорошего кредита, который оказывается плохим кредитом).
  2. Чтобы понять ключевые факторы плохих кредитов

Импорт библиотек

import pandas as pd
import numpy as np
import openpyxl

from sklearn.preprocessing import LabelEncoder, MinMaxScaler, StandardScaler, OneHotEncoder, OrdinalEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, f1_score, precision_score, recall_score

import sweetviz as sv
import matplotlib.pyplot as plt
import seaborn as sns
import shap

Загрузка данных

path = "C:/Users/Laurence PC/Documents/Data Science/Machine Learning/Classification/Dummy Bank/loan_final313.csv"
df = pd.read_csv(path)

Первоначальная EDA + начальная предварительная обработка данных

Данные должны пройти итерации предварительной обработки и EDA. Таким образом, должно быть реализовано следующее:

  1. Получение списка столбцов и исходной формы фрейма данных
  2. Описание статистической сводки числовых столбцов
  3. Проверка значений NA и NAN
  4. Удаление ПУСТЫХ строк, ИЗБЫТОЧНЫХ и НЕИСПОЛЬЗУЕМЫХ столбцов
  5. Изменение типов данных
  6. Обработка столбцов с порядковыми значениями
df.columns

df.shape

#REMOVING REDUNDANT, BLANK Rows, and UNUSABLE Columns
#unusable columns
df = df.drop(columns=['id','issue_d','final_d'])
#redundant columns
df = df.drop(columns=['home_ownership_cat', 'income_cat', 'income_category', 'term', 'application_type', 'application_type_cat', 'purpose_cat', 'interest_payments', 'interest_payment_cat', 'loan_condition', 'grade', 'grade_cat', 'total_pymnt', 'total_rec_prncp'])
#only bad loans have recoveries, not ideal feature as it highly #correlated to the y variable
df = df.drop(columns=['recoveries'])
#redundant to terms and total principal
df = df.drop(columns=['installment']) 
df.info()

Автовиз

sweet_report = sv.analyze(df)
#Saving results to HTML file
sweet_report.show_html('Dummy_Bank_sweet_report.html')

#COPYING ORIGINAL VALUES BEFORE TRANSFORMATIONS
df_orig = df.copy()
df_orig.reset_index(drop=True, inplace=True)
df_orig

Преобразование данных

После того, как данные завершили этап предварительной обработки и EDA, будет выполнено следующее преобразование данных:

  1. Кодирование категориальных переменных
  2. Масштабирование функций
#Segregating the Categorical Variables
categorical = df.select_dtypes(include=['object'])
categorical_cols = list(categorical.columns)
#Checking unique entries per categorical column
for col in categorical:
    print(col)
    print(df[col].unique(),end="\n")

# Encoding Categorical Variables
df = pd.get_dummies(df, columns=categorical_cols)
#Segregating the Numeric Variables
numerical = df.select_dtypes(include['int32', 'int64', 'float64',                'uint8'])
numerical = numerical.drop(columns=['loan_condition_cat'])
numerical_cols = list(numerical.columns)
#FEATURE SCALING
normalize = MinMaxScaler()
standardize = StandardScaler()
numerical_scaled = normalize.fit_transform(numerical)
#numerical_scaled = standardize.fit_transform(numerical)

#TRANSFORMED DATASET
df_transformed = pd.DataFrame(numerical_scaled, columns=[numerical_cols])
df_transformed['loan_condition_cat'] = df['loan_condition_cat']

Стратифицированная выборка Pycaret для обучения и тестирования

data = df_transformed.copy()
import pycaret
from pycaret.classification import *

clf1 = setup(data, target = 'loan_condition_cat', session_id=123, log_experiment=True, data_split_stratify=True, experiment_name='pycaret dummy_bank', n_jobs=-6)

Настройка модели классификации

Для достижения лучших показателей были реализованы следующие настройки:

  1. Управление дисбалансом классов с помощью: Вес класса = «сбалансированный»
  2. Пороговая оптимизация: вероятностный_порог = 0,1

Построение модели

Пикарет XGB:

xgb = create_model('xgboost', probability_threshold=0.1,   class_weight="balanced")

#Visualization
plot_model(xgb, plot = 'confusion_matrix')

Случайный лес Пикаре:

rf = create_model('rf', probability_threshold=0.1, class_weight="balanced")

#Visualization
plot_model(rf, plot = 'confusion_matrix')

Понимание основных движущих сил с помощью SHAP

interpret_model(xgb)

Проведя все этапы, можно сделать следующие выводы:

1) С помощью модели интерпретирования Пикаре на безнадежные кредиты в основном влияют:

- Vintage of loan (recently approved loans tend to be good loans but as these loans age, bad loans starts to show)
- Higher interest rate
- Low Income
- Shorter term period
- Higher loan amount

2) Базовая модель (XGB) работает с полнотой 63%. Это было достигнуто за счет корректировки веса классов и настройки порога классификации до 10%.

3) В соответствии с этими выводами рекомендуется следующее:

- Add new features relevant to each of the loan (historical transaction of customer)
- Cluster customers based on the features available and use it as a new feature
- Build and/or combine other classification models to improve Recall
- Further optimize the classification threshold to improve Recall