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

Настройка гиперпараметров

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

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

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

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

Древо решений

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

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

Поскольку дерево решений — это в первую очередь модель классификации, мы рассмотрим классификатор дерева решений.

Дерево решенийКлассификатор

критерий: строка, необязательная (по умолчанию=”gini”):

Функция для измерения качества разделения. Поддерживаемые критерии: «джини» для примеси Джини и «энтропия» для прироста информации.

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

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

Согласно статье «Теоретическое сравнение между индексом Джини и критериями прироста информации» [3], частота совпадения/несоответствия индекса Джини и критериев прироста информации составила всего 2% всех случаев, поэтому для всех целей и задач можно в значительной степени используют любой из них, но единственная разница в том, что энтропия может быть немного медленнее для вычисления, потому что она требует от вас вычисления логарифмической функции:

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

разделитель: строка, необязательная (по умолчанию=”best”)

Стратегия, используемая для выбора разделения на каждом узле. Поддерживаемые стратегии: «лучший» для выбора наилучшего разделения и «случайный» для выбора наилучшего случайного разделения.

Согласно «лучшей» и «случайной» реализации scikit-learn [4], как «лучший», так и «случайный» разделитель используют алгоритм Фишера-Йейтса для вычисления перестановки массива признаков. Вам действительно не нужно беспокоиться об алгоритме, единственная разница в том, что в «лучшем» сплиттере он оценивает все разделения с использованием критерия перед разделением, тогда как «случайный» сплиттер использует случайную юниформ-функцию с min_feature_value, max_feature_value и random_state как входы. Мы рассмотрим, что это такое ниже, а пока давайте посмотрим, как сплиттер повлияет на модель.

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

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

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

max_depth: целое число или None, необязательно (по умолчанию = None)

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

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

Давайте сначала поговорим о случае None по умолчанию, если вы не укажете глубину для дерева, scikit-learn будет расширять узлы до тех пор, пока все листья не станут чистыми, то есть лист будет иметь метки только в том случае, если вы выберете значение по умолчанию для min_samples_leaf, где значение по умолчанию — один. Обратите внимание, что большинство этих гиперпараметров связаны друг с другом, и мы вскоре поговорим о min_samples_leaf. С другой стороны, если вы укажете min_samples_split, который мы рассмотрим далее, узлы будут расширяться до тех пор, пока все листья не будут содержать меньше минимального количества выборок. Scikit-learn выберет один из них в зависимости от того, что дает максимальную глубину для вашего дерева. Здесь много движущихся частей, min_samples_split и min_samples_leaf, поэтому давайте просто возьмем max_depth отдельно и посмотрим, что произойдет с вашей моделью, когда вы ее измените, поэтому после того, как мы пройдем через min_samples_split и min_samples_leaf, мы сможем лучше понять, как все это происходит. вместе.

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

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

min_samples_split: int, float, необязательно (по умолчанию=2)

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

  • Если это целое число, минимальное число считается min_samples_split.
  • Если число с плавающей запятой, то min_samples_split — это дробь, а ceil(min_samples_split * n_samples) — это минимальное количество выборок для каждого разделения.

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

Допустим, вы указали min_samples_split, и результирующее разделение приводит к листу с 1 образцом, и вы указали min_samples_leaf как 2, тогда ваш min_samples_split не будет разрешен. Другими словами, min_samples_leaf всегда гарантируется независимо от значения min_samples_split.

Согласно статье «Эмпирическое исследование настройки гиперпараметров деревьев решений» [5], идеальные значения min_samples_split, как правило, находятся в диапазоне от 1 до 40 для алгоритма CART, который является алгоритмом, реализованным в scikit-learn. min_samples_split используется для управления переоснащением. Более высокие значения не позволяют модели изучать отношения, которые могут быть очень специфичными для конкретной выборки, выбранной для дерева. Слишком высокие значения также могут привести к недообучению, поэтому в зависимости от уровня недообучения или переобучения вы можете настроить значения для min_samples_split.

min_samples_leaf: целое число, число с плавающей запятой, необязательный (по умолчанию=1)

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

  • Если это целое число, минимальное число считается min_samples_leaf.
  • Если число с плавающей запятой, то min_samples_leaf — это дробь, а ceil(min_samples_leaf * n_samples) — это минимальное количество выборок для каждого узла.

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

В статье «Эмпирическое исследование по настройке гиперпараметров деревьев решений» [5] также утверждается, что идеальные значения min_samples_leaf обычно находятся в диапазоне от 1 до 20 для алгоритма CART. В этой статье также указывается, что min_samples_split и min_samples_leaf являются наиболее ответственными за производительность окончательных деревьев по результатам их анализа относительной важности [5].

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

min_weight_fraction_leaf: число с плавающей запятой, необязательно (по умолчанию = 0.)

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

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

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

max_features: int, float, string или None, необязательно (по умолчанию = None)

Количество функций, которые следует учитывать при поиске наилучшего разделения:

  • Если это целое число, то учитывайте функции max_features при каждом разделении.
  • Если число с плавающей запятой, то max_features – это дробь, а int(max_features * n_features) функции учитываются при каждом разбиении.
  • Если «авто», то max_features=sqrt(n_features).
  • Если «sqrt», то max_features=sqrt(n_features).
  • Если «log2», то max_features=log2(n_features).
  • Если нет, то max_features=n_features.

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

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

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

random_state: int, экземпляр RandomState или None, необязательно (по умолчанию = None)

Если значение int, random_state — это начальное значение, используемое генератором случайных чисел; Если экземпляр RandomState, random_state является генератором случайных чисел; Если нет, генератором случайных чисел является экземпляр RandomState, используемый np.random.

Ха-ха, пресловутое random_state, большинство новичков спрашивают меня, почему 1, почему 0 или почему 42? 42, потому что в этом смысл жизни, да.

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

Это подводит меня к следующему пункту: я видел, как новые студенты играют со значениями random_state и их точностью, это может произойти, потому что алгоритм дерева решений основан на жадном алгоритме [6], где он повторяется несколько раз с использованием случайного выбор функций (разделитель), и на этот случайный выбор влияет генератор псевдослучайных чисел [7], который принимает значение random_state в качестве начального значения, поэтому, изменяя random_state, вы можете случайным образом выбирать хорошие функции, но что вам нужно понимаете, random_state не является гиперпараметром, изменение точности вашей модели с помощью random_state просто означает, что с вашей моделью что-то не так. Это хороший намек на то, что в ваших данных много локальных минимумов, и дерево решений не очень хорошо с этим справляется, поэтому я бы предпочел, чтобы вы установили random_state и настроили другие параметры, чтобы вы не застряли в локальных минимумах. чем поиграть с random_state.

min_impurity_decrease: число с плавающей запятой, необязательно (по умолчанию = 0.)

Узел будет разделен, если это разделение вызовет уменьшение примеси больше или равное этому значению.

Взвешенное уравнение уменьшения содержания примесей выглядит следующим образом:

N_t / N * (impurity - N_t_R / N_t * right_impurity 
                    - N_t_L / N_t * left_impurity)

где N — общее количество выборок, N_t — количество выборок в текущем узле, N_t_L — количество выборок в левом дочернем элементе, а N_t_R — количество выборок в правом дочернем элементе.

N, N_t, N_t_R и N_t_L относятся к взвешенной сумме, если передается sample_weight.

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

Лучший способ настроить это — построить дерево решений и изучить индекс Джини. Интерпретация дерева решений должна быть довольно простой, если у вас есть знания предметной области в наборе данных, с которым вы работаете, потому что конечный узел будет иметь индекс Джини 0, потому что он чистый, что означает, что все выборки принадлежат одному классу. Затем вы можете изучить расщепления, которые приводят к 0 индексу Джини, и посмотреть, имеет ли смысл классифицировать ваши классы как таковые или вы можете уменьшить глубину, тем самым приведя к более обобщающему дереву, если это так, вы можете увеличить min_impurity_decrease, чтобы предотвратить дальнейшее деление, потому что теперь узел не будет далее разделен, если примесь не уменьшится на указанную вами величину. Обратите внимание, что это повлияет на все ваше дерево, поэтому вам придется поэкспериментировать с числами, но приведенное выше объяснение должно дать вам отправную точку.

class_weight: словарь, список словарей, «сбалансированный» или «Нет», по умолчанию = «Нет»

Веса, связанные с классами, в виде {метка_класса: вес}. Если не указано, предполагается, что все классы имеют вес один. Для задач с несколькими выходами список словарей может быть предоставлен в том же порядке, что и столбцы y.

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

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

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

weight * (the number of samples from a class in the node) / (size of class)

presort: bool, необязательно (по умолчанию = False)

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

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

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

Краткое содержание

Сложность дерева решений оказывает решающее влияние на его точность и явно контролируется используемыми критериями остановки и используемым методом сокращения. Обычно сложность дерева измеряется одной из следующих метрик: общее количество узлов, общее количество листьев, глубина дерева и количество используемых атрибутов [8]. max_depth, min_samples_split и min_samples_leaf являются критериями остановки, тогда как min_weight_fraction_leaf и min_impurity_decrease являются методами обрезки.

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

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