Применение методов-оболочек для выбора функций в Python

Методы фильтрации удобны, когда вы хотите выбрать общий набор функций для всех моделей машинного обучения в Python.

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

Методы-оболочки

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

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

Методы оболочки для выбора функций можно разделить на три категории: «Шаг вперед», «Выбор функции» и «Исчерпывающий выбор функций». В этой статье мы увидим, как мы можем реализовать эти подходы к выбору функций в 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

Реализация пошагового выбора функций

Для выбора наиболее оптимальных функций мы будем использовать функцию SequentialFeatureSelector из библиотеки mlxtend. Библиотеку можно загрузить, выполнив следующую команду в командной строке anaconda:

conda install -c conda-forge mlxtend

Мы воспользуемся классификатором random forest, чтобы найти наиболее оптимальные параметры. Используемые критерии оценки – 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)

В приведенном выше скрипте мы передаем RandomForestClassifieras функции SequentialFeatureSelector. K_features указывает количество функций для выбора. Здесь вы можете установить любое количество функций. Если для параметра forward установлено значение True, выполняется пошаговый выбор функции. Параметр verbose используется для регистрации хода работы селектора функций, параметр scoring определяет критерии оценки производительности и, наконец, cv относится к сверткам перекрестной проверки.

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

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')

Теперь, чтобы увидеть эффективность классификации алгоритма Forest с использованием этих 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])))

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

Accuracy on training set: 0.7072327148174093
Accuracy on test set: 0.7096973252804142

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

Выбор функции: шаг назад

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

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

Step Backwards

В этом разделе мы реализуем шаг назад (Step Backwards) по выбору функции в 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')

Наконец, давайте оценим производительность нашего классификатора RandomForest на объектах, выбранных в результате пошагового выбора объектов назад. Выполните следующий скрипт:

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

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

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

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

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

Окончательный выбор функций

В этом разделе мы реализуем шаг назад по выбору функции в 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)

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

features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)

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

filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features

Наконец, чтобы увидеть производительность RandomForestClassifier на объектах, выбранных в результате исчерпывающего выбора признаков. Выполните следующий скрипт:

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])))

Заключение

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *