3.1. Перекрестная проверка: оценка производительности

Изучение параметров функции прогнозирования и тестирование ее на одних и тех же данных является методологической ошибкой: модель, которая будет просто повторять метки образцов, которые она только что увидела, будет иметь идеальную оценку, но пока не сможет предсказать что-либо полезное. невидимые данные. Такая ситуация называется переобучением. Чтобы этого избежать, при проведении (контролируемого) эксперимента с машинным обучением обычно используется часть имеющихся данных в виде набора тестов X_test, y_test. Обратите внимание, что слово «эксперимент» не предназначено для обозначения только академического использования, потому что даже в коммерческих условиях машинное обучение обычно начинается экспериментально. Вот блок-схема типичного рабочего процесса перекрестной проверки при обучении модели. Лучшие параметры могут быть определены методами поиска по сетке.

В scikit-learn можно быстро вычислить случайное разбиение на обучающие и тестовые наборы с помощью train_test_split вспомогательной функции. Давайте загрузим набор данных диафрагмы, чтобы он соответствовал линейной машине опорных векторов:

>>> import numpy as np
>>> from sklearn.model_selection import train_test_split
>>> from sklearn import datasets
>>> from sklearn import svm

>>> X, y = datasets.load_iris(return_X_y=True)
>>> X.shape, y.shape
((150, 4), (150,))

Теперь мы можем быстро выбрать обучающий набор, сохраняя 40% данных для тестирования (оценки) нашего классификатора:

>>> X_train, X_test, y_train, y_test = train_test_split(
...     X, y, test_size=0.4, random_state=0)

>>> X_train.shape, y_train.shape
((90, 4), (90,))
>>> X_test.shape, y_test.shape
((60, 4), (60,))

>>> clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.96...

При оценке различных настроек («гиперпараметров») для оценщиков, таких как Cнастройка, которая должна быть вручную установлена ​​для SVM, все еще существует риск переобучения на тестовом наборе, поскольку параметры можно настраивать до тех пор, пока оценщик не будет работать оптимально. Таким образом, знания о наборе тестов могут «просочиться» в модель, а показатели оценки больше не будут сообщать о производительности обобщения. Чтобы решить эту проблему, еще одна часть набора данных может быть представлена ​​как так называемый «набор для проверки»: обучение продолжается на обучающем наборе, после чего выполняется оценка на проверочном наборе, и когда эксперимент кажется успешным. , окончательную оценку можно провести на тестовом наборе.

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

Решением этой проблемы является процедура перекрестной проверки  (cross-validation сокращенно CV). Набор тестов по-прежнему должен храниться для окончательной оценки, но набор для проверки больше не нужен при выполнении резюме. В базовом подходе, называемом k- кратным CV, обучающая выборка разбивается на k меньших наборов (другие подходы описаны ниже, но обычно следуют тем же принципам). Для каждой из k «фолдов» выполняется следующая процедура :

  • Модель обучается с использованием $k−1$ складок в качестве обучающих данных;
  • Результирующая модель проверяется на оставшейся части данных (т. е. она используется в качестве тестового набора для вычисления показателя производительности, такого как точность).

Показатель производительности, сообщаемый k- фолд перекрестной проверкой, тогда является средним из значений, вычисленных в цикле. Этот подход может быть дорогостоящим в вычислительном отношении, но не тратит слишком много данных (как в случае фиксации произвольного набора проверки), что является основным преимуществом в таких задачах, как обратный вывод, когда количество выборок очень мало.

3.1.1. Вычисление метрик с перекрестной проверкой

Самый простой способ использовать перекрестную проверку — вызвать cross_val_score вспомогательную функцию для оценщика и набора данных.

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

>>> from sklearn.model_selection import cross_val_score
>>> clf = svm.SVC(kernel='linear', C=1, random_state=42)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores
array([0.96..., 1. , 0.96..., 0.96..., 1. ])

Таким образом, средний балл и стандартное отклонение выражаются следующим образом:

>>> print("%0.2f accuracy with a standard deviation of %0.2f" % (scores.mean(), scores.std()))
0.98 accuracy with a standard deviation of 0.02

По умолчанию оценка, вычисляемая на каждой итерации CV, является score методом оценщика. Это можно изменить, используя параметр оценки:

>>> from sklearn import metrics
>>> scores = cross_val_score(
...     clf, X, y, cv=5, scoring='f1_macro')
>>> scores
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

Подробнее см. Параметр скоринга: определение правил оценки модели . В случае набора данных Iris выборки сбалансированы по целевым классам, поэтому точность и оценка F1 (F1-score) почти равны.

Когда cv аргумент является целым числом, по умолчанию cross_val_score используются стратегии KFold или StratifiedKFold, причем последняя используется, если оценщик является производным от ClassifierMixin.

Также можно использовать другие стратегии перекрестной проверки, передав вместо этого итератор перекрестной проверки, например:

>>> from sklearn.model_selection import ShuffleSplit
>>> n_samples = X.shape[0]
>>> cv = ShuffleSplit(n_splits=5, test_size=0.3, random_state=0)
>>> cross_val_score(clf, X, y, cv=cv)
array([0.977..., 0.977..., 1.  ..., 0.955..., 1.        ])

Другой вариант — использовать итерируемые разбиения с получением (train, test) как массивы индексов, например:

>> def custom_cv_2folds(X):
...     n = X.shape[0]
...     i = 1
...     while i <= 2:
...         idx = np.arange(n * (i - 1) / 2, n * i / 2, dtype=int)
...         yield idx, idx
...         i += 1
...
>>> custom_cv = custom_cv_2folds(X)
>>> cross_val_score(clf, X, y, cv=custom_cv)
array([1.        , 0.973...])

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

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

>>> from sklearn import preprocessing
>>> X_train, X_test, y_train, y_test = train_test_split(
...     X, y, test_size=0.4, random_state=0)
>>> scaler = preprocessing.StandardScaler().fit(X_train)
>>> X_train_transformed = scaler.transform(X_train)
>>> clf = svm.SVC(C=1).fit(X_train_transformed, y_train)
>>> X_test_transformed = scaler.transform(X_test)
>>> clf.score(X_test_transformed, y_test)
0.9333...

Pipeline упрощает составление оценщиков, обеспечивая такое поведение при перекрестной проверке:

>>> from sklearn.pipeline import make_pipeline
>>> clf = make_pipeline(preprocessing.StandardScaler(), svm.SVC(C=1))
>>> cross_val_score(clf, X, y, cv=cv)
array([0.977..., 0.933..., 0.955..., 0.933..., 0.977...])

См Пайплайны и композитные оценоки.

3.1.1.1. Функция cross_validate и оценка нескольких показателей

В cross_validate функции отличается от cross_val_score двух способов:

  • Это позволяет указать несколько показателей для оценки.
  • Он возвращает dict, содержащий время соответствия (fit-times) , время оценки (score-times) (и, возможно, оценки обучения, а также подходящие оценки) в дополнение к оценке теста.

Для оценки единственной метрики, где параметром скоринга является строка, вызываемая или None, ключи будут: ['test_score', 'fit_time', 'score_time']

А для оценки нескольких показателей возвращаемое значение — это dict со следующими ключами: ['test_<scorer1_name>', 'test_<scorer2_name>', 'test_<scorer...>', 'fit_time', 'score_time']

return_train_score по умолчанию установлено значение False для экономии времени вычислений. Чтобы оценить баллы на тренировочном наборе, вам необходимо установить его на True.

Вы также можете сохранить оценку, установленную на каждом обучающем наборе, путем настройки return_estimator=True.

Множественные показатели могут быть указаны в виде списка, кортежа или набора заранее определенных имен счетчиков:

>>> from sklearn.model_selection import cross_validate
>>> from sklearn.metrics import recall_score
>>> scoring = ['precision_macro', 'recall_macro']
>>> clf = svm.SVC(kernel='linear', C=1, random_state=0)
>>> scores = cross_validate(clf, X, y, scoring=scoring)
>>> sorted(scores.keys())
['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro']
>>> scores['test_recall_macro']
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

Или как dict сопоставление имени счетчика с предопределенной или настраиваемой функцией оценки:

>>> from sklearn.metrics import make_scorer
>>> scoring = {'prec_macro': 'precision_macro',
...            'rec_macro': make_scorer(recall_score, average='macro')}
>>> scores = cross_validate(clf, X, y, scoring=scoring,
...                         cv=5, return_train_score=True)
>>> sorted(scores.keys())
['fit_time', 'score_time', 'test_prec_macro', 'test_rec_macro',
 'train_prec_macro', 'train_rec_macro']
>>> scores['train_rec_macro']
array([0.97..., 0.97..., 0.99..., 0.98..., 0.98...])

Вот пример cross_validate использования одной метрики:

>>> scores = cross_validate(clf, X, y,
...                         scoring='precision_macro', cv=5,
...                         return_estimator=True)
>>> sorted(scores.keys())
['estimator', 'fit_time', 'score_time', 'test_score']

3.1.1.2. Получение прогнозов путем перекрестной проверки

Функция cross_val_predict имеет аналогичный интерфейс cross_val_score, но возвращает для каждого элемента во входных данных прогноз, который был получен для этого элемента, когда он был в тестовом наборе. Могут использоваться только стратегии перекрестной проверки, которые назначают все элементы набору тестов ровно один раз (в противном случае возникает исключение).

Предупреждение

Замечание о неправильном использовании cross_val_predict. Результат cross_val_predict может отличаться от полученного при использовании, cross_val_score поскольку элементы сгруппированы по-разному. Функция cross_val_score берет среднее значение по сверткам перекрестной проверки, тогда как cross_val_predict просто возвращает метки (или вероятности) из нескольких различных моделей без различия. Таким образом, cross_val_predict не является подходящей мерой ошибки обобщения.

Функция cross_val_predict подходит для:

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

Доступные итераторы перекрестной проверки представлены в следующем разделе.

3.1.2. Итераторы перекрестной проверки

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

3.1.2.1. Итераторы перекрестной проверки для данных

Предполагая, что некоторые данные являются независимыми и идентично распределенными (Independent and Identically Distributed — i.i.d.), предполагается, что все выборки происходят из одного и того же генерирующего процесса и что генеративный процесс не имеет памяти о сгенерированных ранее выборках.

В таких случаях можно использовать следующие кросс-валидаторы.

Примечание

Хотя данные i.i.d — распространенное предположение в теории машинного обучения, на практике оно редко выполняется. Если известно, что образцы были сгенерированы с использованием процесса, зависящего от времени, безопаснее использовать схему перекрестной проверки с учетом временных рядов. Точно так же, если мы знаем, что генеративный процесс имеет групповую структуру (образцы, собранные у разных субъектов, эксперименты, измерительные устройства), безопаснее использовать групповую перекрестную проверку .

3.1.2.1.1. K-фолд

KFold делит все образцы на $k$ группы образцов, называемые складками (если $k = n$, это эквивалентно стратегии Leave One Out ) равных размеров (если возможно). Функция прогнозирования изучается с помощью $k − 1$ фолдов, а последний фолд используется для теста.

Пример 2-фолдовой перекрестной проверки на наборе данных с 4 образцами:

>>> import numpy as np
>>> from sklearn.model_selection import KFold

>>> X = ["a", "b", "c", "d"]
>>> kf = KFold(n_splits=2)
>>> for train, test in kf.split(X):
...     print("%s %s" % (train, test))
[2 3] [0 1]
[0 1] [2 3]

Вот визуализация поведения перекрестной проверки. Обратите внимание, на KFold не влияют классы или группы.

Каждая фолд состоит из двух массивов: первый связан с обучающим набором , а второй — с тестовым набором . Таким образом, можно создавать наборы для обучения / тестирования (training / test), используя индексирование numpy:

>>> X = np.array([[0., 0.], [1., 1.], [-1., -1.], [2., 2.]])
>>> y = np.array([0, 1, 0, 1])
>>> X_train, X_test, y_train, y_test = X[train], X[test], y[train], y[test]

3.1.2.1.2. Повторяющийся K-Fold

RepeatedKFold повторяет K-Fold n раз. Его можно использовать, когда нужно выполнить KFold n раз, производя разные разбиения в каждом повторении.

Пример 2-кратного K-Fold повторяется 2 раза:

>>> import numpy as np
>>> from sklearn.model_selection import RepeatedKFold
>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
>>> random_state = 12883823
>>> rkf = RepeatedKFold(n_splits=2, n_repeats=2, random_state=random_state)
>>> for train, test in rkf.split(X):
...     print("%s %s" % (train, test))
...
[2 3] [0 1]
[0 1] [2 3]
[0 2] [1 3]
[1 3] [0 2]

Аналогичным образом, RepeatedStratifiedKFold повторяет стратифицированный K-Fold n раз с различной рандомизацией в каждом повторении.

3.1.2.1.3. Оставьте один вне (LOO)

LeaveOneOut (или LOO) — это простая перекрестная проверка. Каждый обучающий набор создается путем взятия всех выборок, кроме одной, причем тестовая выборка не учитывается. Таким образом, дляn образцы, у нас есть $n$ различные тренировочные наборы и $n$ набор различных тестов. Эта процедура перекрестной проверки не тратит много данных, поскольку из обучающего набора удаляется только один образец:

>>> from sklearn.model_selection import LeaveOneOut

>>> X = [1, 2, 3, 4]
>>> loo = LeaveOneOut()
>>> for train, test in loo.split(X):
...     print("%s %s" % (train, test))
[1 2 3] [0]
[0 2 3] [1]
[0 1 3] [2]
[0 1 2] [3]

Потенциальные пользователи LOO при выборе модели должны взвесить несколько известных предостережений. Когда сравненивается k-фолдовая перекрестная проверка, одна сборка n модели из n образцы вместо $k$ модели, где $n > k$. Более того, каждый тренируется на $n−1$ образцы, а не $(k−1)n/k$. В обоих случаях, предполагая $k$ не слишком большой и $k<n$, LOO дороже в вычислительном отношении, чем k-фолдная перекрестная проверка.

Что касается точности, LOO часто приводит к большой дисперсии в качестве средства оценки ошибки теста. Интуитивно, поскольку $n−1$ принадлежащий $n$ образцы используются для построения каждой модели, модели, построенные из фолдов, практически идентичны друг другу и модели, построенной из всего обучающего набора.

Однако, если кривая обучения крутая для рассматриваемого размера обучения, то 5- или 10-фолдовая перекрестная проверка может переоценить ошибку обобщения.

Как правило, большинство авторов и эмпирические данные предполагают, что 5- или 10-фолдовая перекрестная проверка должна быть предпочтительнее LOO.

Рекомендации:

3.1.2.1.4. Оставить P Out (LPO)

LeavePOut очень похож на то, LeaveOneOut как он создает все возможные наборы для обучения / тестирования, удаляяpобразцы из комплекта. Дляn образцы, это производит ${n \choose p}$ пары поезд-тест. В отличие от LeaveOneOut и KFold, наборы тестов будут перекрываться дляp>1.

Пример Leave-2-Out в наборе данных с 4 образцами:

>>> from sklearn.model_selection import LeavePOut

>>> X = np.ones(4)
>>> lpo = LeavePOut(p=2)
>>> for train, test in lpo.split(X):
...     print("%s %s" % (train, test))
[2 3] [0 1]
[1 3] [0 2]
[1 2] [0 3]
[0 3] [1 2]
[0 2] [1 3]
[0 1] [2 3]

3.1.2.1.5. Перекрестная проверка случайных перестановок, известная как Shuffle & Split

Итератор ShuffleSplit будет генерировать, определенные пользователем, число независимых обученые / тестовые наборы данных разделений. Образцы сначала перемешиваются, а затем разделяются на пару наборов для обучения и тестов.

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

Вот пример использования:

>>> from sklearn.model_selection import ShuffleSplit
>>> X = np.arange(10)
>>> ss = ShuffleSplit(n_splits=5, test_size=0.25, random_state=0)
>>> for train_index, test_index in ss.split(X):
...     print("%s %s" % (train_index, test_index))
[9 1 6 7 3 0 5] [2 8 4]
[2 9 8 0 6 7 4] [3 5 1]
[4 5 1 0 6 9 7] [2 3 8]
[2 7 5 8 0 3 4] [6 1 9]
[4 1 0 6 8 9 3] [5 2 7]

Вот визуализация поведения перекрестной проверки. Обратите внимание, на ShuffleSplit это не влияют классы или группы.

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

3.1.2.2. Итераторы перекрестной проверки со стратификацией на основе меток классов.

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

3.1.2.2.1. Стратифицированный k-фолд

StratifiedKFold представляет собой разновидность k-фолдовой кратности, которая возвращает стратифицированные фолды: каждый набор содержит примерно такой же процент выборок каждого целевого класса, что и полный набор.

Вот пример стратифицированной 3-фолдовой перекрестной проверки для набора данных с 50 выборками из двух несбалансированных классов. Показываем количество образцов в каждом классе и сравниваем с KFold.

>>> from sklearn.model_selection import StratifiedKFold, KFold
>>> import numpy as np
>>> X, y = np.ones((50, 1)), np.hstack(([0] * 45, [1] * 5))
>>> skf = StratifiedKFold(n_splits=3)
>>> for train, test in skf.split(X, y):
...     print('train -  {}   |   test -  {}'.format(
...         np.bincount(y[train]), np.bincount(y[test])))
train -  [30  3]   |   test -  [15  2]
train -  [30  3]   |   test -  [15  2]
train -  [30  4]   |   test -  [15  1]
>>> kf = KFold(n_splits=3)
>>> for train, test in kf.split(X, y):
...     print('train -  {}   |   test -  {}'.format(
...         np.bincount(y[train]), np.bincount(y[test])))
train -  [28  5]   |   test -  [17]
train -  [28  5]   |   test -  [17]
train -  [34]   |   test -  [11  5]

Мы видим, что StratifiedKFold соотношение классов (примерно 1/10) сохраняется как в обучающем, так и в тестовом наборе данных.

Вот визуализация поведения перекрестной проверки.

RepeatedStratifiedKFold может использоваться для повторения стратифицированного K-фолдов n раз с различной рандомизацией в каждом повторении.

3.1.2.2.2. Стратифицированное перемешивание в случайном порядке

StratifiedShuffleSplit— это вариант ShuffleSplit , который возвращает расслоенные разбиения, т. е. создает разбиения, сохраняя тот же процент для каждого целевого класса, что и в полном наборе.

Вот визуализация поведения перекрестной проверки.

3.1.2.3. Итераторы перекрестной проверки для сгруппированных данных.

Предположение iid нарушается, если основной процесс генерации дает группы зависимых выборок.

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

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

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

3.1.2.3.1. Группа K фолд

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

Представьте, что у вас есть три предмета, каждому из которых соответствует номер от 1 до 3:

>>> from sklearn.model_selection import GroupKFold

>>> X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 8.8, 9, 10]
>>> y = ["a", "b", "b", "b", "c", "c", "c", "d", "d", "d"]
>>> groups = [1, 1, 1, 2, 2, 2, 3, 3, 3, 3]

>>> gkf = GroupKFold(n_splits=3)
>>> for train, test in gkf.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[0 1 2 3 4 5] [6 7 8 9]
[0 1 2 6 7 8 9] [3 4 5]
[3 4 5 6 7 8 9] [0 1 2]

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

Вот визуализация поведения перекрестной проверки.

3.1.2.3.2. Оставьте одну группу вне (Leave One Group Out)

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

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

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

>>> from sklearn.model_selection import LeaveOneGroupOut

>>> X = [1, 5, 10, 50, 60, 70, 80]
>>> y = [0, 1, 1, 2, 2, 2, 2]
>>> groups = [1, 1, 2, 2, 3, 3, 3]
>>> logo = LeaveOneGroupOut()
>>> for train, test in logo.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[2 3 4 5 6] [0 1]
[0 1 4 5 6] [2 3]
[0 1 2 3] [4 5 6]

Другое распространенное применение — использование информации о времени: например, группы могут быть годом сбора образцов и, таким образом, допускать перекрестную проверку на разбиение по времени.

3.1.2.3.3. Оставьте P групп вне (Leave P Groups Out)

LeavePGroupsOut аналогичен LeaveOneGroupOut, но удаляет образцы, относящиеся к $P$ группы для каждой обучающей / тестовой выборки.

Пример выхода из группы 2 из 2:

>>> from sklearn.model_selection import LeavePGroupsOut

>>> X = np.arange(6)
>>> y = [1, 1, 1, 2, 2, 2]
>>> groups = [1, 1, 2, 2, 3, 3]
>>> lpgo = LeavePGroupsOut(n_groups=2)
>>> for train, test in lpgo.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[4 5] [0 1 2 3]
[2 3] [0 1 4 5]
[0 1] [2 3 4 5]

3.1.2.3.4. Групповой случайный сплит

В GroupShuffleSplit итераторе ведет себя как комбинации , ShuffleSplit и LeavePGroupsOut, и генерирует последовательность рандомизированных групп , в которых подмножество групп проводятся для каждого разбивки.

Вот пример использования:

>>> from sklearn.model_selection import GroupShuffleSplit

>>> X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 0.001]
>>> y = ["a", "b", "b", "b", "c", "c", "c", "a"]
>>> groups = [1, 1, 2, 2, 3, 3, 4, 4]
>>> gss = GroupShuffleSplit(n_splits=4, test_size=0.5, random_state=0)
>>> for train, test in gss.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
...
[0 1 2 3] [4 5 6 7]
[2 3 6 7] [0 1 4 5]
[2 3 4 5] [0 1 6 7]
[4 5 6 7] [0 1 2 3]

Вот визуализация поведения перекрестной проверки.

Этот класс полезен, когда LeavePGroupsOut требуется поведение , но количество групп достаточно велико, чтобы генерировать все возможные разделы сPудерживаемые группы будут непомерно дорогими. В таком сценарии GroupShuffleSplit предоставляет случайную выборку (с заменой) разделений обучение / тест, сгенерированных LeavePGroupsOut.

3.1.2.4. Предопределенные Fold-Splits / Validation-Sets

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

Например, при использовании набора проверки установите test_fold значение 0 для всех образцов, которые являются частью набора проверки, и значение -1 для всех других образцов.

3.1.2.5. Использование итераторов перекрестной проверки для разделения обучения и тестирования

Вышеупомянутые групповые функции перекрестной проверки также могут быть полезны для разделения набора данных на подмножества обучения и тестирования. Обратите внимание, что вспомогательная функция train_test_split является оболочкой ShuffleSplit и, таким образом, допускает только стратифицированное разбиение (с использованием меток классов) и не может учитывать группы.

Чтобы выполнить разделение поезда и теста, используйте индексы для подмножеств поезда и теста, полученные на выходе генератора split() методом разделителя перекрестной проверки. Например:

>>> import numpy as np
>>> from sklearn.model_selection import GroupShuffleSplit

>>> X = np.array([0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 0.001])
>>> y = np.array(["a", "b", "b", "b", "c", "c", "c", "a"])
>>> groups = np.array([1, 1, 2, 2, 3, 3, 4, 4])
>>> train_indx, test_indx = next(
...     GroupShuffleSplit(random_state=7).split(X, y, groups)
... )
>>> X_train, X_test, y_train, y_test = \
...     X[train_indx], X[test_indx], y[train_indx], y[test_indx]
>>> X_train.shape, X_test.shape
((6,), (2,))
>>> np.unique(groups[train_indx]), np.unique(groups[test_indx])
(array([1, 2, 4]), array([3]))

3.1.2.6. Перекрестная проверка данных временных рядов

Данные временных рядов характеризуются корреляцией между близкими по времени наблюдениями ( автокорреляция ). Тем не менее, классические методы кросс-проверки , такие как KFold и ShuffleSplit предположим , образцы являются независимыми и одинаково распределенными, и привело бы к необоснованному корреляции между обучения и тестирования случаев (получая плохие оценки ошибки обобщения) на данных временных рядов. Следовательно, очень важно оценивать нашу модель для данных временных рядов по «будущим» наблюдениям, в меньшей степени, чем те, которые используются для обучения модели. Для этого существует одно решение TimeSeriesSplit.

3.1.2.6.1. Разделение временных рядов

TimeSeriesSplit это вариант k-фолд возврата, который возвращается первымk складывается как набор поездов и ($k+1$)-я фолдов в качестве тестового набора. Обратите внимание, что в отличие от стандартных методов перекрестной проверки, последовательные обучающие наборы являются надмножествами предшествующих. Кроме того, он добавляет все лишние данные в первый обучающий раздел, который всегда используется для обучения модели.

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

Пример перекрестной проверки 3-сегментных временных рядов на наборе данных с 6 выборками:

>>> from sklearn.model_selection import TimeSeriesSplit

>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]])
>>> y = np.array([1, 2, 3, 4, 5, 6])
>>> tscv = TimeSeriesSplit(n_splits=3)
>>> print(tscv)
TimeSeriesSplit(gap=0, max_train_size=None, n_splits=3, test_size=None)
>>> for train, test in tscv.split(X):
...     print("%s %s" % (train, test))
[0 1 2] [3]
[0 1 2 3] [4]
[0 1 2 3 4] [5]

Вот визуализация поведения перекрестной проверки.

3.1.3. Замечание о перемешивании

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

Некоторые итераторы перекрестной проверки, например KFold, имеют встроенную возможность перетасовать индексы данных перед их разделением. Обратите внимание, что:

  • Это потребляет меньше памяти, чем перетасовка данных напрямую.
  • По умолчанию не перетасовка не происходит, в том числе и для (стратификация) K фолд кросс- проверка выполняется путем указания cv=some_integerдля cross_val_score, поиска сетки и т.д. Имейте в виду , что по- train_test_split прежнему возвращает случайное разделение.
  • По random_state умолчанию для параметра установлено None значение, что означает, что перемешивание будет разным при каждой KFold(…, shuffle=True) итерации . Однако GridSearchCVfit будет использоваться одно и то же перемешивание для каждого набора параметров, проверенных одним вызовом его метода.
  • Чтобы получить одинаковые результаты для каждого разделения, задайте random_state целое число.

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

3.1.4. Перекрестная проверка и выбор модели

Итераторы перекрестной проверки также могут использоваться для непосредственного выбора модели с помощью поиска по сетке для определения оптимальных гиперпараметров модели. Это тема следующего раздела: Настройка гиперпараметров оценщика .

3.1.5. Результат теста на перестановку (Permutation test score)

permutation_test_score предлагает другой способ оценки производительности классификаторов. Он обеспечивает p-значение на основе перестановок, которое показывает, насколько вероятно, что наблюдаемая производительность классификатора будет получена случайно. Нулевая гипотеза в этом тесте заключается в том, что классификатор не может использовать какую-либо статистическую зависимость между функциями и метками, чтобы делать правильные прогнозы на основе оставленных данных. permutation_test_score генерирует нулевое распределение, вычисляя n_permutations различные перестановки данных. В каждой перестановке метки случайным образом перемешиваются, тем самым удаляя любую зависимость между функциями и метками. Выходное значение p — это доля перестановок, для которых средняя оценка перекрестной проверки, полученная моделью, лучше, чем оценка перекрестной проверки, полученная моделью с использованием исходных данных. Для надежных результатовn_permutationsобычно должно быть больше 100 и составлять cvот 3 до 10 фолдов.

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

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

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

Наконец, permutation_test_score вычисляется методом грубой силы и полностью соответствует (n_permutations + 1) * n_cv моделям. Следовательно, его можно обрабатывать только с небольшими наборами данных, для которых подгонка отдельной модели выполняется очень быстро.

Рекомендации: