Как мы можем использовать Boruta и SHAP для создания удивительного процесса выбора функций — с примерами Python

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

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

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

1. Особенности тени

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

Скажем, у нас есть набор данных с 3 функциями и 100 наблюдениями. В этом случае мы делаем копию набора данных и перемешиваем каждый столбец признаков. Переставленные объекты затем называются «теневыми объектами» (кстати, крутое название) и создают новый набор данных, набор данных Boruta, объединяющий все 3 исходных и 3 новых теневых объекта.

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

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

2. Биномиальные распределения

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

Рассмотрим набор данных фильмов с тремя функциями: «жанр», «audience_score» и «critic_score». Из 20 итераций мы смогли получить следующие результаты:

Мы можем разместить эти результаты на графике биномиального распределения:

Хвосты распределения являются наиболее важной частью. В примере на каждый приходится 0,5% вероятности.

Переменная genre попала в красную область, которая является областью «отклонения». Здесь мы уверены, что функции не повлияют на целевую переменную.

Зеленая зона – это зона «принятия». Мы также уверены, что эти функции являются прогностическими и предназначены для сохранения в модели. В этом примере critic_score — хорошая функция, которую следует сохранить.

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

Мы сохраняем функции, которые были классифицированы в зеленой и синей областях, и отбрасываем те, что в красной области.

Вы можете ознакомиться с отличным объяснением алгоритма Боруты здесь.

3. Борута на Питоне

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



Чтобы использовать Boruta, мы можем использовать библиотеку BorutaPy [1]:

pip install boruta

Затем мы можем импортировать набор данных о диабете (доступен в Scikit-Learn [2]):

from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
# Fetches the data
dataset = load_diabetes(as_frame = True)
# Gets the independent variables
X = dataset['data']
# Gets the dependent variable (the target)
y = dataset['target']
# Splits the dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

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

from sklearn.ensemble import RandomForestRegressor
# Defines the estimator used by the Boruta algorithm
estimator = RandomForestRegressor()

Теперь мы можем создать объект BorutaPy и подогнать его к данным с помощью оценщика:

from boruta import BorutaPy
# Creates the BorutaPy object
boruta = BorutaPy(estimator = estimator, n_estimators = 'auto', max_iter = 100)
# Fits Boruta
boruta.fit(np.array(X_train), np.array(y_train))

Наконец, мы можем обнаружить, какие функции важны, какие не важны, а какие неопределенны:

# Important features
important = list(X.columns[boruta.support_])
print(f"Features confirmed as important: {important}")
# Tentative features
tentative = list(X.columns[boruta.support_weak_])
print(f"Unconfirmed features (tentative): {tentative}")
# Unimportant features
unimportant = list(X.columns[~(boruta.support_ | boruta.support_weak_)])
print(f"Features confirmed as unimportant: {unimportant}")

Результат:

Features confirmed as important: ['bmi', 'bp', 's5', 's6']
Unconfirmed features (tentative): []
Features confirmed as unimportant: ['age', 'sex', 's1', 's2', 's3', 's4']

4. Выбор функций Boruta SHAP

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

Именно здесь к команде присоединяется SHAP [3]. Используя значения SHAP в качестве метода выбора функций в Boruta, мы получаем алгоритм выбора функций Boruta SHAP. С помощью этого подхода мы можем получить сильные захватывающие объяснения свойств, существующие в методе SHAP, в то же время обладая надежностью алгоритма Боруты, чтобы гарантировать, что в наборе останутся только значимые переменные.

Если вы не знаете, что такое SHAP, взгляните на мою статью, в которой это объясняется:



5. Борута SHAP на Python

Чтобы использовать Boruta, мы можем использовать библиотеку BorutaShap [4]:

pip install BorutaShap

Сначала нам нужно создать объект BorutaShap. Значение по умолчанию для importance_measure — «shap», поскольку мы хотим использовать SHAP в качестве дискриминатора важности функции. Мы можем изменить параметр classification на True, если проблема связана с классификацией.

from BorutaShap import BorutaShap
# Creates a BorutaShap selector for regression
selector = BorutaShap(importance_measure = 'shap', classification = False)

Затем мы подгоняем селектор BorutaShap к данным или выборке данных. Параметр n_trials определяет количество итераций алгоритма Boruta, а логическое значение sample определяет, будет ли метод производить внутреннюю выборку данных для ускорения процесса.

# Fits the selector
selector.fit(X = X_train, y = y_train, n_trials = 100, sample = False, verbose = True)
# n_trials -> number of iterations for Boruta algorithm
# sample -> samples the data so it goes faster

После подгонки будет показан следующий результат:

4 attributes confirmed important: ['s5', 'bp', 'bmi', 's6']
5 attributes confirmed unimportant: ['s2', 's4', 's3', 'age', 'sex']
1 tentative attributes remains: ['s1']

Наконец, мы можем увидеть, какие функции будут удалены, и удалить их из наших данных:

# Display features to be removed
features_to_remove = selector.features_to_remove
print(features_to_remove)
# Removes them
X_train_boruta_shap = X_train.drop(columns = features_to_remove)
X_test_boruta_shap = X_test.drop(columns = features_to_remove)

6. Заключение

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

Недостатком этого метода является время оценки, которое может быть слишком большим для многих итераций Boruta или когда SHAP подходит для многих наблюдений. Остерегайтесь времени!

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

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

Если вам нравится этот пост…

Поддержите меня чашечкой кофе!

И прочитайте этот замечательный пост



Ссылки

[1 ] Пакет BorutaPy: https://github.com/scikit-learn-contrib/boruta_py

[2] Набор данных о диабете Scikit-Learn: https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html

[3] Пакет SHAP: https://shap.readthedocs.io/en/latest/index.html

[4] Пакет BorutaShap: https://github.com/Ekeany/Boruta-Shap

[5] https://medium.com/analytics-vidhya/is-this-the-best-feature-selection-algorithm-borutashap-8bc238aa1677

[6] https://towardsdatascience.com/boruta-explained-the-way-i-wish-someone-explained-it-to-me-4489d70e154a