Вступление
В предыдущей статье мы изучили, как мы можем использовать методы фильтрации для выбора функций для алгоритмов машинного обучения. Методы фильтрации удобны, когда вы хотите выбрать общий набор функций для всех моделей машинного обучения.
Однако в некоторых сценариях вы можете использовать определенный алгоритм машинного обучения для обучения вашей модели. В таких случаях функции, выбранные с помощью методов фильтрации, могут быть не самым оптимальным набором функций для этого конкретного алгоритма. Существует еще одна категория методов выбора характеристик, которые выбирают наиболее оптимальные характеристики для указанного алгоритма. Такие методы называются методами-оболочками .
Методы оболочки для выбора функций
Методы оболочки основаны на алгоритмах жадного поиска, поскольку они оценивают все возможные комбинации функций и выбирают комбинацию, которая дает наилучший результат для конкретного алгоритма машинного обучения. Обратной стороной этого подхода является то, что тестирование всех возможных комбинаций функций может быть очень затратным в вычислительном отношении, особенно если набор функций очень велик.
Как было сказано ранее, методы-оболочки могут найти лучший набор функций для конкретного алгоритма, однако недостатком является то, что этот набор функций может не быть оптимальным для любого другого алгоритма машинного обучения.
Методы оболочки для выбора функций можно разделить на три категории: « Шаг вперед», «Выбор функции» и « Исчерпывающий выбор функций» . В этой статье мы увидим, как мы можем реализовать эти подходы к выбору функций в Python.
Шаг вперед выбор функции
На первом этапе поэтапного выбора признаков эффективность классификатора оценивается по каждому признаку. Из всех функций выбирается наиболее эффективная функция.
На втором этапе первая функция проверяется в сочетании со всеми другими функциями. Выбирается комбинация двух функций, обеспечивающая наилучшую производительность алгоритма. Процесс продолжается до тех пор, пока не будет выбрано указанное количество функций.
Давайте реализуем пошаговый выбор функций в Python. В этом разделе мы будем использовать набор данных BNP Paribas Cardif Claims Management, как и в предыдущей статье.
Чтобы реализовать пошаговый выбор функций, нам необходимо преобразовать значения категориальных функций в числовые значения функций. Однако для простоты мы удалим все некатегориальные столбцы из наших данных. Мы также удалим коррелированные столбцы, как мы это делали в предыдущей статье, чтобы у нас был небольшой набор функций для обработки.
Предварительная обработка данных
Следующий скрипт импортирует набор данных и необходимые библиотеки, затем удаляет нечисловые столбцы из набора данных, а затем разделяет набор данных на наборы для обучения и тестирования. Наконец, все столбцы с корреляцией больше 0,8 удаляются. Взгляните на эту статью для подробного объяснения этого скрипта:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import VarianceThreshold
paribas_data = pd.read_csv(r"E:\Datasets\paribas_data.csv", nrows=20000)
paribas_data.shape
num_colums = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
numerical_columns = list(paribas_data.select_dtypes(include=num_colums).columns)
paribas_data = paribas_data[numerical_columns]
paribas_data.shape
train_features, test_features, train_labels, test_labels = train_test_split(
paribas_data.drop(labels=['target', 'ID'], axis=1),
paribas_data['target'],
test_size=0.2,
random_state=41)
correlated_features = set()
correlation_matrix = paribas_data.corr()
for i in range(len(correlation_matrix .columns)):
for j in range(i):
if abs(correlation_matrix.iloc[i, j]) > 0.8:
colname = correlation_matrix.columns[i]
correlated_features.add(colname)
train_features.drop(labels=correlated_features, axis=1, inplace=True)
test_features.drop(labels=correlated_features, axis=1, inplace=True)
train_features.shape, test_features.shape
Реализация пошагового выбора функций в Python
Для выбора наиболее оптимальных функций мы будем использовать функцию
SequentialFeatureSelector
из библиотеки
mlxtend. Библиотеку можно загрузить,
выполнив следующую команду в командной строке anaconda:
conda install -c conda-forge mlxtend
Мы воспользуемся классификатором «Случайный лес», чтобы найти наиболее оптимальные параметры. Используемые критерии оценки
ROC-AUC . Следующий скрипт выбирает 15 функций из нашего набора данных, которые обеспечивают лучшую производительность для случайного классификатора леса:
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score
from mlxtend.feature_selection import SequentialFeatureSelector
feature_selector = SequentialFeatureSelector(RandomForestClassifier(n_jobs=-1),
k_features=15,
forward=True,
verbose=2,
scoring='roc_auc',
cv=4)
В приведенном выше скрипте мы передаем RandomForestClassifier
в
качестве оценщика функции SequentialFeatureSelector
k_features
указывает количество функций для выбора. Здесь вы можете установить
любое количество функций. Если для forward
установлено значение True
, выполняется пошаговый выбор функции. Параметр verbose
используется
для регистрации хода выполнения селектора функций, scoring
определяет
критерии оценки производительности и, наконец, cv
относится к сверткам
перекрестной проверки.
Мы создали наш селектор функций, теперь нам нужно вызвать fit
в нашем
селекторе функций и передать ему обучающие и тестовые наборы, как
показано ниже:
features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)
В зависимости от оборудования вашей системы выполнение вышеуказанного сценария может занять некоторое время. После завершения выполнения вышеуказанного сценария вы можете выполнить следующий сценарий, чтобы увидеть 15 выбранных функций:
filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features
На выходе вы должны увидеть следующие функции:
Index(['v4', 'v10', 'v14', 'v15', 'v18', 'v20', 'v23', 'v34', 'v38', 'v42',
'v50', 'v51', 'v69', 'v72', 'v129'],
dtype='object')
Теперь, чтобы увидеть эффективность классификации алгоритма случайного леса с использованием этих 15 функций, выполните следующий сценарий:
clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)
train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))
test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))
В приведенном выше скрипте мы обучаем наш алгоритм случайного леса на 15 функциях, которые мы выбрали с помощью пошагового выбора функций, а затем мы оценили производительность нашего алгоритма на наборах для обучения и тестирования. На выходе вы должны увидеть следующие результаты:
Accuracy on training set: 0.7072327148174093
Accuracy on test set: 0.7096973252804142
Вы можете видеть, что точность обучающих и тестовых наборов довольно схожа, что означает, что наша модель не переобучена.
Шаг назад Выбор функции
Шаг назад при выборе функции, как следует из названия, является полной противоположностью шага вперед выбора функции, которую мы изучали в предыдущем разделе. На первом этапе шага назад выбора функции одна функция удаляется циклическим способом из набора функций и оценивается производительность классификатора.
Набор функций, обеспечивающий наилучшую производительность, сохраняется. На втором этапе снова удаляется одна функция в циклическом режиме и оценивается производительность всей комбинации функций, кроме двух. Этот процесс продолжается до тех пор, пока указанное количество объектов не останется в наборе данных.
Шаг назад к выбору функций в Python
В этом разделе мы реализуем шаг назад по выбору функции в BNP Paribas
Cardif Claims
Management
. Шаг предварительной обработки останется таким же, как и в предыдущем
разделе. Единственное изменение будет в параметре forward
класса
SequentiaFeatureSelector
В случае выбора функции шага назад мы
установим для этого параметра значение False
. Выполните следующий
скрипт:
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score
from mlxtend.feature_selection import SequentialFeatureSelector
feature_selector = SequentialFeatureSelector(RandomForestClassifier(n_jobs=-1),
k_features=15,
forward=False,
verbose=2,
scoring='roc_auc',
cv=4)
features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)
Чтобы увидеть функцию, выбранную в результате удаления шага назад, выполните следующий скрипт:
filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features
Результат выглядит так:
Index(['v7', 'v8', 'v10', 'v17', 'v34', 'v38', 'v45', 'v50', 'v51', 'v61',
'v94', 'v99', 'v119', 'v120', 'v129'],
dtype='object')
Наконец, давайте оценим производительность нашего классификатора случайного леса на объектах, выбранных в результате пошагового выбора объектов назад. Выполните следующий скрипт:
clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)
train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))
test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))
Результат выглядит примерно так:
Accuracy on training set: 0.7095207938140247
Accuracy on test set: 0.7114624676445211
Вы можете видеть, что производительность, достигнутая на обучающем наборе, аналогична производительности, достигнутой при пошаговом выборе функции. Однако на тестовом наборе обратный выбор функций работал немного лучше.
Исчерпывающий выбор функций
При исчерпывающем выборе функций производительность алгоритма машинного обучения оценивается по всем возможным комбинациям функций в наборе данных. Выбирается подмножество функций, обеспечивающее наилучшую производительность. Алгоритм исчерпывающего поиска - самый жадный алгоритм из всех методов-оболочек, поскольку он пробует все комбинации функций и выбирает лучшее.
Обратной стороной исчерпывающего выбора функций является то, что он может быть медленнее по сравнению с методом шага вперед и назад, поскольку он оценивает все комбинации функций.
Исчерпывающий выбор функций в Python
В этом разделе мы реализуем шаг назад по выбору функции в BNP Paribas Cardif Claims Management . Шаг предварительной обработки останется таким же, как при выборе функции «Шаг вперед».
Чтобы реализовать исчерпывающий выбор функций, мы будем использовать
функцию ExhaustiveFeatureSelector
из библиотеки
mlxtend.feature_selection
Класс имеет min_features
и max_features
которые можно использовать для определения минимального и максимального
количества функций в комбинации.
Выполните следующий скрипт:
from mlxtend.feature_selection import ExhaustiveFeatureSelector
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score
feature_selector = ExhaustiveFeatureSelector(RandomForestClassifier(n_jobs=-1),
min_features=2,
max_features=4,
scoring='roc_auc',
print_progress=True,
cv=2)
Мы создали наш селектор функций, теперь нужно вызвать fit
в нашем
селекторе функций и передать ему обучающие и тестовые наборы, как
показано ниже:
features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)
Обратите внимание, что выполнение приведенного выше сценария может занять довольно много времени. Чтобы увидеть функцию, выбранную в результате удаления шага назад, выполните следующий скрипт:
filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features
Наконец, чтобы увидеть производительность классификатора случайного леса на объектах, выбранных в результате исчерпывающего выбора признаков. Выполните следующий скрипт:
clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)
train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))
test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))
Заключение
Методы оболочки - одни из наиболее важных алгоритмов, используемых для выбора функций для конкретного алгоритма машинного обучения. В этой статье мы изучили различные типы методов-оберток, а также их практическую реализацию. Мы изучили шаг вперед, шаг назад и исчерпывающие методы выбора функций.
Как правило, если набор данных невелик, следует выбирать метод исчерпывающего выбора признаков, однако в случае больших наборов данных предпочтение следует отдавать методам выбора объектов с шагом вперед или назад.