Stratifiedkfold что это
Перейти к содержимому

Stratifiedkfold что это

  • автор:

Введение в кросс-валидацию k-fold

Введение в кросс-валидацию k-fold

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

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

В этом уроке мы рассмотрим процедуру кросс-валидации k-fold для оценки качества моделей машинного обучения.

После завершения этого урока, вы будете знать:

  • Как использовать k-fold кросс-валидацию для оценки квалификации модели на новых данных.
  • общие тактики, которые можно использовать, чтобы выбрать значение k для набора данных.
  • широко используемые вариации на перекрестной проверки, такие как стратифицированы (stratified) и repeated, которые доступны в библиотеки scikit-learn.

Урок состоит из 5 частей:

  • k-Fold Кросс-Валидация
  • Конфигурация k
  • Рабочий пример
  • Работы с API кросс-валидации
  • Вариации на кросс-валидации

k-Fold кросс-Валидация

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

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

Перекрестная проверка в основном используется в прикладном машинном обучении для оценки квалификации модели машинного обучения на не используемых данных. То есть использовать ограниченную выборку (test sample) для оценки того, как модель будет работать в целом при использовании ее при прогнозирования на данных, не используемых во время обучения модели.

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

Общая процедура заключается в следующем:

1. Перемешайте датасет случайным образом

2. Разделите датасет на k-групп

3. Для каждой уникальной выборки:

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

4. Обобщите параметры качества модели с помощью выборки оценки моделей

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

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

Результаты кросс-валидации k-fold часто суммируются со средним итогом качества модели. Также хорошей практикой является включение показателя дисперсии оценок качества, таких как стандартное отклонение или стандартная ошибка.

Конфигурация параметра k

Значение k должно быть тщательно выбрано для выборки данных.

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

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

  • Представитель: Значение для k выбрано таким образом, что каждая группа подборка/тестовая группа данных достаточно велика, чтобы быть статистически репрезентативной для более широкого набора данных.
  • k=10: Значение для k фиксируется до 10. Данное число было найдено в ходе экспериментов и обычно приводит к оценке качества модели с низкой предвзятостью небольшую дисперсии.
  • k = n: Значение для k фиксируется на n, где n является размером набора данных, чтобы дать каждому тестовой группе возможность быть использованной в наборе данных.

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

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

Рабочий пример

Чтобы сделать процедуру перекрестной проверки конкретной, давайте посмотрим на пример спроработанных.

Представьте, что у нас есть выборка данных с 6 наблюдениями:

[0.1, 0.2, 0.3, 0.4, 0.5, 0.6]

Первым шагом является выбор значения для k для определения количества выборок, используемых для разделения данных. Здесь мы будем использовать значение k=3. Это означает, что мы будем тасовать данные, а затем разделить данные на 3 группы. Поскольку у нас есть 6 наблюдений, каждая группа будет иметь равно 2 наблюдения.

subset1: [0,5, 0,2] subset2: [0,1, 0,3] subset3: [0,4, 0,6]

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

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

  • Модель1: обучаем на subset1 и subset2, тестируем на subset3
  • Модель2: обучаем на subset2 и subset3, тестируем на subset1
  • Модель3: обучаем на subset1 и subset3, тестируем на subset2

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

Оценки качества собираются для каждой модели и суммируются для использования.

API кросс-валидации

Мы не должны осуществлять k-fold проверки вручную. Библиотека scikit-learn предоставляет реализацию, которая поможет разделить датасет .

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

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

kfold = KFold(3, True, 1)

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

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

#перечисление выборок датасета for train, test in kfold.split(data): print('train: %s, test: %s' % (train, test))

Мы можем связать все это вместе с нашим датасетом, используемым в примере из предыдущего раздела.

# scikit-learn k-fold кросс-валидация from numpy import arrayfrom sklearn.model_selection import KFold # датасет data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6]) # подготовьте кросс валидацию kfold = KFold(3, True, 1) # перечисление выборок датасета for train, test in kfold.split(data): print('train: %s, test: %s' % (data[train], data[test]))

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

train: [0.1 0.4 0.5 0.6], test: [0.2 0.3] train: [0.2 0.3 0.4 0.6], test: [0.1 0.5] train: [0.1 0.2 0.3 0.5], test: [0.4 0.6]

Реализация перекрестной проверки k-fold в scikit-learn предоставляется в качестве компонентной операции в рамках более широких методов, таких как гиперпараметры модели поиска сетки и оценка модели на наборе данных.

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

Вариации на кросс-валидацию

Существует ряд вариаций процедуры перекрестной проверки k-fold.

Три часто используемых варианта:

  • Обучение / Тест выборка: Самая крайность, это когда k = 2 (не 1) так, что одна выборка идет на обучение и одна и тест для оценки модели.
  • LOOCV: Другая крайность, когда k равен общему размеру наблюдений в датасете. По-английски это называется leave-one-out cross-validation, или LOOCV для краткости.
  • Стратифицированная выборка (stratified): разделение данных на складки может регулироваться такими критериями, чтобы каждая выборка имела одинаковую пропорцию наблюдений с заданным категоричным значением, например значением класса. Это называется стратифицированной перекрестной проверкой.
  • Повторяющаяся выборка (repeated): k-fold перекрестная валидация повторяется n раз, и датасет перетасовывается на каждой итерации, что приводит к иной выборки данных.

Библиотека scikit-learn предоставляет набор реализации перекрестной проверки

Подведем итог


В этом уроке вы узнали про процедуру перекрестной проверки k-fold для оценки качества моделей машинного обучения.

В частности, вы узнали:

  • Что k-fold кросс валидация это процедура, используемая для оценки квалификации модели на новых данных.
  • общие тактики, которые можно использовать, чтобы выбрать значение k для набора данных.
  • широко используемые вариации кросс-валидации, такие как стратифицированные и повторяющиеся, которые доступны в scikit-learn.

Полезные ссылки:

  • sklearn.model_selection.KFold() API
  • sklearn.model_selection: Model Selection API

sklearn.model_selection.StratifiedKFold

Предоставляет индексы train/test для разделения данных в наборах train/test.

Этот объект перекрестной проверки является вариантом KFold, который возвращает стратифицированные складки. Складки сделаны с сохранением процентного соотношения образцов для каждого класса.

Подробнее читайте в User Guide .

Parameters: n_splitsint, default=5

Количество складок. Должно быть не менее 2.

Изменено в версии 0.22: Значение n_splits по умолчанию изменено с 3 на 5.

shufflebool, default=False

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

random_stateint, экземпляр RandomState или None, default=None

Когда shuffle равен True, random_state влияет на порядок индексов, который управляет случайностью каждой кратности для каждого класса. В противном случае оставьте random_state как None . Передайте int для воспроизводимого вывода при нескольких вызовах функций. См. Glossary .

Повторяет Stratified K-Fold n раз.

Notes

Реализация предназначена для:

  • Создавайте наборы тестов таким образом, чтобы все они содержали одинаковое или максимально близкое распределение классов.
  • Быть инвариантным к метке класса: изменение маркировки y = [«Happy», «Sad»] на y = [1, 0] не должно изменять сгенерированные индексы.
  • Сохранять зависимости порядка в упорядочении набора данных, когда shuffle=False : все выборки из класса k в некотором наборе тестов были смежными по y или разделены по y выборками из классов, отличных от k.
  • Создайте наборы тестов, в которых наименьший и наибольший отличаются не более чем на одну выборку.

Изменено в версии 0.22: Предыдущая реализация не соответствовала последнему ограничению.

Examples
>>> import numpy as np >>> from sklearn.model_selection import StratifiedKFold >>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]]) >>> y = np.array([0, 0, 1, 1]) >>> skf = StratifiedKFold(n_splits=2) >>> skf.get_n_splits(X, y) 2 >>> print(skf) StratifiedKFold(n_splits=2, random_state=None, shuffle=False) >>> for train_index, test_index in skf.split(X, y): . print("TRAIN:", train_index, "TEST:", test_index) . X_train, X_test = X[train_index], X[test_index] . y_train, y_test = y[train_index], y[test_index] TRAIN: [1 3] TEST: [0 2] TRAIN: [0 2] TEST: [1 3]
Methods

П14153П Т25387Т у, В36246В

Возвращает количество итераций разделения в кросс-валидаторе

К14153К К25387К Т36246Т В45910В

Создайте индексы, чтобы разделить данные на обучающий и тестовый наборы.

К14153КТ25387Т, В36246В, З45910З) П14153П

Возвращает количество итераций разделения в кросс-валидаторе

Parameters: Xobject

Всегда игнорируется, существует для совместимости.

yobject

Всегда игнорируется, существует для совместимости.

groupsobject

Всегда игнорируется, существует для совместимости.

Returns: n_splitsint

Возвращает количество итераций разделения в кросс-валидаторе.

раскол (X, Y, groups=None) [source]

Создайте индексы, чтобы разделить данные на обучающий и тестовый наборы.

Parameters: Рентгеноподобная форма (n_samples, n_features)

Данные обучения, где n_samples — количество выборок, а n_features — количество признаков.

Обратите внимание, что предоставления y достаточно для создания разбиений, и, следовательно, np.zeros(n_samples) можно использовать в качестве заполнителя для X вместо фактических обучающих данных.

похожий на яррей формы (n_samples,)

Целевая переменная для задач контролируемого обучения. Стратификация выполняется на основе меток y.

groupsobject

Всегда игнорируется, существует для совместимости.

Yields: trainndarray

Индексы тренировочного набора для этого разделения.

testndarray

Индексы набора тестов для этого разделения.

Notes

Рандомизированные разделители CV могут возвращать разные результаты для каждого вызова разделения. Вы можете сделать результаты идентичными, установив random_state в целое число.

Варим ML Boot Camp III: Starter Kit

16 марта закончилось соревнование по машинному обучению ML Boot Camp III. Я не настоящий сварщик, но, тем не менее, смог добиться 7го места в финальной таблице результатов. В данной статье я хотел бы поделиться тем, как начать участвовать в такого рода чемпионатах, на что стоит обратить внимание в первый раз при решении задачи, и рассказать о своем подходе.

ML Boot Camp III

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

Описание данных

  • maxPlayerLevel — максимальный уровень игры, который прошел игрок;
  • numberOfAttemptedLevels — количество уровней, которые попытался пройти игрок;
  • attemptsOnTheHighestLevel — число попыток, сделанных на самом высоком уровне;
  • totalNumOfAttempts — общее число попыток;
  • averageNumOfTurnsPerCompletedLevel — среднее количество ходов, выполненных на успешно пройденных уровнях;
  • doReturnOnLowerLevels — делал ли игрок возвраты к игре на уже пройденных уровнях;
  • numberOfBoostersUsed — количество использованных бустеров;
  • fractionOfUsefullBoosters — количество бустеров, использованных во время успешных попыток (игрок прошел уровнь);
  • totalScore — общее количество набранных очков;
  • totalBonusScore — общее количество набранных бонусных очков;
  • totalStarsCount — общее количество набранных звезд;
  • numberOfDaysActuallyPlayed — количество дней, когда пользователь играл в игру.

Более подробно о чемпионате можно узнать на сайте проекта.

Читаем правила

В отличие от инструкций к бытовой технике, тут есть полезная информация. На что обратить внимание:

  • форматы входных и выходных данных;
  • максимальное количество посылок в день;
  • критерий качества/функция оценки.

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

Здесь
N — это количество примеров
M — это количество классов (их всего два)
Pij — это предсказанная вероятность принадлежности примера i к классу j
Yij — равняется 1, если пример i действительно принадлежит классу j, и 0 в противном случае

Важно отметить, что данная формула сильно “наказывает” самоуверенность в ответах. Поэтому в качестве решения выгоднее посылать вероятность того, что игрок продолжит играть вместо однозначных “1” и “0”.

Иногда изучение функции оценки позволяет слегка схитрить и получить дополнительные баллы (как это сделал победитель прошлого и текущего соревнований).

Больше информации по разным метрикам можно прочитать здесь.

Инструментарий

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

В этот раз большинство участников выбирали между Python и R. Общая рекомендация: придерживаться одного языка и более глубоко изучать возможности доступных инструментов. Для обоих языков есть хорошие решения, а самые популярные библиотеки (например XGBoost) доступны и там и там.

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

Я выбрал python, и мое финальное решение использовало следующие библиотеки:

  • scikit learn — большой набор инструментов для машинного обучения. Изначально можно ограничится только ей.
  • XGBoost — градиентный бустинг. Одна из самых любимых библиотек участников чемпионатов по машинному обучению.
  • LightGBM — альтернатива XGBoost, в моем случае она работала на порядок быстрее последнего, но выдавала чуть менее точные результаты.
  • Lasagne — библиотека для создания и обучения нейронных сетей с использованием Theano. Как альтернативу можно попробовать Keras — она выглядит чуть более простой и документации по ней попадалось больше. Но коней на переправе не меняют и я решил придерживаться первоначального выбора.

Первый сабмит

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

>>> import numpy as np >>> import pandas as pd >>> X_train = pd.read_csv('x_train.csv', sep=';') >>> X_test = pd.read_csv('x_test.csv', sep=';') >>> y_train = pd.read_csv('y_train.csv', header=None).values.ravel() >>> print(X_train.shape, X_test.shape, y_train.shape) (25289, 12) (25289, 12) (25289,) >>> result = np.zeros((X_test.shape[0])) >>> pd.DataFrame(result).to_csv('submit.csv', index=False, header=False)

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

>>> from sklearn.ensemble import RandomForestClassifier >>> clf = RandomForestClassifier() >>> clf.fit(X_train, y_train) >>> result = clf.predict_proba(X_test)[:,1] >>> pd.DataFrame(result).to_csv('submit.csv', index=False, header=False)

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

Зафиксировать значение seed

>>> np.random.seed(2707) >>> clf = RandomForestClassifier(random_state=2707) . 

Запустить алгоритм с разными seed и взять средний результат

>>> runs = 1000 >>> results = np.zeros((runs, X_test.shape[0])) >>> for i in range(runs): … clf = RandomForestClassifier(random_state=2707+i) … clf.fit(X_train, y_train) … results[i, :]=clf.predict_proba(X_test)[:,1] >>> result = results.mean(axis=0)

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

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

Подготовка данных

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

Про дубликаты стоит отметить, что они зачастую относились к разным классам (пользователи с одинаковыми данными могли как остаться так и уйти из игры), и не имея дополнительной информации затруднительно сделать точное предсказание. К счастью, большинство моделей справлялись с этим самостоятельно, выводя вероятности, которые минимизируют оценочную функцию, в нашем случае — log loss.

UPD: участнику с третьего места все же удалось использовать этот факт в свою пользу.

Подготовленные организаторами данные — это скорее исключение из правил, а значит, нужно быть готовым самому обработать их. Кроме дубликатов строк и выбросов, данные могут содержать пропущенные значения. Удалять строки с пропущенными значениями слишком расточительно, т.к. они все еще содержат полезную информацию. Следовательно, у нас осталось 2 выхода:

  • оставить все как есть: некоторые алгоритмы могут работать с пропущенными (NA) значениями;
  • попытаться восстановить их.

Для восстановления можно просто произвести замену на более часто встречаемое (категориальные признаки), среднее или медианное значение. В python для этого можно воспользоваться sklearn.preprocessing.Imputer классом. Есть и более сложные способы с использованием других признаков (например, среднее значение среди пользователей одного уровня), я пробовал даже обучать еще одну модель, которая по другим столбцам предсказывает пропущенное значение. Ах да, выше я писал, что данные подготовлены и в них нет пропущенных значений, на самом деле это не совсем так.

Если прочитать правила внимательнее, то становится ясно, что почти все признаки — это статистика, основанная на логах за 2 недели. Более детальное изучение данных показывает, что немало пользователей начали играть раньше, чем 2 недели назад. Если их отсеивать, то на кросс-валидации я получал невероятно хорошие оценки, это навело меня на мысль, что ключом к победе может быть улучшение предсказаний для оставшихся “грязных” данных. Попытки восстановить данные для пользователя на момент 2х недель назад не дали сильного прироста, но я оставил это решение и позже использовал его вместе с другими.

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

Немного графиков

image

Все данные:

image

Только пользователи, начавшие играть в течение 2х недельного периода:

image

Попытка восстановить данные по другим столбцам:

image

“Инвертирование” для пользователей, начавших играть раньше 2х недель назад:

В определенных случаях имеет смысл сразу избавиться от некоторых признаков:

  • константные признаки;
  • два сильно коррелирующих признака (нужен только один из них);
  • признаки с близкой к нулевой дисперсией.

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

Последнее, что можно сделать с данными на начальном этапе — это масштабирование. Само по себе оно не меняет зависимости между признаками, но может значительно улучшить предсказания для некоторых (например линейных) моделей. В python для этого можно использовать классы: sklearn.preprocessing.StandardScaler, sklearn.preprocessing.MinMaxScaler и sklearn.preprocessing.MaxAbsScaler.

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

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

Проверяем себя

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

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

Разбиваем данные на K фолдов: на К-1 фолдах обучаем, а для оставшегося предсказываем и считаем оценку предсказания. Так повторяем для всех К фолдов. Финальная оценка считается как среднее оценок для каждого фолда.

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

Важную роль играет и качество разбиения на фолды. Чтобы сохранить распределение классов при разбивке, я использовал sklearn.model_selection.StratifiedKFold. Это особенно важно, если классы изначально сильно несбалансированы. Кроме этого могут возникнуть и другие проблемы с распределением данных по фолдам (дни недели, время, пользователи и т.д.), которые нужно проверять и исправлять отдельно.

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

>>> from sklearn.model_selection import StratifiedKFold, cross_val_score >>> clf = RandomForestClassifier(random_state=2707) >>> kf = StratifiedKFold(random_state=2707, n_splits=5, shuffle=True) >>> scores = cross_val_score(clf, X_train, y_train, cv=kf) >>> print("CV scores:", scores) CV scores: [ 0.8082625 0.81059707 0.8024911 0.81431679 0.81926043] >>> print("mean:", np.mean(scores)) mean: 0.810985579862 >>> print("std:", np.std(scores)) std: 0.00564433052781

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

Усложняем модель (что работает, то не безобразно)

Тюнинг

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

Рассмотрим несколько вариантов решения этой задачи.

  • Брутфорс (sklearn.model_selection.GridSearchCV). Несмотря на полный перебор, этот метод может быть достаточно эффективным. XGBoost модели я тюнил именно им. А вот тут хороший гайд, как можно это сделать и не ждать несколько суток. Метод хорош еще и тем, что для экономии времени заставляет получше разобраться в значении гипер-параметров.
  • Рандомизированный перебор (sklearn.model_selection.RandomizedSearchCV). В качестве плюсов можно отметить, что можно задавать количество подборов независимо от количества параметров.
  • hyperopt. Позволяет подбирать сразу много гипер-параметров, в том числе и для нейронных сетей с разным количество слоев, что особенно удобно если нужно найти конфигурацию, от которой будешь потом отталкиваться.
  • Дифференциальная эволюция.
  • Ручная подгонка и т.д.

Кстати, если для кросс-валидации вы используете метод cros_val_score библиотеки Scikit Learn, то стоит обратить внимание, что некоторые алгоритмы могут принимать в свой метод fit метрику, которую они будут минимизировать при обучении. И для того чтобы задать этот параметр при кросс-валидации, нужно использовать fit_params .

UPD: eval_metric параметр в библиотеках xgboost и LightGBM задает метрику, которой оценивается eval_set для early stopping. Другими словами, в fit метод передается набор данных, на котором модель оценивается с помощью eval_metric на каждом шаге градиентного бустинга, в случае когда early_stopping_rounds шагов подряд оценка для eval_set не улучшается, то обучение останавливается.

clf = xgb.XGBClassifier(seed=2707) kf = StratifiedKFold(random_state=2707, n_splits=5, shuffle=True) scores = cross_val_score(clf, X_train, y_train, cv=kf, scoring='neg_log_loss', fit_params=)

Калибровка (привет Гарусу!)

Идея калибровки состоит в том, что если модель дает предсказание принадлежности к классу 0,6, то среди всех семплов, которым она дала это предсказание 60% действительно принадлежат этому классу. В Scikit Learn библиотека содержит для этого sklearn.calibration.CalibratedClassifierCV класс. Это может улучшить оценку, но надо помнить, что для калибровки используется механизм кросс-валидации, а значит, это сильно увеличит время обучения.

from sklearn.ensemble import RandomForestClassifier from sklearn.calibration import CalibratedClassifierCV kf = StratifiedKFold(random_state=2707, n_splits=5, shuffle=True) clf = RandomForestClassifier(random_state=2707) scores = cross_val_score(clf, X_train, y_train, cv=kf, scoring="neg_log_loss") print("CV scores:", -scores) print("mean:", -np.mean(scores)) clf = CalibratedClassifierCV(clf,method='sigmoid', cv=StratifiedKFold(random_state=42, n_splits=5, shuffle=True)) scores = cross_val_score(clf, X_train, y_train, cv=kf, scoring="neg_log_loss") print("CV scores:", -scores) print("mean:", -np.mean(scores)) CV scores: [ 1.12679227 1.01914874 1.24362513 0.97109882 1.07280166] mean: 1.08669332288 CV scores: [ 0.41028741 0.4055759 0.4134125 0.40244068 0.39892905] mean: 0.406129108769 

Bagging

Идея заключается в том, чтобы запускать один и тот же алгоритм на разных (не полных) наборах обучающих семплов и признаков и затем использовать среднее предсказание таких моделей. Как и всегда Scikit Learn уже содержит все, что нам нужно, что сильно экономит наше время, достаточно просто использовать sklearn.ensemble.BaggingClassifier класс.

from sklearn.ensemble import RandomForestClassifier, BaggingClassifier ​ kf = StratifiedKFold(random_state=2707, n_splits=5, shuffle=True) clf = RandomForestClassifier(random_state=2707) ​ scores = cross_val_score(clf, X_train, y_train, cv=kf, scoring="neg_log_loss") print("CV scores:", -scores) print("mean:", -np.mean(scores)) ​ clf = BaggingClassifier(clf, random_state=42) scores = cross_val_score(clf, X_train, y_train, cv=kf, scoring="neg_log_loss") print("CV scores:", -scores) print("mean:", -np.mean(scores)) CV scores: [ 1.12679227 1.01914874 1.24362513 0.97109882 1.07280166] mean: 1.08669332288 CV scores: [ 0.51778172 0.46840953 0.52678512 0.5137191 0.52285478] mean: 0.509910050424

Разумеется, никто не запрещает использовать это совместно с калибровкой.

Составные модели

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

Самая лучшая моя модель как раз использовала такой принцип. Делил я на две группы: те, кто начал играть в течении 2-х недель, и те, кто начал раньше. Причем в первую группу я добавил еще и тех, кто на момент начала логирования был 1го уровня, т.к. это улучшало общую оценку. В качестве моделей я взял xgboost с разными гипер-параметрами и использовал для них разные наборы признаков. Причем при обучении второй модели я использовал все данные, но для пользователей, начавших играть раньше, чем 2 недели назад, я давал вес равный 3.

Грязные приемчики

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

Больше данных!

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

  • Перемножение или деление друг на друга существующих признаков — простой, но действенный способ.
  • Извлечение новых признаков. Например, день недели из даты, количество символов из текста и т.д.
  • Нелинейная трансформация существующего признака позволяет приблизить распределение величины к нормальной, что в некоторых случаях (те же нейронные сети) дает лучший результат. Примеры: log(x), log(x+1), sqrt(x), sqrt(x+1) и т.д.
  • Другое. Все, на что у вас хватит фантазии: максимальная степень двойки, на которую делится число, разница в возрасте с президентом и т.д. Один из сгенерированных мной признаков, который использовался в финальных моделях, считался по формуле:
raw_data['totalScore'] / (1 + np.log(1+raw_data['maxPlayerLevel']) * raw_data['maxPlayerLevel'])

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

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

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

Пример

import matplotlib.pyplot as plt import xgboost as xgb from xgboost import plot_importance clf = xgb.XGBClassifier(seed=2707) clf.fit(X_train, y_train, eval_metric='logloss') for a, b in sorted(zip(clf.feature_importances_, X_train.columns)): print(a,b, sep='\t\t') plot_importance(clf) plt.show()
0.014771 numberOfAttemptedLevels 0.014771 totalStarsCount 0.0221566 totalBonusScore 0.0295421 doReturnOnLowerLevels 0.0354505 fractionOfUsefullBoosters 0.0531758 attemptsOnTheHighestLevel 0.0886263 numberOfBoostersUsed 0.118168 totalScore 0.128508 averageNumOfTurnsPerCompletedLevel 0.144756 maxPlayerLevel 0.172821 numberOfDaysActuallyPlayed 0.177253 totalNumOfAttempts

image

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

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

Работа над ошибками

Банально, но правда

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

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

В случае, если вы застряли на мертвой точке:

  • помните про локальный минимум: возможно, какая-то идея сначала даст результат хуже текущего, но ее дальнейшее развитие или сочетание с другой идей будут вашей “киллер фичей”;
  • почти всегда можно найти научные работы по теме задания, что может натолкнуть на мысли;
  • изучите решения участников других чемпионатов (kaggle);
  • пробуйте разные модели или еще больше генерации признаков.

Больше моделей!

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

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

Второй подход — стекинг. Вот тут можно поесть овса… Идея простая: использовать предсказания моделей первого уровня как входные данные для другого алгоритма. Иногда к этим предсказаниям добавляют первоначальные данные или результаты моделей первого уровня используют для генерации новых признаков. Подвох заключается в том, что для обучения модели второго уровня (еще их называют мета-моделями), необходимы предсказания для обучающей выборки. Для их получения есть два основных подхода: holdout set и out-of-fold predictions.

Holdout set — это небольшой (~10%) кусок обучающей выборки, для которого получают предсказания моделей первого уровня, предварительно обучив их на оставшихся данных. Это простой способ, однако модель второго уровня обучается на очень маленькой выборке.

OOF predictions — обучающую выборку делят на K фолдов и поочередно считают предсказания для каждого фолда, обучая модели на K-1 оставшихся. Таким образом получается полная обучающая выборка для второго уровня. С тестовой выборкой же можно обойтись двумя способами: сделать предсказания, обучив на всей обучающей выборке (Variant В на рисунке), либо делать предсказания для тестовой выборки каждый раз, когда обучаем модели первого уровня на К-1 фолде, а после брать среднее этих предсказаний (Variant A).

image

Пример

def get_oof(clf): oof_train = np.zeros((X_train.shape[0],)) oof_test = np.zeros((X_test.shape[0],)) oof_test_skf = np.empty((NFOLDS, X_test.shape[0])) for i, (train_index, test_index) in enumerate(kf.split(X_train, y_train)): x_tr = X_train[train_index] y_tr = y_train[train_index] x_te = X_train[test_index] clf.train(x_tr, y_tr) oof_train[test_index] = clf.predict_proba(x_te)[:, 1] oof_test_skf[i, :] = clf.predict_proba(X_test)[:, 1] oof_test[:] = oof_test_skf.mean(axis=0) return oof_train.reshape(-1, 1), oof_test.reshape(-1, 1)

Пытаясь разобраться в этом способе? я натыкался на предупреждения, что метод может приводить к утечке данных (data leak), а затем и к переобучению на обучающей выборке, но доказательств этому не нашел. Я испытывал ухудшения публичной оценки при улучшении локальной, но, как оказалось, скрытая оценка все же улучшалась.

Хинт 1: OOF predictions можно совместить с подсчетом оценки и тем самым за один раз посчитать предсказания и получить оценку кросс-валидации.

Хинт 2: если механизм разбиения на фолды всегда одинаковый и K~=10, то всегда можно взять только 1 фолд и использовать его как holdout set.

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

Don’t Repeat Yourself

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

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

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

Итоги

Это был очень интересный опыт для меня. Кроме новых знаний я получил много положительных эмоций от общения с другими участниками в официальном telegram канале. Что касается результатов, то от призового 6 места меня отделял 8 знак после запятой и даже страница результатов не смогла показать это различие.

Код с финальным решением можно посмотреть на GitHub.

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

Спасибо за внимание, у меня все.

  • machine learning
  • ml boot camp

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 >> 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.

A 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_', 'test_', 'test_', '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 = >>> 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 не является подходящей мерой ошибки обобщения.

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

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

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

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

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

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

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

  • http://www.faqs.org/faqs/ai-faq/neural-nets/part3/section-12.html ;
  • Т. Хасти, Р. Тибширани, Дж. Фридман, Элементы статистического обучения , Springer 2009 г.
  • Л. Брейман, П. Спектор Выбор подмодели и оценка в регрессии: случай X , Международный статистический обзор 1992;
  • Р. Кохави, Исследование перекрестной проверки и начальной загрузки для оценки точности и выбора модели , Intl. Jnt. Конф. AI
  • Р. Бхарат Рао, Г. Фунг, Р. Росалес, Об опасностях перекрестной проверки. Экспериментальная оценка , SIAM 2008;
  • Дж. Джеймс, Д. Виттен, Т. Хасти, Р. Тибширани, Введение в статистическое обучение , Springer 2013.

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

LeavePOut очень похож на то, LeaveOneOut как он создает все возможные наборы для обучения / тестирования, удаляяpобразцы из комплекта. Дляn образцы, это производит $$ пары поезд-тест. В отличие от 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 моделям. Следовательно, его можно обрабатывать только с небольшими наборами данных, для которых подгонка отдельной модели выполняется очень быстро.

  • Охала и Гаррига. Перестановочные тесты для изучения производительности классификатора . J. Mach. Учить. Res. 2010 г.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *