Для чего нужны валидационная выборка и методы кросс валидации
Кросс-валидация
Кросс-валидация или скользящий контроль — процедура эмпирического оценивания обобщающей способности алгоритмов. С помощью кросс-валидации эмулируется наличие тестовой выборки, которая не участвует в обучении, но для которой известны правильные ответы.
Содержание
Определения и обозначения [ править ]
Пусть [math] X [/math] — множество признаков, описывающих объекты, а [math] Y [/math] — конечное множество меток.
[math]T^l = <(x_i, y_i)>_^
[math]Q[/math] — мера качества,
[math]\mu: (X \times Y)^l \to A, [/math] — алгоритм обучения.
Разновидности кросс-валидации [ править ]
Валидация на отложенных данных (Hold-Out Validation) [ править ]
Обучающая выборка один раз случайным образом разбивается на две части [math] T^l = T^t \cup T^
После чего решается задача оптимизации:
Метод Hold-out применяется в случаях больших датасетов, т.к. требует меньше вычислительных мощностей по сравнению с другими методами кросс-валидации. Недостатком метода является то, что оценка существенно зависит от разбиения, тогда как желательно, чтобы она характеризовала только алгоритм обучения.
Полная кросс-валидация (Complete cross-validation) [ править ]
Здесь число разбиений [math]C_l^
k-fold кросс-валидация [ править ]
Каждая из [math]k[/math] частей единожды используется для тестирования. Как правило, [math]k = 10[/math] (5 в случае малого размера выборки).
t×k-fold кросс-валидация [ править ]
Кросс-валидация по отдельным объектам (Leave-One-Out) [ править ]
Выборка разбивается на [math]l-1[/math] и 1 объект [math]l[/math] раз.
Преимущества LOO в том, что каждый объект ровно один раз участвует в контроле, а длина обучающих подвыборок лишь на единицу меньше длины полной выборки.
Недостатком LOO является большая ресурсоёмкость, так как обучаться приходится [math]L[/math] раз. Некоторые методы обучения позволяют достаточно быстро перенастраивать внутренние параметры алгоритма при замене одного обучающего объекта другим. В этих случаях вычисление LOO удаётся заметно ускорить.
Случайные разбиения (Random subsampling) [ править ]
Выборка разбивается в случайной пропорции. Процедура повторяется несколько раз.
Критерий целостности модели (Model consistency criterion) [ править ]
Не переобученый алгоритм должен показывать одинаковую эффективность на каждой части.
Перекрёстная проверка (кросс-валидация, Cross-validation) — метод оценки аналитической модели и её поведения на независимых данных. При оценке модели имеющиеся в наличии данные разбиваются на k частей. Затем на k−1 частях данных производится обучение модели, а оставшаяся часть данных используется для тестирования. Процедура повторяется k раз; в итоге каждая из k частей данных используется для тестирования. В результате получается оценка эффективности выбранной модели с наиболее равномерным использованием имеющихся данных.
Обычно кросс-валидация используется в ситуациях, где целью является предсказание, и хотелось бы оценить, насколько предсказывающая модель способна работать на практике. Один цикл кросс-валидации включает разбиение набора данных на части, затем построение модели на одной части (называемой тренировочным набором), и валидация модели на другой части (называемой тестовым набором). Чтобы уменьшить разброс результатов, разные циклы кросс-валидации проводятся на разных разбиениях, а результаты валидации усредняются по всем циклам.
Кросс-валидация важна для защиты от гипотез, навязанных данными («ошибки третьего рода»), особенно когда получение дополнительных данных затруднительно или невозможно.
Предположим, у нас есть модель с одним или несколькими неизвестными параметрами, и набор данных, на котором эта модель может быть оптимизирована (тренировочный набор). Процесс подгонки оптимизирует параметры модели и делает модель настолько подходящей под тренировочный набор, насколько это возможно. Если мы теперь возьмем независимый образец данных для валидации модели из того же источника, откуда мы взяли тренировочный набор данных, обычно обнаруживается, что модель описывает тестовые данные хуже, чем тренировочный набор. Это называется переподгонкой (overfitting), и особенно часто встречается в ситуациях, когда размер тренировочного набора невелик, или когда число параметров в модели велико. Кросс-валидация это способ оценить способность модели работать на гипотетическом тестовом наборе, когда такой набор в явном виде получить невозможно.
Распространенные типы кросс-валидации
Кросс-валидация по K блокам (K-fold cross-validation)
В этом случае исходый набор данных разбивается на K одинаковых по размеру блока. Из K блоков один оставляется для тестирования модели, а остающиеся K-1 блока используются как тренировочный набор. Процесс повторяется K раз, и каждый из блоков используется один раз как тестовый набор. Получаются K результатов, по одному на каждый блок, они усредняются или комбинируются каким-либо другим способом, и дают одну оценку. Преимущество такого способа перед случайным сэмплированием (random subsampling) в том, что все наблюдения используются и для тренировки, и для тестирования модели, и каждое наблюдение используется для тестирования в точности один раз. Часто используется кросс-валидация на 10 блоках, но каких-то определенных рекомендаций по выбору числа блоков нет.
В послойной кросс-валидации блоки выбираются таким образом, что среднее значение ответа модели примерно равно по всем блокам.
Валидация последовательным случайным сэмплированием (random subsampling)
Этот метод случайным образом разбивает набор данных на тренировочный и тестовый наборы. Для каждого такого разбиения, модель подгоняется под тренировочные данные, а точность предсказания оценивается на тестовом наборе. Результаты затем усредняются по всем разбиениям. Преимущество такого метода перед кросс-валидацией на K блоках в том, что пропорции тренировочного и тестового наборов не зависят от числа повторений (блоков). Недостаток метода в том, что некоторые наблюдения могут ни разу не попасть в тестовый набор, тогда как другие могут попасть в него более, чем один раз. Другими словами, тестовые наборы могут перекрываться. Кроме того, поскольку разбиения проводятся случайно, результаты будут отличаться в случае повторного анализа.
В послойном варианте этого метода, случайные выборки генерируются таким способом, при котором средний ответ модели равен по тренировочному и тестовому наборам. Это особенно полезно, когда ответ модели бинарен, с неравными пропорциями ответов по данным.
Поэлементная кросс-валидация (Leave-one-out, LOO)
Здесь отдельное наблюдение используется в качестве тестового набора данных, а остальные наблюдения из исходного набора – в качестве тренировочного. Цикл повторяется, пока каждое наблюдение не будет использовано один раз в качестве тестового. Это то же самое, что и K-блочная кросс-валидация, где K равно числу наблюдений в исходном наборе данных.
Оценка соответствия модели
Цель кросс-валидации в том, чтобы оценить ожидаемый уровень соответствия модели данным, независимым от тех данных, на которых модель тренировалась. Она может использоваться для оценки любой количественной меры соответствия, подходящей для данных и модели. Например, для задачи бинарной классификации, каждый случай в тестовом наборе будет предсказан правильно или неправильно. В этой ситуации коэффициент ошибки может быть использован в качестве оценки соответствия, хотя могут использоваться и другие оценки. Если предсказываемое значение распределено непрерывно, для оценки соответствия может использоваться среднеквадратичная ошибка, корень из среднеквадратичной ошибки или медианное абсолютное отклонение.
Применения кросс-валидации
Кросс-валидация может использоваться для сравнения результатов различных процедур предсказывающего моделирования. Например, предположим, что мы интересуемся оптическим распознаванием символов, и рассматриваем варианты использования либо поддерживающих векторов (Support Vector Machines, SVM), либо k ближайших соседей (k nearest neighbors, KNN). С помощью кросс-валидации мы могли бы объективно сравнить эти два метода в терминах относительных коэффициентов их ошибок классификаций. Если мы будем просто сравнивать эти методы по их ошибкам на тренировочной выборке, KNN скорее всего покажет себя лучше, поскольку он более гибок и следовательно более склонен к переподгонке по сравнению с SVM.
Кросс-валидация также может использоваться для выбора параметров. Предположим, у нас есть 20 параметров, которые мы могли бы использовать в модели. Задача – выбрать параметры, использование которых даст модель с лучшими предсказывающими способностями. Если мы будем сравнивать подмножества параметров по их ошибкам на тестовом наборе, лучшие результаты получатся при использовании всех параметров. Однако с кросс-валидацией, модель с лучшей способностью к обобщению обычно включает только некоторое подмножество параметров, которые достаточно информативны.
Вопросы вычислительной производительности
Ограничения и неверное использование кросс-валидации
Кросс-валидация дает значимые результаты только когда тренировочный набор данных и тестовый набор данных берутся из одного источника, из одной популяции. В многих применениях предсказательных моделей структура изучаемой системы меняется со временем. Это может наводить систематические отклонения тренировочного и валидационного наборов данных. К примеру, если модель для предсказания цены акции тренируется на данных из определенного пятилетнего периода, нереалистично рассматривать последующий пятилетний период как выборку из той же самой популяции.
Если выполняется правильно, и наборы данных из одной популяции, кросс-валидация дает результат практически без смещений (bias). Однако, есть много способов использовать кросс-валидацию неправильно. В этом случае ошибка предсказания на реальном валидационном наборе данных скорее всего будет намного хуже, чем ожидается по результатам кросс-валидации.
Способы неверно использовать кросс-валидацию:
1. Использовать кросс-валидацию на нескольких моделях, и взять только результаты лучшей модели.
2. Проводить начальный анализ для определения наиболее информативного набора параметров, используя полный набор данных. Если отбор параметров требуется в модели предсказания, он должен проводиться последовательно на каждом тренировочном наборе данных. Если кросс-валидация используется для определения набора используемых моделью параметров, на каждом тренировочном наборе должна проводиться внутренняя кросс-валидация для определения набора параметров.
3. Позволять некоторым тренировочным данным попадать также и в тестовый набор – это может случиться из-за существования дублирующих наблюдений в исходном наборе.
Валидационные данные (Validation Data)
Валидационные данные (Validation Data, Holdout Data – «удержанные» данные) – это часть Датасета (Dataset), основа для проверки работоспособности Модели (Model) Машинного обучения (ML). Является одной из составляющих разделенного набора данных наряду с Тренировочными (Train Data) и Тестовыми (Test Data) данными.
Типы разделений датасета
Пример. Мы создаем модель, предсказывающую потребление электроэнергии в городе. Если на тренировочных данных она, подобно человеческому мозгу, учится видеть скачки потребления электричества, то на тестовой Дата-сайентист (Data Scientist) проверяет качество обучения. Но зачем же нужна валидационная часть?
Когда модель пытается улучшиться, она подыскивает оптимальные значения Гиперпараметров (Hyperparameter). В этом случае существует вероятность Переобучения (Overfitting): модель слишком подробно учитывает особенности информации, на которой обучилась, и при переходе на другие реальные данные будет малоэффективна. Чтобы решить эту проблему, мы можем создать дополнительную валидационную часть датасета, и проверять качество модели на любом подходящем этапе разработки.
В основе всех методов проверки лежит разделение данных при обучении модели. Принцип прост: мы случайным образом разбиваем данные в пропорции 70 : 30, причем большая часть отводится тренировочным данным, а меньшая – тестовым. Но что если в одно подмножество тренировочных данных попали энергопотребители только определенного возраста или уровня дохода? Эта систематическая ошибка называется Смещением выборки (Sampling Bias). В результате неслучайной Выборки (Sampling) из Генеральной совокупности (Population) вероятность включения одних типов Наблюдений (Observation) в выборку ниже, чем у других, что приводит к искаженному восприятию реальности моделью.
Виды валидации
Выделяют следующие методы проверки:
Посмотрим, как работает одна из этих техник.
k-блочная кросс-валидация
Чтобы свести к минимуму систематическую ошибку выборки, мы изменим формат разделения данных Вместо того, чтобы делать одно разбиение на тренировочную и тестовую части, мы сделаем их много и проверим модель на каждой комбинации:
Преимущество заключается в том, что все наблюдения используются как для обучения, так и для проверки, а каждое наблюдение используется один раз для проверки. Обычно мы разбиваем датасет на 5 или 10 частей: это обеспечивает баланс между вычислительной сложностью и точностью.
k-блочная кросс-валидация и Scikit-learn
Продемонстрируем, как реализована такая валидация в библиотеке Scikit-learn. Для начала импортируем необходимые библиотеки:
Создадим игрушечный размеченный датасет, где X – матрица 4 х 2, состоящая из Переменных-предикторов (Predictor Variable), а y – Целевая переменная (Target Variable), классы, к которым принадлежит то или иное наблюдение:
Применим k-блочную кросс-валидацию в две итерации:
Выведем индексы тренировочных и тестовых данных для каждой из двух итераций:
Поскольку датасет скромный, то вариантов разбиений немного: то в тестовую часть попадают 2-й и 3-й наблюдения, то 0-й и 1-й.
Использование полного объема данных – это хорошо для модели, потому такая валидация улучшает предсказательную способность модели.
Ноутбук, не требующий дополнительной настройки на момент написания статьи, можно скачать здесь.
Кросс-валидация (Cross-validation)
Кросс-валидация, которую иногда называют перекрестной проверкой, это техника валидации модели для проверки того, насколько успешно применяемый в модели статистический анализ способен работать на независимом наборе данных. Обычно кросс-валидация используется в ситуациях, где целью является предсказание, и хотелось бы оценить, насколько предсказывающая модель способна работать на практике. Один цикл кросс-валидации включает разбиение набора данных на части, затем построение модели на одной части (называемой тренировочным набором), и валидация модели на другой части (называемой тестовым набором). Чтобы уменьшить разброс результатов, разные циклы кросс-валидации проводятся на разных разбиениях, а результаты валидации усредняются по всем циклам.
Кросс-валидация важна для защиты от гипотез, навязанных данными («ошибки третьего рода»), особенно когда получение дополнительных данных затруднительно или невозможно.
Предположим, у нас есть модель с одним или несколькими неизвестными параметрами, и набор данных, на котором эта модель может быть оптимизирована (тренировочный набор). Процесс подгонки оптимизирует параметры модели и делает модель настолько подходящей под тренировочный набор, насколько это возможно. Если мы теперь возьмем независимый образец данных для валидации модели из того же источника, откуда мы взяли тренировочный набор данных, обычно обнаруживается, что модель описывает тестовые данные хуже, чем тренировочный набор. Это называется переподгонкой (overfitting), и особенно часто встречается в ситуациях, когда размер тренировочного набора невелик, или когда число параметров в модели велико. Кросс-валидация это способ оценить способность модели работать на гипотетическом тестовом наборе, когда такой набор в явном виде получить невозможно.
Распространенные типы кросс-валидации
Кросс-валидация по K блокам (K-fold cross-validation)
В этом случае исходый набор данных разбивается на K одинаковых по размеру блока. Из K блоков один оставляется для тестирования модели, а остающиеся K-1 блока используются как тренировочный набор. Процесс повторяется K раз, и каждый из блоков используется один раз как тестовый набор. Получаются K результатов, по одному на каждый блок, они усредняются или комбинируются каким-либо другим способом, и дают одну оценку. Преимущество такого способа перед случайным сэмплированием (random subsampling) в том, что все наблюдения используются и для тренировки, и для тестирования модели, и каждое наблюдение используется для тестирования в точности один раз. Часто используется кросс-валидация на 10 блоках, но каких-то определенных рекомендаций по выбору числа блоков нет.
В послойной кросс-валидации блоки выбираются таким образом, что среднее значение ответа модели примерно равно по всем блокам.
Валидация последовательным случайным сэмплированием (random subsampling)
Этот метод случайным образом разбивает набор данных на тренировочный и тестовый наборы. Для каждого такого разбиения, модель подгоняется под тренировочные данные, а точность предсказания оценивается на тестовом наборе. Результаты затем усредняются по всем разбиениям. Преимущество такого метода перед кросс-валидацией на K блоках в том, что пропорции тренировочного и тестового наборов не зависят от числа повторений (блоков). Недостаток метода в том, что некоторые наблюдения могут ни разу не попасть в тестовый набор, тогда как другие могут попасть в него более, чем один раз. Другими словами, тестовые наборы могут перекрываться. Кроме того, поскольку разбиения проводятся случайно, результаты будут отличаться в случае повторного анализа.
В послойном варианте этого метода, случайные выборки генерируются таким способом, при котором средний ответ модели равен по тренировочному и тестовому наборам. Это особенно полезно, когда ответ модели бинарен, с неравными пропорциями ответов по данным.
Поэлементная кросс-валидация (Leave-one-out, LOO)
Здесь отдельное наблюдение используется в качестве тестового набора данных, а остальные наблюдения из исходного набора – в качестве тренировочного. Цикл повторяется, пока каждое наблюдение не будет использовано один раз в качестве тестового. Это то же самое, что и K-блочная кросс-валидация, где K равно числу наблюдений в исходном наборе данных.
Оценка соответствия модели
Цель кросс-валидации в том, чтобы оценить ожидаемый уровень соответствия модели данным, независимым от тех данных, на которых модель тренировалась. Она может использоваться для оценки любой количественной меры соответствия, подходящей для данных и модели. Например, для задачи бинарной классификации, каждый случай в тестовом наборе будет предсказан правильно или неправильно. В этой ситуации коэффициент ошибки может быть использован в качестве оценки соответствия, хотя могут использоваться и другие оценки. Если предсказываемое значение распределено непрерывно, для оценки соответствия может использоваться среднеквадратичная ошибка, корень из среднеквадратичной ошибки или медианное абсолютное отклонение.
Применения
Кросс-валидация может использоваться для сравнения результатов различных процедур предсказывающего моделирования. Например, предположим, что мы интересуемся оптическим распознаванием символов, и рассматриваем варианты использования либо поддерживающих векторов (Support Vector Machines, SVM), либо k ближайших соседей (k nearest neighbors, KNN). С помощью кросс-валидации мы могли бы объективно сравнить эти два метода в терминах относительных коэффициентов их ошибок классификаций. Если мы будем просто сравнивать эти методы по их ошибкам на тренировочной выборке, KNN скорее всего покажет себя лучше, поскольку он более гибок и следовательно более склонен к переподгонке по сравнению с SVM.
Кросс-валидация также может использоваться для выбора параметров. Предположим, у нас есть 20 параметров, которые мы могли бы использовать в модели. Задача – выбрать параметры, использование которых даст модель с лучшими предсказывающими способностями. Если мы будем сравнивать подмножества параметров по их ошибкам на тестовом наборе, лучшие результаты получатся при использовании всех параметров. Однако с кросс-валидацией, модель с лучшей способностью к обобщению обычно включает только некоторое подмножество параметров, которые достаточно информативны.
Вопросы вычислительной производительности
Ограничения и неверное использование кросс-валидации
Кросс-валидация дает значимые результаты только когда тренировочный набор данных и тестовый набор данных берутся из одного источника, из одной популяции. В многих применениях предсказательных моделей структура изучаемой системы меняется со временем. Это может наводить систематические отклонения тренировочного и валидационного наборов данных. К примеру, если модель для предсказания цены акции тренируется на данных из определенного пятилетнего периода, нереалистично рассматривать последующий пятилетний период как выборку из той же самой популяции.
Если выполняется правильно, и наборы данных из одной популяции, кросс-валидация дает результат практически без смещений (bias). Однако, есть много способов использовать кросс-валидацию неправильно. В этом случае ошибка предсказания на реальном валидационном наборе данных скорее всего будет намного хуже, чем ожидается по результатам кросс-валидации.
Способы неверно использовать кросс-валидацию:
1. Использовать кросс-валидацию на нескольких моделях, и взять только результаты лучшей модели.
2. Проводить начальный анализ для определения наиболее информативного набора параметров, используя полный набор данных. Если отбор параметров требуется в модели предсказания, он должен проводиться последовательно на каждом тренировочном наборе данных. Если кросс-валидация используется для определения набора используемых моделью параметров, на каждом тренировочном наборе должна проводиться внутренняя кросс-валидация для определения набора параметров.
3. Позволять некоторым тренировочным данным попадать также и в тестовый набор – это может случиться из-за существования дублирующих наблюдений в исходном наборе.
Другие статьи по теме:
Yaroslav Efremov: Как-то не согласуются две фразы
1) Кросс-валидация может использоваться для сравнения результатов различных процедур предсказывающего моделирования.
2) Способы неверно использовать кросс-валидацию:
Использовать кросс-валидацию на нескольких моделях, и взять только результаты лучшей модели.
Почему нельзя за счет кросс-валидации выбрать модель? Пока вижу один минус, что если мы выбираем из тысячи похожих моделей, то скорее всего выберем ту, которая покажет лучшие результаты на кросс-валидации, а это будет ручная подгонка. Но если есть скажем 4 модели и их результаты отличаются в разы на валидационной выборки, то выбор оправдан…
mehanizator: во второй фразе говорится о результатах, а не о модели. для выбора модели использовать кросс-валидацию — это ок. ошибка когда каждый раз гоняются несколько моделей и берутся лучшие результаты.
Kaggle Mercedes и кросс-валидация
Всем привет, в этом посте я расскажу о том, как мне удалось занять 11 место в конкурсе от компании Мерседес на kaggle, который можно охарактеризовать как лидера по количеству участников и по эпичности shake-up. Здесь можно ознакомиться с моим решением, там же ссылка на github, здесь можно посмотреть презентацию моего решения в Yandex.
В этом посте пойдет речь о том, как студент консерватории попал в data science, стал призером двух подряд kaggle-соревнований, и каким образом методы математической статистики помогают не переобучиться на публичный лидерборд.
Начну я с того, что немного расскажу о задаче и о том, почему я взялся ее решать. Должен сказать, что в data science я человек новый. Лет 7 назад я закончил Физический Факультет СПбГУ и с тех пор занимался тем, что получал музыкальное образование. Идея немного размять мозг и вернуться к техническим задачам впервые посетила меня примерно два года назад, на тот момент я уже работал в оркестре Московской Филармонии и учился на 3 курсе в Консерватории. Начал я с того, что вооружившись книгой Страуструпа стал осваивать C++. Далее были конечно же разные онлайн курсы и примерно год назад я стал склоняться к мысли о том, что Data Science — это пожалуй именно то, чем я хотел бы заниматься в IT. Мое “образование” в Data Science — это курс от Яндекса и Вышки на курсере, несколько курсов из специализации МФТИ на курсере и конечно же постоянное саморазвитие в соревнованиях.
Свою первую медальку kaggle я получил в соревновании от Сбербанка — я занял там 13 из 3000+ место, здесь решение Сбербанка со ссылкой на github. И сразу после этого я решил вписаться в соревнование от Мерседеса, до окончания которого оставалось 10 дней. Это были очень тяжелые 10 дней моего отпуска, но, во-первых, я открыл для себя много нового, во-вторых, я получил в итоге еще одну золотую медальку. И в этом посте я бы хотел поделиться тем, что я почерпнул, решая эту задачу.
Постановка задачи
Теперь, когда общий план понятен, самое время переходить к деталям. Здесь бы я хотел сразу оговориться, что далее по тексту я не буду обсуждать тонкости ансамблирования алгоритмов или какие-то нетривиальные хитрости градиентного бустинга. Речь пойдет в основном о том, как валидироваться, чтобы не расстраиваться при открытии private leaderboard. Если отбросить все художественные подробности, мы имеем обычную задачу регрессии на анонимизированных фичах. Особенность этого конкурса состояла в маленьком (по меркам kaggle) датасете (трейн и тест примерно по 4000 объектов) и в весьма шумном таргете (боксплот таргета ниже).
Из боксплота становится очевидно, что мы столкнемся с трудностями при валидаци. Можно предположить, что на кросс-валидации нас ждет здоровенный разброс метрики по фолдам. И чтобы подлить масла в огонь, я уточню, что метрика соревнования — коэффициент детерминации (R2), который, как известно, очень чувствителен к выбросам.
Задачка привлекла столько участников прежде всего тем, что бейзлайн пишется в несколько строчек. Сделаем такой бейзлайн и посмотрим на результаты кросс-валидации:
Вывод будет примерно таким:
Стандартное отклонение по фолдам настолько велико, что сравнение средних теряет смысл (в подавляющем большинстве случаев средние будут отличаться менее чем на стандартное отклонение).
Все, что будет дальше, состоит из двух частей. Первая часть простая и приятная, вызвавшая живой интерес на тренировке в Яндексе. В ней я расскажу почему большое std (Standard Deviation) – не помеха для кросс-валидации и покажу красивый и несложный подход, ликвидирующий влияние этого std. Вторая часть более сложная, но, на мой взгляд, и значительно более важная. В ней я расскажу о том, почему это не панацея, как кросс-валидация может ввести нас в заблуждение, чего имеет смысл ожидать от кросс-валидации и как к ней относиться. Итак, поехали.
Сравнение моделей на шумных данных
Для чего вообще нам нужна кросс-валидация? Когда мы решаем задачку, мы пробуем огромное количество разных моделей и хотим найти лучшую или лучшие. Таким образом, нам нужен способ сравнить две модели и достоверно выбрать из этой пары победителя. Именно в этом мы и просим помощи у кросс-валидации. Я оговорюсь, что под моделью я понимаю не просто какой-то алгоритм машинного обучения, а весь пайплайн, включающий в себя предобработку данных, отбор признаков, создание новых признаков, выбор алгоритма и его гиперпараметров. Любой из этих шагов является по сути гиперпараметром нашей модели, и мы хотим найти лучшие гиперпараметры для нашей задачи. А для этого необходимо уметь сравнивать две разные модели. Попробуем решить эту задачу.
Напомню, что значение функции потерь по фолдам кросс-валидации в задаче Мерседеса катастрофически непостоянное. Поэтому, просто сравнивая средний скор двух моделей на кросс-валидации, мы никаких выводов сделать не сможем (отличия будут в пределах погрешности). Я использовал такой подход:
1. Сделаем не одно разбиение на 5 фолдов, а 10. Теперь у нас есть 50 фолдов, но размер фолда остался прежним. В массиве scores мы получим 50 скоров на пятидесяти тестовых фолдах:
2. Будем сравнивать не средний скор моделей, а то, насколько каждая из моделей лучше или хуже другой на соответствующем фолде. Или, что то же самое, будем сравнивать с нулем среднее попарных разностей результатов двух моделей на соответствующих фолдах.
Дальше я немного формализую второй пункт, но уже сейчас нужно понять, что ура, мы больше не зависим от того, что, скажем, в первом фолде у нас аутлаер, и скор там всегда очень низкий. Теперь скор на первом фолде не усредняется с остальными, он сравнивается исключительно со скором на том же фолде второй модели. Соответственно, нам больше не мешает то, что первый фолд всегда хуже второго, поскольку мы сравниваем не скор в среднем, а скор на каждом фолде и только потом усредняем.
Теперь перейдем к оценке статистической значимости. Мы хотим ответить на вопрос: значимо ли отличаются скоры наших двух моделей на наших 50 тестовых фолдах. Скоры наших моделей представляют собой связанные выборки, и я предлагаю воспользоваться статистическим критерием, специально предназначенным для таких случаев. Это t-критерий Стьюдента для связанных выборок. Я не буду перегружать пост рассуждениями о том, что гипотеза нормальности в нашем случае выполняется с достаточной точностью, и критерий Стьюдента применим — я подробно остановился на этом на тренировке в Яндексе, при желании можно посмотреть запись. Сейчас же я сразу перейду к практической части.
Статистика t-критерия имеет следующий вид:
где – списки значений метрики по тестовым фолдам для первой и второй модели соответственно, S – дисперсия попарных разностей, n – число фолдов. Здесь я хочу оговориться, что описать процедуру проверки статистических гипотез и теорию, которая за этим стоит, я в этом посте не смогу. Не потому, что это сложно для понимания, а просто потому, что, как мне кажется, пост не совсем об этом. И еще потому, что это достаточно сложно для объяснения и, сделав этот пост длиннее на два экрана, я все равно едва ли сделаю эти вещи понятнее людям, для которых они в новинку. В первых двух неделях этого курса тема проверки статистических гипотез раскрыта исчерпывающим образом, очень рекомендую: https://www.coursera.org/learn/stats-for-data-analysis/home/welcome.
Итак, наша нулевая гипотеза состоит в том, что обе модели дают одинаковые результаты. В этом случае t-статистика распределена по Стьюденту с математическим ожиданием в 0. Соответственно, чем больше она отклоняется от 0, тем меньше вероятность того, что нулевая гипотеза выполняется, а средние в числителе дроби не совпали чисто случайно. Обратите внимание на знаменатель: S – это дисперсия попарных разностей. То есть, нас совершенно не интересует дисперсия скоров на фолдах для каждой модели в отдельности (то есть дисперсия и
), нас интересует лишь насколько «стабильно» лучше или хуже одна модель другой. Именно за это и отвечает S, находясь в знаменателе.
Интересующий нас критерий реализован в библиотеке scipy в модуле stats, это функция ttest_rel. Функция принимает на вход два списка (или массива) метрик на тестовых фолдах, а возвращает значение t-статистики и p-value для двусторонней альтернативы. Чем больше t-статистика по модулю, и чем меньше p-value, тем существеннее отличия. Наиболее распространенной практикой является считать, что отличия значимы если p-value Ttest_relResult(statistic=5.9592780076048273, pvalue=2.7039720009616195e-07)
Статистика положительна, это значит, что числитель дроби положителен и соответственно среднее больше среднего
. Вспомним, что мы максимизируем целевую метрику R2 и поймем, что первый алгоритм лучше, то есть 110 деревьев на этих данных проигрывают 100. P-value значительно меньше 0.05, поэтому мы смело отвергаем нулевую гипотезу, утверждая что модели существенно различны. Попробуйте посчитать mean() и std() для scores_100_trees и scores_110_trees и вы убедитесь, что просто сравнение средних здесь не катит (отличия будут порядка std). А между тем модели отличаются, причем отличаются очень сильно, и t-критерий Стьюдента для связанных выборок помог нам это показать.
На этом я бы закончил первую часть, но почему-то я уже представляю себе, как многие читатели, вооружившись этими знаниями, устроят большущий GridSearch, наделают тысячи массивов scores_xxx, сделают тысячи t-тестов, сравнивая это все с бейзлайном, и выберут алгоритм с наибольшей по модулю отрицательной t-статистикой (или положительной в зависимости от порядка аргументов ttest_rel). Друзья, коллеги, подождите, не делайте этого. GridSearch – это очень коварная штука. Давайте вспомним, что наша t-статистика распределена по Стьюденту. Это значит, что, во-первых, это случайная величина, во-вторых, даже в предположении отсутствия каких бы то ни было различий, она может принимать значения от минус бесконечности до бесконечности. Задумайтесь: от минус бесконечности до бесконечности для моделей, которые на самом деле будут давать на новых данных практически одинаковый скор! С другой стороны, чем больше значение t-статистики по модулю, тем меньше вероятность его получить случайно. То есть, например, вероятность того, что мы получим что-то больше 3 по модулю, меньше 0.5%. Но вы же делали GridSearch, проверяли несколько тысяч разных моделей. Очевидно, что даже если они ну вообще не отличались, хоть раз вы, скорее всего, эту тройку преодолеете. И примете неверную гипотезу.
В статистике это называется множественной проверкой, и существуют разные методы борьбы с ошибками при этой самой множественной проверке. Я предлагаю воспользоваться самым простым из них — проверять меньше гипотез и делать это очень осмысленно. Сейчас поясню, как я вижу это на практике.
Вернемся к нашему xgboost и попробуем оптимизировать количество деревьев. Во-первых, я призываю оптимизировать гиперпараметры строго по одному. Пусть у нас бейзлайн — 100 деревьев. Посмотрим, что происходит с t-статистикой при плавном уменьшении количества деревьев до 50:
То, что мы видим на графике — это хорошая ситуация. Когда у нас около 50 деревьев, ответы модели не сильно отличаются от бейзлайна со ста деревьями. При увеличении количества деревьев — отличия увеличиваются, алгоритм начинает предсказывать лучше: где-то в районе 85 мы имеем оптимум, и далее t-статистика падает, то есть алгоритм приближается к нашему бейзлайну. Посмотрев на график становится очевидно, что оптимальное количество деревьев примерно 83. А вполне можно взять 81, 82, 83, 84, 85 и усреднить. Подобного рода усреднения позволяют, практически бесплатно в смысле наших усилий, улучшить обобщающую способность и итоговый скор, я часто пользуюсь этим приемом. Я надеюсь, что из всех этих рассуждений становится понятно, что на подобных графиках нам интересен не просто глобальный оптимум, а оптимум, к которому функция плавно стремится и от которого плавно уходит. При достаточно большом количестве точек на графике мы вполне можем получить случайные всплески, которые могут быть и больше интересующего нас оптимума. Но мы отличаемся от GridSearch в том числе и тем, что будем брать не просто точку с максимальным (минимальным) значением t-статистики, а будем подходить к этому чуть более разумно.
Именно для того, чтобы была возможность смотреть на подобные графики, я призываю оптимизировать гиперпараметры по очереди. В некоторых случаях может быть оправдано перейти к 3-х мерному scatter-plot, на котором можно следить за метрикой в зависимости от двух гиперпараметров.
К сожалению, я не могу резюмировать первую часть планом вида сначала делай так, потом так, поскольку настройка гиперпараметров по кросс-валидации — дело очень тонкое и требующее постоянного анализа. Единственное, на чем я однозначно настаиваю: никогда не пытайтесь попасть в десятку — это невозможно. То, что на кросс-валидации 148 деревьев лучше, чем 149, совершенно не означает, что на тесте будет так же. Не уверены — усредняйте, потому что усреднение — это одна из очень немногих вещей, которая модель: а) точно не испортит, б) скорее всего улучшит. И осторожнее с GridSearch – этот алгоритм очень хорошо умеет создавать видимость оптимизации гиперпараметров. По меньшей мере по тем гиперпараметрам, которые вы считаете важными в данной задаче, необходимо вручную убедиться в том, что вы нашли действительно оптимальное значение, а не случайный всплеск среди белого шума.
Опасность переобучения на выбросах
Во второй части своего поста я буду рассуждать о том, что такое кросс-валидация в принципе, в чем и как она нам может помочь, а в чем не может. Предыстория такова: применив валидацию, о которой я говорил в первой части, я начал улучшать модель: что-то где-то подкручивать, отбирать фичи, добавлять новые, в общем заниматься тем, чем мы всегда занимаемся при решении kaggle. К проверке статистических гипотез я подходил очень консервативно, старался проверять их как можно меньше и как можно более разумно. Достаточно быстро я пришел к тому, что средний R2 на кросс-валидации был примерно 0.58. Как мы знаем сегодня, лучший скор на прайвате (private leaderboard) — это 0.5556. Но тогда я этого не знал, а на паблике (public leaderboard) топ был уже 0.63+, хотя и понятно было, что смотреть на чужие паблик скоры абсолютно бесполезно (leaderboard probing в этом соревновании имел небывалый масштаб). Холодный душ случился тогда, когда я сделал сабмит лучшей, по моему мнению, модели и получил на паблике 0.54, при том, что бейзлайн давал 0.55. Стало очевидно, что что-то здесь не так.
На этом моменте я бы хотел остановиться чуть подробнее. Если бы, например, это был не kaggle, а работа, я бы имел все шансы отправить такую модель в продакшн (по крайней мере попытаться это сделать). Казалось бы, что такого? У меня такая хитрая кросс-валидация, я очень аккуратно подобрал все параметры и получил высокий скор, какие могут быть вопросы? Но нужно понимать, и всегда помнить о том, о чем я тогда забыл — кросс-валидация в принципе не может оценивать перформанс модели на новых данных. На всякий случай поясню, что словом перформанс (англ. performance) я обозначаю качество работы модели в терминах выбранной метрики. Вы делаете кросс-валидацию снова и снова, выбирая только те модели, которые лучше работают на тестовых фолдах. Не на каких-то тестовых фолдах, а на совершенно конкретных и одинаковых тестовых фолдах. И даже если вы, скажем, периодически меняете random_state у Kfold, делая тем самым фолды различными, они все равно, в конечном итоге, собираются из объектов вашей обучающей выборки. И, подбирая гиперпараметры, вы натаскиваете алгоритм именно на этих объектах. Если данные хорошие, и мы все делали аккуратно, то это может привести к тому, что алгоритм будет работать чуть лучше и на новых объектах, но одинакового перформанса в общем случае ждать не стоит. А в случае, когда данные достаточно шумные, есть риск столкнуться с ситуацией, с которой столкнулся я и о которой буду рассуждать до конца поста.
Для себя я понял, что абсолютно необходимо в любой задаче иметь отложенную выборку. Я бы предложил делать так: получили задачу — сразу сделали отложенную выборку и выкинули ее из трейна. Посчитали, какой результат дает бейзлайн на этой выборке. Потом можно долго и упорно улучшать модель и наконец, когда уже самая лучшая модель готова, пришло время посмотреть скор на отложенной выборке. В случае kaggle роль отложенной выборки может играть паблик лидерборд. Но важно помнить, что чем чаще мы смотрим скор по отложенной выборке, тем хуже он оценивает перформанс модели на новых данных.
Возвращаюсь к Мерседесу. Получив на паблике скор ниже, чем у моего бейзлайна, я понял, что переобучился. Сейчас я продемонстрирую как происходит переобучение при, казалось бы, правильном подходе к подбору гиперпараметров. Для наглядности у нас будет только одна фича. Пусть истинная зависимость — синус, добавим нормальный шум и добавим нормальные же выбросы (на 15% объектов выбросы поменьше, на 4% — побольше):
Боксплот чем-то похож на то, что мы видели для таргета в задаче от Мерседеса, но выбросы присутствуют с обеих сторон.
Пусть первая тысяча объектов — это наша обучающая выборка, в вторая — тестовая. Посчитаем скоры бейзлайна на кросс-валидации:
Теперь, так же как мы делали в первой части, сравним с бейзлайном модели с меньшим количеством деревьев и посмотрим на зависимость t-статистики от n_estimators:
Получим очень красивый график, из которого сделаем вывод, что оптимально брать примерно 85 деревьев:
Но посмотрим, как себя поведут эти алгоритмы на новых данных:
С удивлением обнаруживаем, что 85 — это далеко не оптимальное количество деревьев для нашего датасета. Виноваты в этом конечно же выбросы, и именно в такую ситуацию, как мне кажется, я попал на конкурсе Мерседес. Если вы поэкспериментируете с этим кодом, то увидите, что совершенно не обязательно оптимум на трейне будет правее оптимума на тесте, но достаточно часто их x-координата не будет совпадать.
Чтобы оценить, как сильно влияют выбросы на скор, предлагаю помучить эту строчку:
Обратите внимание на то, что если мы, например, вместо 1.1 во втором массиве напишем 1.0, скор изменится в четвертом знаке. А теперь попробуем подобраться на 0.1 ближе к нашему аутлаеру — заменим 5.3 на 5.4. Скор меняется сразу на 0.015, то есть примерно в 100 раз сильнее, чем если бы мы на столько же улучшили предсказание «нормального» значения. Таким образом, скор в основном определяется не тем, насколько точно мы предсказываем «нормальные» значения, а тем, какая из моделей случайно оказалась чуть лучше на выбросах. И становится понятно, что отбирая признаки и настраивая гиперпараметры, мы непроизвольно выбираем те модели, которые чуть лучше угадывают выбросы на тестовых фолдах, а не те, которые лучше предсказывают основную массу объектов. Это происходит просто потому, что модели, угадывающие аутлаеров, получают более высокий скор, а перформанс на основной массе объектов не очень сильно влияет на скор.
В большинстве задач, я полагаю, выбросы предсказать невозможно. Это нужно проверить, и если это так, открыто это признать. А коль скоро мы не можем их предсказать, давайте и не учитывать их при сравнении моделей. Действительно, если любая из наших моделей одинаково плохо будет предсказывать выбросы на новых данных, какой смысл тогда оценивать предсказания выбросов на кросс-валидации? Есть две стратегии поведения в таких ситуациях:
1. Давайте удалим все выбросы из обучающей выборки и только после этого будем обучать и валидировать модели. О том, как именно удалять выбросы, поговорим чуть позже, пока считаем, что как-то мы это делать умеем. Такая стратегия действительно очень сильная, победитель конкурса Sberbank Russian Housing Market Евгений Патеха валидировался именно так: youtu.be/Eo4WMlcT7uo, www.kaggle.com/c/sberbank-russian-housing-market/discussion/35684. Единственная проблема этого метода состоит в том, что зачастую выкидывание аутлаеров смещает среднее предсказание, и мы вынуждены это смещение как-то компенсировать.
2. Не будем ничего удалять из обучающей выборки, но при валидации (при вычислении значения метрики на тестовых фолдах) не будем учитывать выбросы. Я использовал именно такую схему. Мою реализацию такой кросс-валидации вы можете найти в этом репозитории, функция называется cross_validation_score_statement, определена в файле cross_val_custom.py. Еще раз, все вплоть до вызова метода fit (и включая его) мы делаем, ничего не выкидывая, затем мы делаем predict на тестовых фолдах, но метрику считаем только на объектах, не являющихся выбросами.
Как я уже говорил, получив очень низкий скор на паблике, я понял, что переобучился. Когда я начал валидироваться без аутлаеров, это переобучение сразу стало очевидно. Оказалось, что я слишком агрессивно отбирал признаки, что слишком много деревьев выращивал для своих xgboost’ов. Поправить все оказалось очень легко, я потратил примерно час на то, чтобы найти новый оптимум в пространстве гиперпараметров, и засабмитил результат. Переход к валидации без аутлаеров сделал из решения 3000+ на прайвате решение на 11 место.
Покажем, как это работает на нашем игрушечном датасете. Во-первых, необходимо определиться, кого считать аутлаером. Я считал аутлаерами объекты, на которых бейзлайн ошибается сильнее всего (ошибка out-of-fold предсказания больше какого-то порога). Порог подбирается исходя из того, сколько процентов обучающей выборки вы хотите объявить аутлаерами.
Outliers fraction in train = 0.045
То есть 4.5% объектов объявляются выбросами. Теперь посчитаем скоры на кросс-валидации для бейзлайна, а затем будем менять количество деревьев. Только теперь выбросы при вычислении скора учитываться не будут.
Получим такой график:
Видно, что, к сожалению, это не серебряная пуля, и оптимум все равно находится не на 50 деревьях, как хотелось бы. Но это уже и не 85 как было раньше, и экстремум не такой явный, что наводит на мысли о том, что имеет смысл усреднить по количеству деревьев от 60 до 95. А сделав это, мы вполне возможно получим результат, сопоставимый с тем, который мы бы получили, если бы знали, что на самом деле нужно брать 50.
И последнее, что я хочу показать — это как в действительности меняются предсказания нашего бустинга при росте количества деревьев, благо в одномерном случае это можно сделать. Для разных n_estimators я буду строить предсказания алгоритма и склею это в gif:
Видим как сильно мешают аутлаеры работать нашей модели. Также видим, что после примерно n_estimators=60 модель фактически перестает приближаться с исходной функции и занимается лишь тем, что переобучается на выбросах из обучающей выборки. Вспомним, что на наших «новых» данных лучше всего показывают себя 50 деревьев. А на анимации при n_estimators=60, 70, 80 t-статистика на кросс-валидации продолжает увеличиваться, и увеличивается она именно благодаря удачному попаданию в аутлаеры. Когда я сделал эту анимацию, идея обучать модели на очищенном датасете стала мне казаться еще более привлекательной. Много чего еще можно сказать, глядя на эту гифку, но не смею вас больше задерживать.
Очень надеюсь, что вы не жалеете о потраченном на прочтение этого поста вечере времени. Эта тема сложная, неоднозначная и интересная, я буду рад вашим комментариям и возможности продолжить рассуждения, но уже не в режиме монолога.