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

Глядя на данные

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

Мы видим, что наши целевые классы очень несбалансированы. Фактически, в наборе данных имеется 284315 законных транзакций и только 492 (0,17%) мошеннических транзакций. Матрица корреляции сообщает нам, что корреляция между функциями отсутствует или очень мала, и если мы посмотрим на корреляцию между отдельными функциями и целевым столбцом, мы увидим, что можем избавиться от Time столбца, поскольку он не предоставляет никакой информации.

Снижение размерности

Следующее, что я хотел проверить, - есть ли разделение между мошенническими и законными транзакциями. Учитывая, что наш вектор признаков имеет 29 измерений, мне было бы трудно его визуализировать. Мы можем использовать алгоритм, называемый анализом главных компонентов (PCA), чтобы уменьшить размерность нашего набора данных до двух измерений, чтобы мы могли построить его.

Проблема классового дисбаланса

Давайте теперь вкратце рассмотрим, почему большой дисбаланс между целевыми классами является проблемой. В нашем наборе данных 284807 образцов, 492 из которых являются поддельными. Если бы мы спрогнозировали «не мошенничество» для этих 492 образцов, мы получили бы точность классификации 99,83%, но наша модель была бы бесполезной. Чтобы обойти это, мы будем использовать матрицы неточностей, кривые характеристик оператора приемника (ROC) и кривые точного отзыва в качестве показателей производительности. Наша цель будет заключаться в том, чтобы максимально повысить отзывчивость и некоторую точность торговли, поскольку лучше предсказать «мошенничество» по не мошенническим транзакциям, чем пропустить множество мошеннических.

Разделение данных

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

Обучение модели

Логистическая регрессия

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

from sklearn.linear_model import LogisticRegression
lr_model = LogisticRegression(n_jobs=4)
lr_model.fit(train_X, train_y)

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

Функция взвешенных потерь

SciKit learn предоставляет параметр class_weight, который мы можем установить на balanced и разрешить модели использовать функцию взвешенных потерь. Ниже показаны метрики модели, которые я получил после использования функции взвешенных потерь. Как мы видим, оценка отзыва теперь намного лучше, хотя мы немного потеряли точность.

Недостаточная выборка

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

import numpy as np
def undersample(data, n=1):
    positive_samples = data[data[target] ==    1].copy().apply(np.random.permutation)
    negative_samples = data[data[target] == 0].copy().apply(np.random.permutation).head(positive_samples.shape[0] * n)
    undersampled_data = pd.concat([positive_samples, negative_samples])
    return train_test_split(undersampled_data[feature_columns],  undersampled_data[target], test_size=0.3)

Следующие два рисунка представляют собой метрики модели после обучения на данных с неполной выборкой, при этом 50% мошеннических и 50% законных транзакций в данных обучения.

На первом изображена модель, оцененная на основе неполной выборки тестовых данных с оценкой запоминания 0,99. Это здорово, но есть проблема в том, что данные теперь не отражают то, что мы видели в реальном мире. На следующем рисунке показана модель, оцененная на наших исходных тестовых данных, и мы ясно видим, что, хотя оценка отзыва падает до 0,95 (что мы получили с функцией взвешенных потерь), оценка точности также снижается. Это хорошо представлено показателем F1, равным 0,98 для модели с взвешенной функцией потерь и 0,86 для модели, обученной на данных с недостаточной выборкой.

Машина опорных векторов

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

Случайный лес

Последняя модель, которую я пробовал, - это модель случайного леса с PCA, которая уменьшает размерность до 16 измерений. Часть PCA не является необходимой, но она дает модели меньше функций, которые являются более репрезентативными, и, следовательно, снижает вероятность переобучения (на практике это улучшило отзывчивость на 0,03). Несмотря на то, что отзыв составил всего 0,89, он имеет наименьшее количество ложноотрицательных результатов и лучший результат F1 среди всех моделей, упомянутых в этой статье.

Заключение

Многие наборы данных реального мира имеют несбалансированные целевые классы, аналогичные тому, который я представил вам в этой статье. Осведомленность об этом факте и выбор правильных показателей при оценке производительности модели на тестовых данных помогает нам лучше настраивать модели, а также быть более уверенными в том, что они делают то, что мы думаем. Я получил лучший результат F1, используя модель случайного леса с PCA, которую можно дополнительно оптимизировать для лучшего запоминания, уменьшив порог принятия решения. Лучшая нестандартная модель с точки зрения показателя отзыва кажется логистической регрессией с функцией взвешенных потерь, которая достигла отзыва 0,95 и общей оценки F1 0,92. Я также должен отметить, что функции нашего набора данных - это первые 28 основных компонентов, полученных с помощью PCA исходного набора данных, поэтому модель, которую мы обучили, бесполезна для реальных данных (если вы не знаете, каковы были исходные функции :)).

Полный код можно найти в этом блокноте iPython. Если вы запустите это самостоятельно, вы можете получить разные оценки, поскольку они зависят от того, как данные рандомизируются и разделяются, но они не должны отклоняться более чем на 3%. Я надеюсь, что эта статья окажется для вас полезной, и не стесняйтесь оставлять комментарии ниже.