Знайте, где подводные камни и как их избежать
Проблемы классификации довольно распространены в мире науки о данных. Будь то обнаружение мошенничества, анализ настроений или тестирование болезней, возможность предсказать, в какой группе находится конкретная точка данных, невероятно эффективна.
Обычно основное внимание уделяется обнаружению точек данных в группе меньшинства, и это может создавать некоторые общие проблемы. Обычно в подобных ситуациях собранные вами данные несбалансированы, что означает, что интересующая вас цель имеет значительно меньшие объемы данных, чем другие группы. Этот дисбаланс в ваших данных приведет к тому, что ваша модель будет склоняться к выбору группы большинства. При работе с несбалансированными наборами данных существует три общих метода балансировки данных:
- недостаточная выборка класса большинства
- чрезмерная выборка классов меньшинств
- сочетание недостаточной выборки класса большинства и избыточной выборки класса меньшинства
В этом сообщении блога будет рассмотрен один из видов техники передискретизации, называемый методом SMOTE.
SMOTE (Техника передискретизации синтетических меньшинств) - это тип процедуры передискретизации, которая используется для исправления дисбаланса в группах. Этот метод создает новые экземпляры данных групп меньшинств путем копирования существующих экземпляров меньшинств и внесения в них небольших изменений. Благодаря этому SMOTE отлично подходит для усиления сигналов, которые уже существуют в группах меньшинств, но не создает новых сигналов для этих групп.
Давайте посмотрим на некоторые данные классификации, которые не были сбалансированы с помощью SMOTE. Мы будем использовать набор данных по раку груди из библиотеки sci-kit learn. Давайте импортируем необходимые пакеты, импортируем наши данные и создадим функцию, которая может оценивать наши модели.
import pandas as pd from sklearn import datasets from sklearn.model_selection import cross_val_score from sklearn.metrics import confusion_matrix def evaluate_model(X_train, y_train, model): model.fit(X_train, y_train) preds = model.predict(X_test) scores = cross_val_score(model, X_train, y_train, cv=3, scoring="accuracy") diff = scores.mean() - model.score(X_test, y_test) SD = diff / scores.std() print(f"Training Score:{model.score(X_train, y_train)}") print(f"Cross V Score: {scores.mean()} +/- {scores.std()}") print(f"Testing Score: {model.score(X_test, y_test)}") print(f"Cross & Test Diff: {diff}") print(f"Standard Deviations Away: {SD}") print(confusion_matrix(y_test, preds)) cancer = datasets.load_breast_cancer() X = cancer.data y = cancer.target
Отсюда мы проведем разделение наших данных на обучающий тест и инициализируем нашу базовую модель.
from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0) clf = LogisticRegression(random_state=0, solver='newton-cg', max_iter=1000)
Напоминание: важно установить случайное состояние в функции разделения поезд-тест, чтобы быть уверенным, что любые изменения в производительности вашей модели вызваны изменениями, которые вы сделали, а не случайным начальным числом. Параметр stratify разделяет данные в соответствии с входным параметром, в данном случае y. Это означает, что в вашем тренировочном и тестовом наборах будет одинаковый процент выборок для каждой группы.
Теперь посмотрим, как работает наша базовая модель.
evaluate_model(X_train, y_train, clf)
В целом мы видим, что наша базовая модель неплохо справляется с моделированием данных, но давайте посмотрим, сможем ли мы использовать SMOTE для повышения производительности.
Итак, при работе с синтетическими данными первое правило:
Не добавляйте синтетические данные в данные тестирования!
Мы хотим реализовать нашу модель на реальных данных, поэтому мы хотим увидеть, как наша модель будет работать с реальными данными, а не с синтетическими данными, которые мы создали. Это означает, что мы можем добавлять в обучающую выборку только синтетические данные. Мы можем сделать это с помощью следующего кода:
from imblearn.over_sampling import SMOTE smt = SMOTE(random_state=0) X_train_SMOTE, y_train_SMOTE = smt.fit_sample(X_train, y_train)
Отсюда мы можем обучить нашу модель на обучающих данных с включенным SMOTE.
evaluate_model(X_train_SMOTE, y_train_SMOTE, clf)
Как мы видим, наша модель смогла более точно предсказать данные тестирования с включенными данными SMOTE. Однако одна проблема, вызывающая беспокойство, - это наша оценка перекрестной проверки. Оценка перекрестной проверки используется для оценки вашей модели на ограниченном наборе данных, чтобы предсказать, как модель будет работать с данными реального мира. В идеале мы хотим, чтобы наша оценка перекрестной проверки была такой же или близкой к нашей оценке тестирования. В этом случае наши оценки расходятся, потому что мы нарушили второе правило при работе с синтетическими данными, а именно:
Не помещайте синтетические данные в свои данные проверки!
Как и в случае с данными тестирования, мы хотим проверить нашу модель, используя только реальные данные. Это означает, что нам нужны только наши данные SMOTE в тренировочных свертках, а не в проверочных свертках. Пример того, как добавлять синтетические данные в каждую отдельную свертку, можно найти в документации научного набора с использованием функции StratifiedKFold.
К счастью для нас, есть модуль безукоризненного обучения, который может выполнять всю обработку данных за нас, модуль конвейера. Просто включите процесс SMOTE и вашу модель в конвейер, а модуль сделает все остальное. Для этой задачи вы можете использовать функцию Pipeline или make_pipeline.
from imblearn.pipeline import make_pipeline pipeline = make_pipeline(smt, clf) evaluate_model(X_train, y_train, pipeline)
Как мы видим, наша оценка перекрестной проверки теперь более точно отражает фактическую производительность, которую мы можем ожидать от нашей модели в реальном мире. Надеюсь, этот блог поможет вам реализовать вашу модель в реальном мире.