📊 Построение и отбор признаков. Часть 2: feature selection

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

Что такое отбор признаков?

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

«Прогонка» всех признаков в модели, чтобы посмотреть, какие из них работают – плохая идея. На самом деле алгоритмы работают плохо, когда в них попадает слишком много “фич”. Как решить эту проблему? При помощи отбора признаков.

Отбор признаков (feature selection) – это оценка важности того или иного признака с помощью алгоритмов машинного обучения и отсечение ненужных.

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

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

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

1. Методы фильтрации (filter methods)

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

Сбор информации (Information Gain, IG)

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

import pandas as pd
import numpy as np
from sklearn.feature_selection import mutual_info_classif
import matplotlib.pyplot as plt

importances = mutual_info_classif(X, y)
# Где data - ваш датасет; X, y – входные и выходные данные соответственно
feature_importances = pd.Series(importances, data.columns[0:len(data.columns)-1])
feature_importances.plot(kind='barh', color='teal')
plt.show()

Критерий хи-квадрат (Chi-square Test)

Используется для категориальных признаков в датасете. Мы вычисляем хи-квадрат между каждым признаком и целью, после выбираем желаемое количество “фич” с лучшими показателями. Чтобы правильно применить критерий для проверки связи между различными функциями в наборе данных и целевой переменной, должны быть выполнены следующие условия: категориальные переменные, которые выбираются независимо, и частота значений > 5.

import pandas as pd
import numpy as np
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

# Преобразование в категориальные данные путем преобразования в целые числа.
# Где X, y - входные и выходные данные соответственно.
X_categorical = X.astype(int)

# Выбираем 3 признака с наивысшим "хи-квадрат".
chi2_features = SelectKBest(chi2, k = 3)
X_kbest_features = chi2_features.fit_transform(X_categorical, y)

# Вывод "до и после"
print("Количество признаков до преобразования:", X_categorical.shape[1])
print("Количество признаков после преобразования:", X_kbest_features.shape[1])

Критерий Фишера (F-тест)

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

import pandas as pd
import numpy as np
from skfeature.function.similarity_based import fisher_score
import matplotlib.pyplot as plt

# Вычисляем критерий
# Где X, y - входные и выходные данные соответственно.
ranks = fisher_score.fisher_score(X, y)

# Делаем график наших "фич"
# Где data - ваш датасет
feature_importances = pd.Series(ranks, data.columns[0:len(data.columns)-1])
feature_importances.plot(kind='barh', color='teal')
plt.show()

Коэффициент корреляции

Корреляция – это мера линейной связи двух или более переменных. При её помощи мы можем предсказать одну переменную через другую. Логика использования этого метода для выбора характеристик заключается в том, что “хорошие” переменные сильно коррелируют с нашей целью.

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

import seaborn as sns
import matplotlib.pyplot as plt

# Матрица корреляции
# Где data - ваш датасет
correlation_matrix = data.corr()

# Выводим признаки на тепловую карту
plt.figure(figsize= (10, 6))
sns.heatmap(correlation_matrix, annot = True)

Абсолютное отклонение (Mean Absolute Difference, MAD)

Эта техника позволяет нам вычислить абсолютное отклонение от среднего.

import pandas as pd
import numpy as np
import matplotlib as plt
# Вычисляем MAD
# Где X - входные данные
mean_absolute_difference = np.sum(np.abs(X - np.mean(X, axis = 0)), axis = 0) / X.shape[0]

# Наш график признаков
plt.bar(np.arange(X.shape[1]), mean_absolute_difference, color = 'teal')

2. Методы обертки (wrapper methods)

Особенность этих методов – поиск всех возможных подмножеств признаков и оценка их качества путем “прогонки” через модель.

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

Прямой отбор признаков

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

from sklearn.linear_model import LogisticRegression
from mlxtend.feature_selection import SequentialFeatureSelector
 
lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)
ffs = SequentialFeatureSelector(lr, k_features='best', forward = True, n_jobs=-1)
 
ffs.fit(X, Y)
# X, y – входные и выходные данные соответственно.
# X_train – входные данные с обучающейся выборки,
# y_pred – выходные данные предиктора
features = list(ffs.k_feature_names_)
features = list(map(int, features))
y_pred = lr.predict(X_train[features])

Последовательный отбор признаков

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

from sklearn.linear_model import LogisticRegression
from mlxtend.feature_selection import SequentialFeatureSelector

lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)
lr.fit(X, y)

bfs = SequentialFeatureSelector(lr, k_features='best', forward = False, n_jobs=-1)
bfs.fit(X, y)
features = list(bfs.k_feature_names_)
features = list(map(int, features))
lr.fit(X_train[features], y_train)
y_pred = lr.predict(x_train[features])

Исчерпывающий выбор признаков

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

from mlxtend.feature_selection import ExhaustiveFeatureSelector
from sklearn.ensemble import RandomForestClassifier

# создаем ExhaustiveFeatureSeLlector объект.
efs = ExhaustiveFeatureSelector(RandomForestClassifier(),
        min_features=4,
        max_features=8,
        scoring='roc_auc',
        cv=2)

efs = efs.fit(X, Y)

# выводим выбранные признаки
selected_features = X_train.columns[list(efs.best_idx_)]
print(selected_features)

# выводим финальную оценку прогнозирования.
print(efs.best_score_)

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

Сначала модель обучается на начальной выборке признаков, и важность каждой функции определяется либо с помощью атрибута coef_ или feature_importances_. Затем наименее важные “фичи” удаляются из текущего набора. Процедура рекурсивно повторяется для сокращенного набора до тех пор, пока в конечном итоге не будет достигнуто желаемое количество признаков для выбора.

from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import RFE

lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)

rfe = RFE(lr, n_features_to_select=7)
rfe.fit(X_train, y_train)
# X_train, y_train - входные и выходные данные с обучающей выборки соответственно.
y_pred = rfe.predict(X_train)

3. Встроенные методы (embedded methods)

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

Регуляризация LASSO (L1)

Регуляризация состоит в добавлении штрафа (penalty) к различным параметрам модели во избежание чрезмерной подгонки. При регуляризации линейной модели штраф применяется к коэффициентам, умножающим каждый из предикторов. Lasso-регуляризация обладает свойством, позволяющим уменьшить некоторые коэффициенты до нуля. Следовательно, такие “фичи” можно будет просто удалить из модели.

from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import SelectFromModel

# Устанавливаем наш параметр регуляризации C=1
logistic = LogisticRegression(C=1, penalty="l1", solver='liblinear', random_state=7).fit(X, y)
# Где X, y - входные и выходные данные соответственно.
model = SelectFromModel(logistic, prefit=True)

X_new = model.transform(X)

# Выбираем нужные нам столбцы из датасета без нулевых данных
# Где “selected_features” - предварительно выбранные нами признаки (см. по предыдущим методам)
selected_columns = selected_features.columns[selected_features.var() != 0]
print(selected_columns)

Метод с использованием Случайного Леса (Random Forest Importance)

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

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier

# создаем случайное дерево с вашими гипер параметрами
model = RandomForestClassifier(n_estimators=340)

# Обучаем модель на вашей выборке; Где X, y - входные и выходные данные соответственно.
model.fit(X, y)

# Подбираем самые важные признаки
importances = model.feature_importances_

# Создаем отдельный датасет для визуализации
final_df = pd.DataFrame({"Features" : pd.DataFrame(X).columns, "Importances" : importances})
final_df.set_index('Importances')

# Сортируем их по возрастанию для лучшей визуализации
final_df = final_df.sort_values('Importances')

# Выводим на график
final_df.plot.bar(color = 'teal')

Заключение

Эффективный отбор необходимых “фич” для модели приводит к наибольшему увеличению производительности. Это та проблема, за решением которой дата-сайентисты проводят большую часть времени. Разумеется, без построения признаков (feature engineering) у нас не будет материала для дальнейшего отбора.

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


ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

matyushkin
07 апреля 2020

ТОП-15 книг по Python: от новичка до профессионала

Книги по Python (и связанным с ним специальным темам) на русском языке. Рас...
admin
14 июля 2017

Пишем свою нейросеть: пошаговое руководство

Отличный гайд про нейросеть от теории к практике. Вы узнаете из каких элеме...