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

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

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

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

Один класс алгоритмов, к которому не применяются многие стандартные «правила» предварительной обработки, — это древовидные модели.

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

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

Горячее кодирование — не ахти?

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

  1. Основная причина заключается в том, что древовидные алгоритмы просто не очень хорошо работают с горячим кодированием. Поскольку они работают на основе разделения, одногорячее кодирование заставляет деревья решений секвестрировать точки данных по отдельным категориальным значениям — у модели нет возможности сказать «если страна == «США» или «Великобритания», то X». Если алгоритм хочет использовать «страну», в дереве должна быть ветвь «только для США», ветвь «только для Великобритании» в дереве и так далее.
  2. Это может либо увеличить потребление памяти, либо заставить работать с разреженной матрицей.
  3. Он изменяет форму ваших данных, поэтому столбцы больше не совпадают 1:1 с исходным фреймом данных или таблицей.

Препятствие для вычисления важности функции

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

Например, вместо важности признака для «страны» у вас будет важность признака для «страна=США», еще один для «страна=Великобритания» и т. д., по которому будет сложно определить относительную важность «страны» в целом, если вы не проведете дополнительные расчеты и преобразования в дополнение к важности этой раздробленной функции.

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

Другими словами, одно горячее кодирование создает один беспорядок!

К счастью, есть более простой, быстрый и точный метод.

Другой класс кодирования

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

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

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

Хорошим примером этого является целевое кодирование.

Целевое кодирование

С помощью целевого кодирования мы сопоставляем категориальное со средним значением цели с учетом этого категориального значения. Например, если среднее значение цели, в то время как «страна == «США» равно 2,4, мы можем заменить «США» на «2,4». Это может быть особенно полезным методом кодирования для преобразования категорийных данных в нечто порядковое, что явно имеет отношение к задаче прогнозирования.

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

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

Неожиданно хорошие кодировки

Вот несколько примеров таких кодировок:

  • Сопоставление категориальных значений со случайными поплавками.
  • Сортировка категориальных значений в алфавитном порядке, а затем сопоставление с индексом в этом списке (порядковое кодирование).
  • Сопоставление категорийных значений с их частотой в данных.
  • Сопоставление категориальных значений с их частотным рангом в данных.
  • Или… попробуйте придумать свой собственный!

Удивительно, но древовидные модели хорошо совместимы с такими кодировками, что неоднократно демонстрировалось на соревнованиях по науке о данных и в профессиональных приложениях.

Когда эти кодировки не работают?

Вот несколько причин, по которым эти кодировки могут не работать:

  1. Конфликты на карте. Например, частотное кодирование может сопоставлять некоторые категориальные значения с одним и тем же точным числом, что делает модель неспособной использовать их отдельно.
  2. Слишком много категориальных значений. Если информация, содержащаяся в категориальном признаке, находится "глубоко" внутри вектора (т. е. для доступа к ней потребуется слишком много разделов), дерево может не найти ее.
  3. Модель не настроена должным образом, чтобы обеспечить достаточно точное разбиение, чтобы обнулить определенные категориальные значения. Возможно, модели потребуется разрешить очень глубокое разбиение для доступа к информации в категориальном признаке, что может привести к переобучению для Другие особенности.
  4. Удача. Кодировка может просто — по какой-либо причине — скрыть информацию из критерия разделения и может помешать дереву принять решение об использовании функции, даже если она содержит информацию.

Другие кодировки

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

Существует бинарное кодирование (не то же самое, что однократное кодирование, даже несмотря на то, что однократное кодирование создает двоичные признаки), которое представляет собой несколько странное кодирование, отображающее категориальный признак в целое число, и затем сопоставляет это целое число с его представлением в виде двоичной строки; затем каждая двоичная цифра подвергается «горячему кодированию». Это более эффективное представление, чем однократное горячее кодирование, поскольку оно использует столбцы log_base_2(n), а не столбцы n (где n равно мощность категориального признака).

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

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

Эксперименты: давайте сравним методы кодирования

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

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

Все пять, которые я выбрал, — классика.

  • abalone.csv: этот набор регрессионных данных включает прогнозирование возраста морского ушка на основе физических измерений.
  • adult.csv. Этот классификационный набор данных предназначен для прогнозирования того, превышает ли доход человека определенный порог, на основе различных демографических характеристик и характеристик занятости.
  • bank.csv. В этом классификационном наборе данных, известном как набор данных "Банковский маркетинг", цель состоит в том, чтобы предсказать, подпишется ли клиент на срочный депозит в банке.
  • mushroom.csv: этот набор данных классификации включает классификацию грибов как съедобных или ядовитых на основе различных признаков.
  • titanic.csv: набор данных классификации основан на прогнозировании выживания на Титанике на основе характеристик пассажиров.

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

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

Из документации вы можете видеть, что в нашем распоряжении есть масса методов. Все они используют один и тот же API в стиле scikit-learn для подгонки и преобразования наших данных (и фактически являются преобразователями scikit-learn).

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

  • Одно горячее кодирование
  • Порядковое кодирование
  • Двоичное кодирование
  • Целевое кодирование
  • Кодирование счета (частотное кодирование)

Примечание. Порядковый кодировщик пакета Category Encoder (который мы здесь используем) сопоставляет категориальные признаки со случайно выбранными целыми числами. В Scikit-learn также есть класс Ordinal Encoder, но он сопоставляет категории с их рангом в алфавитно отсортированном списке категорий.

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

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

Анализ

Чтобы интерпретировать результаты в этой таблице, обратите внимание на следующее:

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

Лучшие результаты среди наборов данных:

  • abalone: ​​кодирование количества лучше всего подходит для наименьшего RMSE, в данном случае 4,717.
  • взрослый: кодирование количества лучше всего с максимальной точностью, в данном случае 87,6 процента.
  • банк: кодирование подсчета снова побеждает с наивысшей точностью, в данном случае 91,5 процента.
  • гриб: этот набор данных слишком прост, так как все получают 100 процентов.
  • Титаник: снова все завязано.

Согласно моему опыту, а также опыту многих других, «кодирование подсчета», также известное как «кодирование частоты», является очень сильным и надежным методом. Вы можете увидеть это здесь: когда результаты не связаны, Count Encoding немного лучше, чем другие проверенные методы.

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

В частности, подсчет кодировки:

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

В среднем, кодирование Count обычно примерно так же хорошо (или даже лучше) как one-hot-encoding, но оно имеет перечисленные выше преимущества, а также простоту представления.

Как мы видели, с древовидными моделями просто нет причин не выбирать низкоразмерное кодирование! Это путь!

Заключение

Я хотел бы повторить эти эксперименты с большим количеством наборов данных и улучшить глубину сравнения между методами. Здесь есть еще много интересного.

Я настоятельно рекомендую вам использовать кодирование количества/частоты вместо горячего кодирования при работе с древовидными моделями, если у вас нет очень веской причины!

Спасибо за прочтение!

Филипп Адкинс — мастер Kaggle и опытный руководитель в области обработки данных. Найдите его в LinkedIn.