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

Этот метод, реализованный на Python и теперь имеющий открытый исходный код, основан на общем алгоритме: рекурсивное исключение признаков (RFE). Однако, используя важность функции SHAPley Additive ExPlanations (SHAP) и поддерживая оптимизацию гиперпараметров, можно достичь более точных и надежных результатов с помощью ShapRFECV, с API, знакомым пользователям scikit-learn.

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

Выбор функции

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

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

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

Рекурсивное исключение признаков

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

  1. Подгоните модель и вычислите важность функции. В зависимости от реализации этот шаг может включать использование перекрестной проверки (CV).
  2. Удалите из набора данных n объекты, которые имеют наименьшее значение, где n - параметр.

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

Популярные Python-реализации RFE - RFE и RFECV, обе доступны в scikit-learn. Однако при их использовании необходимо учитывать две проблемы, описанные в следующих подразделах.

Ловушка важности характеристик в RFE

Как уже упоминалось, RFE сильно зависит от метрики важности функции, используемой для выбора переменных, которые будут удалены на каждой итерации. В случае реализаций scikit-learn RFE и RFECV этими метриками важности функций являются следующие: коэффициенты (бета-версии) для линейных моделей и важность функции на основе примесей для древовидных моделей.

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

Модели на основе дерева решений позволяют использовать сильно нелинейные отношения в данных. Следовательно, использование RFE с алгоритмом случайного леса, например, позволяет найти подмножество функций, которые содержат сложные шаблоны, которые очень предсказуемы для цели. К сожалению, RFE и RFECV (как реализовано в scikit-learn) по умолчанию используют метрику важности на основе примесей для древовидных моделей.

Важность на основе примесей рассчитывается как нормализованное общее сокращение критерия разделения, вызванное данным признаком во всех деревьях модели. По сути, он показывает, насколько высоко и как часто данная функция используется в дереве (ах) модели. Это не только напрямую не влияет на важность функции, но также и то, что метод сильно смещен в сторону характеристик с высокой мощностью, что означает, что переменная, имеющая более уникальные значения, имеет более высокий шанс иметь высокую важность. Таким образом, использование RFE или RFECV с древовидной моделью, например, Random Forest или XGBoost, может привести к смещенным результатам.

Зачем нужна гиперпараметрическая оптимизация в RFE

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

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

Однако, что касается древовидных моделей, существует множество параметров для оптимизации, которые существенно влияют на производительность модели и ее рейтинг важности. Для настройки этих гиперпараметров часто применяются схемы поиска, такие как GridSearchCV или RandomizedSearchCV. К сожалению, использование этих методов в RFE / RFECV scikit-learn в настоящее время не поддерживается, что может, следовательно, смещать выходной набор функций для древовидных моделей.

Рекурсивное исключение признаков с помощью SHAP

Эти проблемы решаются с помощью Probatus, пакета Python с открытым исходным кодом, созданного специалистами по данным в ING Bank. Probatus предоставляет инструменты для анализа моделей бинарной классификации, уделяя внимание также данным, используемым для их разработки. Пакет теперь предоставляет ShapRFECV, алгоритм RFE для древовидных моделей двоичной классификации, который поддерживает настройку гиперпараметров на каждой итерации при использовании SHAP для оценки важности функций.

Важность функции SHAP - новая передовая практика

SHAP - это пакет Python с открытым исходным кодом, который, как описано в их документации,

«… Это теоретико-игровой подход к объяснению результатов любой модели машинного обучения. Он связывает оптимальное распределение кредитов с местными объяснениями с использованием классических ценностей Шепли из теории игр и связанных с ними расширений… ».

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

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

Основные преимущества важности функции SHAP следующие:

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

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

ShapRFECV в Пробатусе

ShapRFECV в Пробатусе реализует алгоритм RFE для древовидных моделей классификации с использованием важности признаков SHAP. В каждой итерации RFE применяются следующие шаги:

  1. (Необязательно) Настройте гиперпараметры модели с помощью GridSearchCV или RandomizedSearchCV.
  2. Примените перекрестную проверку (CV), чтобы оценить важность функции SHAP в предоставленном наборе данных. В каждом CV-сгибе настроенная модель размещается на разделенных поездах, затем оценивается на валидационных разделах, чтобы оценить важность функции SHAP.
  3. Удалите из набора данных n объекты с наименьшей важностью SHAP, где n - параметр.

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

Пример использования

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

from probatus.feature_elimination import ShapRFECV
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split, RandomizedSearchCV
import numpy as np
import pandas as pd
import lightgbm
feature_names = ['f1_categorical', 'f2_missing', 'f3_static', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f20']
# Prepare dataset
X, y = make_classification(n_samples=1000, class_sep=0.05, n_informative=6, n_features=20, random_state=0, n_redundant=10, n_clusters_per_class=1)
X = pd.DataFrame(X, columns=feature_names)
X['f1_categorical'] = X['f1_categorical'].apply(lambda x: str(np.round(x*10)))
X['f2_missing'] = X['f2_missing'].apply(lambda x: x if np.random.rand()<0.8 else np.nan)
X['f3_static'] = 0

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

clf = lightgbm.LGBMClassifier(max_depth=5, class_weight='balanced')
param_grid = {'n_estimators': [5, 7, 10], 'num_leaves': [3, 5, 7, 10]}
search = RandomizedSearchCV(clf, param_grid, cv=5, scoring='roc_auc', refit=False)

Имея целевой набор данных, модель и пространство поиска гиперпараметров, теперь мы можем применить ShapRFECV:

shap_elimination = ShapRFECV(search, step=0.2, cv=10, scoring='roc_auc', n_jobs=3)
report = shap_elimination.fit_compute(X, y)

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

performance_plot = shap_elimination.plot()

График выше иллюстрирует производительность модели (с использованием метрики AUC) для обучающих и проверочных разделов модели для разного количества функций. Линия представляет собой усредненный CV-балл AUC, а заштрихованная область позади показывает стандартное отклонение CV-баллов. Мы видим, что AUC проверки начинает терять около 8 или 7 функций. Таким образом, мы можем безопасно удалить 12 из 20 функций без значительного снижения производительности.

Мы можем вывести окончательный набор функций следующим образом:

shap_elimination.get_reduced_features_set(num_features=8)

[«F9», «f16», «f1_categorical», «f14», «f15», «f19», «f5», «f8»]

ShapRFECV против RFECV

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

from probatus.feature_elimination import ShapRFECV
import numpy as np
import pandas as pd
import lightgbm
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import RFECV
# Prepare train and test data:
X, y = make_classification(n_samples=10000, class_sep=0.1, n_informative=40, n_features=50, random_state=0, n_clusters_per_class=10)
X = pd.DataFrame(X)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)
# Set up the model:
clf = lightgbm.LGBMClassifier(n_estimators=10, num_leaves=7)
# Run RFECV and ShapRFECV with the same parameters
rfe = RFECV(clf, step=1, cv=10, scoring='roc_auc', n_jobs=3).fit(X_train, y_train)
shap_elimination = ShapRFECV(clf=clf, step=1, cv=10, scoring='roc_auc', n_jobs=3)
shap_report = shap_elimination.fit_compute(X_train, y_train)

Теперь мы можем визуализировать результаты обоих методов:

На графике выше представлена ​​усредненная CV Validation AUC производительности модели для каждого раунда процесса RFE как в ShapRFECV, так и в RFECV. Оптимальное количество функций - 21 для первого и 13 для второго.

Сравним производительность модели, обученной на:

  • Все 50 доступных функций (базовые),
  • 13 функций, выбранных RFECV (оптимально),
  • 21 функция, выбранная ShapRFECV (оптимальная),
  • 13 функций, выбранных ShapRFECV (базовый уровень).

Как показано на графике, ShapRFECV обеспечивает превосходные результаты для обоих: CV Validation и Test AUC, по сравнению с RFECV и базовой моделью со всеми доступными функциями. Представленный метод позволяет не только устранить особенности без потери производительности, но и может повысить производительность модели.

Когда дело доходит до времени, необходимого для выполнения выбора функции в эксперименте выше, RFECV занимает 6,11 ± 33,7 мс, тогда как ShapRFECV занимает 10,1 ± 72,8 мс, что показывает, что последнее требует больших вычислительных затрат из-за расчета значений SHAP.

Заключение

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

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

Особая благодарность команде Probatus, особенно Райану Чавесу и Тиму Винку за их вклад в функцию ShapRFECV и этот пост.