Введение

Моделирование кредитного риска является важнейшим аспектом индустрии BFSI, позволяющим кредиторам оценивать вероятность дефолта заемщиков по кредитам. Мы все знаем, что происходит с прибыльностью и даже с выживанием финансовых учреждений, когда кредиты становятся мошенническими!

В этом блоге мы рассмотрим, как построить модель кредитного риска с помощью Python. Мы обсудим набор данных, попытаемся решить проблему несбалансированных данных, предварительно обработаем данные, обучим модель логистической регрессии и оценим ее производительность. Давайте погрузимся!

Обзор набора данных

Исходные данные, используемые в этом упражнении, взяты из общедоступных данных с LendingClub.com, веб-сайта, который связывает заемщиков и инвесторов через Интернет.

Переменные, используемые в данных
Зависимая переменная — 'not.full.paid': бинарная переменная, указывающая, что ссуда не была возвращена полностью, т. е. (заемщик либо не выполнил свои обязательства, либо кредит был «списан», что означало, что заемщик вряд ли когда-либо вернет его).

Независимые переменные
1) Credit.policy: 1, если клиент соответствует критериям кредитного андеррайтинга LendingClub.com, и 0 в противном случае.

2) цель: цель кредита (принимает значения «credit_card», «debt_consolidation», «образовательный», «major_purchase» и т. д.).

3) int.rate: процентная ставка по кредиту в виде доли (ставка 11% будет сохранена как 0,11). Заемщикам, которых LendingClub.com считает более рискованными, назначаются более высокие процентные ставки.

4) взнос: ежемесячный платеж (в долларах США), причитающийся заемщику, если кредит финансируется.

5) log.annual.inc:натуральный логарифм годового дохода заемщика, о котором сообщается самостоятельно.

6) dti:отношение долга к доходу заемщика (сумма долга, деленная на годовой доход).

7) fico: кредитный рейтинг FICO заемщика.

8) days.with.cr.line: количество дней, в течение которых у заемщика была кредитная линия.

9) revol.bal: оборотный баланс заемщика (сумма, не выплаченная в конце платежного цикла по кредитной карте).

10) revol.util: коэффициент использования возобновляемой линии заемщика (сумма использованной кредитной линии относительно общего доступного кредита).

12) inq.last.6mths:количество запросов заемщика от кредиторов за последние 6 месяцев.

13) delinq.2yrs:сколько раз заемщик просрочивал платеж более чем на 30 дней за последние 2 года.

14) pub.rec: количество уничижительных публичных записей заемщика (заявления о банкротстве, налоговые удержания или судебные решения).

Начнем с загрузки необходимых библиотек и данных.

# Import required libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

# Import necessary modules
from sklearn.linear_model import LogisticRegression 
from sklearn.model_selection import train_test_split  
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.metrics import roc_auc_score

# Load data
df = pd.read_csv("loansdata.csv")
print(df.shape)

Набор данных содержит 9578 строк и 14 столбцов. Всегда приятно просто взглянуть на набор данных, не так ли? Мы можем легко сделать это с помощью функции df.head(), которая выводит следующий результат.

Итак, у нас есть первое представление о данных, и, прежде чем перейти к этапу моделирования, давайте посмотрим на сводную статистику переменных, которые у нас есть.

Функция df.describe() будет генерировать описательную статистику числовых столбцов. Вы можете добавить transpose()utility для переключения строк и столбцов, чтобы упростить чтение и интерпретацию, со столбцами, представляющими каждую статистику, и строками, соответствующими каждой числовой функции.

Мы могли бы отправиться в эпическое путешествие по детальному исследовательскому анализу данных, углубляясь в каждую переменную. Однако, чтобы все было быстро и лаконично, давайте нацелимся на звезду шоу: целевую переменную `not.full.paid`.

Глядя на вывод выше, мы замечаем, что эта озорная переменная играет в бинарную игру со значениями 0 и 1. Ах, среднее значение! Он стоит перед нами как секретный код, раскрывающий, что всего 16% записей осмелились бросить вызов условностям и не полностью погасили свои кредиты. Довольно мятежная банда!

Давайте рассмотрим это визуально с помощью приведенного ниже кода, который отображает количество вхождений для каждого уникального значения «not.full.paid» в наборе данных.

# Create a countplot of the target variable
sns.countplot(data=df, x='not.fully.paid')

# Set the plot title and axes labels
plt.title("Countplot of not.fully.paid")
plt.xlabel("not.fully.paid")
plt.ylabel("Count")

# Show the plot
plt.show()

Выход:

Очевидно, у нас несбалансированный набор данных.

Подготовка данных для моделирования

Мы сделали наши первые шаги в области анализа данных, и теперь пришло время подготовить наши данные к мощному этапу моделирования! Но прежде чем мы продолжим, нам нужно пролить свет на тени отсутствующих значений, скрывающиеся в нашем наборе данных.

Приведенный ниже код выполняет задачу и генерирует количество пропущенных значений для каждой переменной.

Таким образом, мы можем ясно видеть переменные с пропущенными значениями. Давайте проведем обработку пропущенных значений с помощью вменения медианы. Конечно, есть и другие способы обработки пропущенных значений, но об этом как-нибудь в другой раз (или в блоге)!

columns_with_missing = ['days.with.cr.line', 'revol.util', 'inq.last.6mths','delinq.2yrs', 'pub.rec', 'log.annual.inc']

# Replace missing values with median in specified columns
for column in columns_with_missing:
    median = df[column].median()
    df[column].fillna(median, inplace=True)

# Check for the changes 
df.isnull().sum()

Выход:

Таким образом, преобразование отсутствующего значения выполнено, и следующее необходимое преобразование — преобразовать категориальную переменную purpose в числовые переменные с помощью метода, называемого одним горячим кодированием.

df = pd.get_dummies(df, columns=['purpose'], drop_first=True, prefix='Pur')
df.head()

Выход:

Масштабирование переменных-предикторов

Теперь у нас есть готовые переменные, и следующим шагом будет масштабирование переменных-предикторов. Масштабирование помогает нам выровнять игровое поле и гарантирует, что все предикторы имеют одинаковый диапазон значений. Это как привести всех к одному росту, чтобы никто не затмевал других!

Приведенный ниже код выполняет эту задачу.

target_column = ['not.fully.paid'] 
predictors = list(set(list(df.columns))-set(target_column))
df[predictors] = df[predictors]/df[predictors].max()
df.describe().transpose()

Вывод ниже показывает, что теперь все независимые переменные масштабируются от 0 до 1.

Создание массивов обучающих и тестовых наборов

В этом фрагменте кода мы готовимся к обучению нашей модели машинного обучения, разделяя наши данные на наборы для обучения и тестирования. Это называется подходом к оценке модели методом удержания-валидации. Существуют и другие методы, такие как варианты перекрестной проверки, но мы будем использовать подход разделения обучения/тестирования.

Короче говоря, мы собираем наши функции из набора данных и сохраняем их в X, присваивая целевую переменную y. Чтобы обеспечить тщательное обучение и честное тестирование, мы разделили данные на наборы для обучения и тестирования с помощью функции train_test_split. Отображая формы обучающих и тестовых наборов, мы можем проверить количество образцов и функций в каждом наборе, гарантируя, что все настроено для грандиозной производительности нашей модели!

X = df[predictors].values
y = df[target_column].values

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=100)
print(X_train.shape); print(X_test.shape)

Выход:

Обучающие и тестовые данные содержат 6704 и 2874 строки соответственно.

Обучение и оценка модели

Теперь, когда данные готовы, мы обучим модель логистической регрессии, используя обучающие данные. Алгоритм логистической регрессии широко используется для моделирования кредитного риска из-за его интерпретируемости и способности решать проблемы бинарной классификации. В реальных сценариях логистическая регрессия часто рассматривается как базовая модель, которая устанавливает цель для улучшения других алгоритмов машинного обучения.

После обучения модели мы оценим ее производительность как на обучающем, так и на тестовом наборах. Мы будем использовать показатели классификации, такие как матрица путаницы, отчет о классификации и оценка AUC, чтобы оценить эффективность модели.

logreg = LogisticRegression()
logreg.fit(X_train, y_train)

predict_train = logreg.predict(X_train)
predict_test = logreg.predict(X_test)

print(confusion_matrix(y_train,predict_train))
print(classification_report(y_train,predict_train))

Выход:

Давайте также посмотрим на производительность модели на тестовом наборе данных.

print(confusion_matrix(y_test,predict_test))
print(classification_report(y_test,predict_test))

Выход:

Приведенный выше вывод раскрывает интригующее откровение о производительности нашей модели. Похоже, он превосходно предсказывает неплательщиков, тех идеальных клиентов, которые добросовестно выплачивают свои кредиты. Однако, когда дело доходит до прогнозирования неплательщиков, наша модель немного отстает от величия.

А теперь придержите свое волнение на мгновение! Пусть вас не вводят в заблуждение кажущиеся впечатляющими показатели точности 84 % и 83 % на тренировочном и тестовом наборах соответственно. Позвольте мне сбросить на вас бомбу правды: точность — не лучший показатель для оценки моделей, работающих с несбалансированными данными, как в нашем текущем сценарии.

Вот в чем фишка: основная задача банка или финансового учреждения заключается в повышении предсказуемости неплатежеспособных клиентов (тех смельчаков, представленных числом 1 в переменной «not.full.paid»). Они хотят отточить свой хрустальный шар, чтобы точно выявлять потенциальных неплательщиков.

Итак, если не точность, то какой должна быть метрика оценки? Напомним, что в таких случаях часто используются оценка F-1 и оценка AUC, и мы рассмотрим их в следующем разделе, где мы попытаемся справиться с дисбалансом в наборе данных.

Обработка дисбаланса с помощью весов классов

Чтобы устранить дисбаланс классов, мы можем назначить веса классов, чтобы обеспечить сбалансированную перспективу для модели. Это можно сделать, передав веса аргументу class_weight в модуле LogisticRegression, как показано в коде ниже.

# dictionary of class weights
weight_dict = {0:1.19, 1:6.25}

# define the model
logreg2 = LogisticRegression(random_state=10, class_weight=weight_dict)

# fit the model
logreg2.fit(X_train,y_train)

Назначая более высокие веса классу меньшинства, мы можем придать ему большее влияние во время обучения. Обратите внимание, что эти веса выбираются произвольно (с небольшим использованием деления), и вы также можете выбрать любую другую комбинацию.

Затем мы обучим и оценим модель логистической регрессии с этими пользовательскими весами классов, чтобы увидеть ее влияние на производительность.

predict_train = logreg2.predict(X_train)
print(confusion_matrix(y_train,predict_train))
print(classification_report(y_train,predict_train))
print(roc_auc_score(y_train,predict_train))

Выход:

Давайте оценим модель на тестовом наборе данных.

predict_test = logreg2.predict(X_test)
print(confusion_matrix(y_test,predict_test))
print(classification_report(y_test,predict_test))
print(roc_auc_score(y_test,predict_test))

Мы можем ясно наблюдать заметное улучшение результатов, упомянутых выше. Показатель recall в тестовом наборе данных резко вырос с 2 % до впечатляющих 59 %, что указывает на существенное улучшение его способности правильно определять положительные случаи. Кроме того, оценка AUC, мера общей производительности модели, показала многообещающий прогресс, увеличившись с 0,5 до 0,61.

Хотя мы еще не достигли совершенства, эти улучшения служат надежной основой для производительности нашей модели. Двигаясь вперед, наша цель будет состоять в том, чтобы превзойти эти результаты, внедряя более сложные алгоритмы и стратегии, стремясь к еще более высоким показателям. Путь к безупречной модели кредитного риска продолжается!

Заключение

В этом сообщении блога мы рассмотрели моделирование кредитного риска с использованием Python. Мы обсудили набор данных, внедрили метод предварительной обработки и решили проблему несбалансированных данных. Мы обучили модель логистической регрессии, оценили ее производительность и исследовали влияние использования пользовательских весов классов.

Следующие шаги

Наше путешествие здесь не заканчивается! Есть захватывающие пути, по которым нужно следовать, и улучшения, которые необходимо внести. Ниже перечислены некоторые следующие шаги и предложения по повышению производительности нашей модели:

1. Выбор лучших весовых комбинаций:
Мы можем точно настроить веса классов, чтобы найти еще более эффективную комбинацию. Экспериментируя с различными весовыми коэффициентами, мы можем найти баланс, в котором должным образом учитываются классы как меньшинства, так и большинства. Это как найти идеальный рецепт успеха!

2. Раскрытие возможностей разработки признаков:
Мы можем вывести нашу модель на новый уровень, применив некоторые хитрости проектирования признаков. Это включает в себя изучение взаимосвязей между переменными, выявление корреляций и удаление любых избыточных или сильно коррелированных функций. Это похоже на расхламление нашего набора данных и раскрытие скрытого внутри потенциала!

3. Использование методов устранения дисбаланса:
Чтобы решить проблемы дисбаланса классов, мы можем использовать мощные методы, такие как SMOTE (метод искусственного меньшинства перед выборкой). SMOTE создает синтетические образцы класса меньшинства, повышая его представленность в наборе данных.

4. Высвобождение зверей: Random Forest, XG Boost и Deep Neural Nets
Теперь пришло время обратиться к тяжеловесам из области машинного обучения. Эти мощные алгоритмы обладают исключительными способностями к прогнозированию и могут обрабатывать сложные отношения в данных. Изучая эти передовые модели, мы можем обнаружить еще большую точность и эффективность прогнозирования.

Помните, друзья-энтузиасты науки, наши поиски идеальной модели кредитного риска продолжаются. По мере того, как мы приступаем к этим следующим шагам, давайте наслаждаться экспериментами и инновациями. Возможности безграничны, а награды велики. Мы идем вперед, стремясь к вершине производительности модели и области исключительной оценки рисков!

Свяжитесь со мной:

Пожалуйста, не стесняйтесь связаться со мной в Linkedin (https://in.linkedin.com/in/vikashsingh29)

#CreditRiskModeling #machinelearning #loandefault #BFSI