Узнайте, когда использовать стратифицированную K-кратность и как реализовать ее на Python с помощью Sci-Kit Learn

В этом уроке мы рассмотрим стратифицированную перекрестную проверку kfold: что это такое и когда мы должны ее использовать. Затем мы рассмотрим, как разделить данные на 5 стратифицированных сгибов с помощью функции StratifiedKFold в Sci-Kit Learn и использовать эти складки для обучения и тестирования модели перед экспортом всех разделений в файлы csv.

Что такое стратифицированная перекрестная проверка KFold?

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

Давайте посмотрим на пример. Если мы строим модель для классификации изображений кошек и собак и у нас есть набор данных, состоящий из 75% изображений кошек и 25% изображений собак, использование стратифицированной перекрестной оценки kfold будет означать, что каждая созданная нами складка остается близкой к этой 75/. соотношение 25.

Когда использовать стратифицированную перекрестную проверку Kfold

1. Мы хотим сохранить соотношение классов нашей цели

2. У нас относительно меньше обучающих примеров

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

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

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

Теперь, когда мы понимаем, что это за метод и когда его использовать, давайте посмотрим, как реализовать его в Python с помощью Sci-Kit Learn.

Как реализовать стратифицированный Kfold с помощью Scikit-Learn

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

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

Начнем с импорта Pandas и функции StratifiedKFold из SciKit-Learn. Мы также будем читать наши данные из csv в DataFrame.

import pandas as pd
from sklearn.model_selection import StratifiedKFold
df = pd.read_csv('data/processed_data.csv')

Нашей целью здесь является столбец Returned_Units, который будет равен 1 или 0.

Давайте быстро проверим, как выглядит соотношение классов для этого столбца.

print('Class Ratio:',
       sum(df['Returned_Units'])/len(df['Returned_Units']))
> Class Ratio: 0.216

Как видно из наших данных, в 21,6% случаев товар возвращается. Когда мы создаем наши складки, мы хотим, чтобы каждый сплит имел одинаковый процент возврата.

Давайте инициализируем объект StratifiedKFold и объявим желаемое количество разбиений, которое в нашем случае равно 5.

skf = StratifiedKFold(n_splits=5)

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

target = df.loc[:,'Returned_Units']

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

fold_no = 1
for train_index, test_index in skf.split(df, target):
    train = df.loc[train_index,:]
    test = df.loc[test_index,:]
    print('Fold',str(fold_no),
          'Class Ratio:',
          sum(test['Returned_Units'])/len(test['Returned_Units']))
    fold_no += 1

> Fold 1 Class Ratio 0.215
> Fold 2 Class Ratio 0.215
> Fold 3 Class Ratio 0.215
> Fold 4 Class Ratio 0.2175
> Fold 5 Class Ratio 0.2175

Как и в случае с обычной перекрестной проверкой KFold, каждое разделение поезда содержит 4 сгиба, а тестовый набор содержит один сгиб, поэтому мы используем тестовый сплит для определения соотношения классов для каждого сгиба. Вы можете видеть, что соотношение классов каждой складки близко к полному набору данных, что, очевидно, нам и нужно.

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

Разделение и обучение модели машинного обучения

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

Сначала мы импортируем необходимые библиотеки и инициализируем модель.

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
model = LogisticRegression()

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

def train_model(train, test, fold_no):
   X = ['Retail_Price','Discount']
   y = ['Returned_Units']
   X_train = train[X]
   y_train = train[y]
   X_test = test[X]
   y_test = test[y]
   model.fit(X_train,y_train)
   predictions = model.predict(X_test)
   print('Fold',str(fold_no),
         'Accuracy:',
         accuracy_score(y_test,predictions))

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

fold_no = 1
for train_index, test_index in skf.split(df, target):
    train = df.loc[train_index,:]
    test = df.loc[test_index,:]
    train_model(train,test,fold_no)
    fold_no += 1

> Fold 1 Accuracy: 0.785
> Fold 2 Accuracy: 0.785
> Fold 3 Accuracy: 0.785
> Fold 4 Accuracy: 0.7825
> Fold 5 Accuracy: 0.7825

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

Разделение и экспорт в CSV

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

fold_no = 1
for train_index, test_index in skf.split(df, target):
    train = df.loc[train_index,:]
    test = df.loc[test_index,:]
    train_filename = 'train_split_' + str(fold_no) + '.csv'
    test_filename = 'test_split_' + str(fold_no) + '.csv'
    train.to_csv('data/splits/' + train_filename, index=False)
    test.to_csv('data/splits/' + test_filename, index=False)
    fold_no += 1

Как вы видели, стратифицированная перекрестная проверка k-fold — чрезвычайно полезный метод перекрестной проверки с множеством приложений для проектов различного типа. Его также легко реализовать с помощью Sci-Kit Learn, и он должен быть инструментом, который все специалисты по данным используют в разное время.

Для получения более подробной информации о функции Sci-Kit Learn StratifiedKFold вы можете просмотреть документацию здесь.

Сохраняйте и систематизируйте фрагменты кода Data Science на сайте www.datasnips.com

Первоначально опубликовано на https://www.analyseup.com.