Оптимизация древовидных моделей

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

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

Тестовая установка

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

Как себя чувствовали модели?

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

Обычно мы ожидаем, что однократное кодирование улучшит модель, но, как видно на снимке экрана, модель с однократным кодированием работает значительно хуже, чем модель без него. Однократное горячее кодирование способствовало уменьшению логарифмических потерь на 0,157 единицы. Победители конкурса Kaggle определяются с минимальной маржой, и смещение 0,05 может быть разницей между попаданием в верхние 75% и лучшие 25% в таблице лидеров. Теперь, когда мы установили, что горячее кодирование ухудшает модели, давайте рассмотрим причины, по которым это происходит.

Почему это происходит?

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

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

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

Например, рассмотрим следующий набор данных, который содержит фиктивные переменные для
категориальных переменных, которые имеют уровни A, B, C и D. Если бы мы подгоняли дерево решений к этим данным только для понимания разбиений, оно было бы напоминанием следующий.

В заключение, если у нас есть категориальная переменная с q уровнями, дерево должно выбирать из ((2 ^ q / 2) -1) разбиений. Для фиктивной переменной существует только одно возможное разделение, и это вызывает разреженность.

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

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

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

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

Важность функции

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

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

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

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

Ссылка на Github

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

Дополнительное чтение

  1. Визуализация - http://www.r2d3.us/visual-intro-to-machine-learning-part-1/
  2. Учебник - https://web.stanford.edu/~hastie/ElemStatLearn//
  3. Увлекательное обсуждение - https://www.kaggle.com/c/zillow-prize-1/discussion/38793
  4. Сводка по всем типам кодирования - https://medium.com/data-design/visiting-categorical-features-and-encoding-in-decision-trees-53400fa65931