1.13. Отбор признаков (Feature selection)¶
Классы модуля sklearn.feature_selection
могут быть использованы для отбора признаков/сокращения размерности наборов образцов, либо для повышения точности оценок, либо для повышения их производительности на очень высокоразмерных наборах данных.
1.13.1. Удаление признаков с низкой дисперсией¶
VarianceThreshold
- это простой базовый подход к отбору признаков.
Он удаляет все признаки, дисперсия которых не соответствует некоторому порогу.
По умолчанию он удаляет все признаки с нулевой дисперсией, т. е. признаки, которые имеют одинаковое значение во всех выборках.
В качестве примера предположим, что у нас есть набор данных с булевыми признаками, и мы хотим удалить все признаки, которые имеют либо единицу, либо ноль (включены или выключены) в более чем 80 % образцов. Булевы признаки - это случайные величины Бернулли, и дисперсия таких величин определяется как
Поэтому мы можем выбрать порог .8 * (1 - .8)
:
>>> from sklearn.feature_selection import VarianceThreshold
>>> X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
>>> sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
>>> sel.fit_transform(X)
array([[0, 1],
[1, 0],
[0, 0],
[1, 1],
[1, 0],
[1, 1]])
Как и ожидалось, VarianceThreshold
удалил первый столбец, который с вероятностью \(p = 5/6 > .8\) содержит ноль.
1.13.2. Выделение одномерных признаков¶
Одномерный отбор признаков работает путем отбора лучших признаков на основе одномерных статистических тестов.
Его можно рассматривать как шаг предварительной обработки оценки.
Scikit-learn раскрывает процедуры отбора признаков как объекты, реализующие метод transform
:
SelectKBest
удаляет все признаки, кроме \(k\) с наивысшей оценкой.SelectPercentile
удаляет все признаки, кроме заданного пользователем процента признаков, набравших наибольшее количество балловиспользуя общие одномерные статистические тесты для каждого признака: коэффициент ложных срабатываний
SelectFpr
, коэффициент ложных обнаруженийSelectFdr
, или “семейная” ошибкаSelectFwe
.GenericUnivariateSelect
позволяет выполнять отбор одномерных признаков с настраиваемой стратегией. Это позволяет выбрать наилучшую стратегию отбора одномерных признаков с помощью гиперпараметрического поисковой модели.
Например, мы можем использовать F-тест для получения двух лучших признаков для набора данных следующим образом:
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import f_classif
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> X_new = SelectKBest(f_classif, k=2).fit_transform(X, y)
>>> X_new.shape
(150, 2)
Эти объекты принимают на вход функцию оценки, которая возвращает одномерные оценки и p-значения (или только оценки для SelectKBest
и SelectPercentile
):
Для регрессии:
r_regression
,f_regression
,mutual_info_regression
Для классификации:
chi2
,f_classif
,mutual_info_classif
Методы, основанные на F-тесте, оценивают степень линейной зависимости между двумя случайными величинами. С другой стороны, методы взаимной информации могут отразить любой вид статистической зависимости, но, будучи непараметрическими, они требуют больше образцов для точной оценки. Обратите внимание, что \(\chi^2\)-тест следует применять только к неотрицательным признакам, таким как частоты.
Предупреждение
Остерегайтесь использовать функцию оценки регрессии в задаче классификации - вы получите бесполезные результаты.
Примечание
Функции SelectPercentile
и SelectKBest
также поддерживают неконтролируемый отбор признаков. Необходимо предоставить score_func
, где y=None
. Для вычисления оценок score_func
должен использовать внутреннее значение X
.
1.13.3. Рекурсивное исключение признаков¶
При наличии внешней модели, присваивающего веса признакам (например, коэффициентам линейной модели), целью рекурсивного исключения признаков (RFE
) является выбор признаков путем рекурсивного рассмотрения всё меньших и меньших наборов признаков.
Сначала оценочный механизм обучается на начальном наборе признаков, и важность каждого признака определяется либо через какой-либо специфический атрибут (например, coef_
, feature_importances_
), либо через вызываемый признак.
Затем из текущего набора признаков отсекаются наименее важные.
Эта процедура рекурсивно повторяется для обрезанного набора, пока в конечном итоге не будет достигнуто желаемое количество признаков для выбора.
RFECV
выполняет RFE в цикле кросс-валидации для поиска оптимального числа признаков.
Более подробно, количество выбираемых признаков настраивается автоматически путем подгонки селектора RFE
к различным разбиениям кросс-валидации (задается параметром cv
).
Эффективность селектора RFE
оценивается с помощью scorer
для разного количества отобранных признаков и суммируется.
Наконец, оценки усредняются по фолдам, а число выбранных признаков устанавливается равным числу признаков, максимизирующих результат кросс-валидации.
1.13.4. Выбор признаков с помощью SelectFromModel¶
SelectFromModel
- это мета-трансформатор, который может использоваться вместе с любой модели, присваивающим важность каждому признаку через определенный атрибут (например, coef_
, feature_importances_
) или через importance_getter
, вызываемый после обучения.
Признаки считаются неважными и удаляются, если соответствующие значения важности признаков ниже заданного параметра threshold
(порога).
Помимо численного задания порога, существуют встроенные эвристики для поиска порога по строковому аргументу.
Доступны следующие эвристики: среднее
, медиана
и кратные им плавающие значения, например 0.1 * среднее
.
В сочетании с критерием threshold
можно использовать параметр max_features
, чтобы установить ограничение на количество выбираемых признаков.
Примеры использования этого параметра приведены в следующих разделах.
1.13.4.1. Выбор функций на основе L1¶
Линейные модели, с нормой L1, имеют разреженные решения: многие из их оценочных коэффициентов равны нулю. Когда целью является снижение размерности данных для использования с другим классификатором, их можно использовать вместе с SelectFromModel
для выбора ненулевых коэффициентов. В частности, для этой цели полезны разреженные модели Lasso
для регрессии, а также LogisticRegression
и LinearSVC
для классификации:
>>> from sklearn.svm import LinearSVC
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X, y)
>>> model = SelectFromModel(lsvc, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 3)
Для SVM и логистической регрессии параметр C
управляет разреженностью: чем меньше C
, тем меньше признаков выбирается. В Lasso чем выше параметр alpha
, тем меньше признаков отбирается.
При хорошем выборе альфа-параметра Лассо (Lasso) может полностью восстановить точный набор ненулевых переменных, используя всего несколько наблюдений, при соблюдении определенных условий. В частности, количество выборок должно быть “достаточно большим”, иначе модели L1 будут работать произвольно, где “достаточно большое” зависит от количества ненулевых коэффициентов, логарифма количества признаков, количества шума, наименьшего абсолютного значения ненулевых коэффициентов и структуры матрицы проектирования X. Кроме того, матрица проектирования должна обладать определенными свойствами, например, не быть слишком коррелированной. Не существует общего правила для выбора параметра альфа для восстановления ненулевых коэффициентов.
Его можно установить с помощью кросс-валидации (
L1-восстановление и сжатие измерений (compressive sensing)
Click for more details
¶
LassoCV
или LassoLarsCV
), хотя это может привести к недооценке моделей: включение небольшого числа нерелевантных переменных не вредит результату предсказания.
BIC (LassoLarsIC
), наоборот, склонен устанавливать высокие значения alpha.
1.13.4.2. Выбор признаков на основе деревьев¶
Оценки на основе деревьев (см. модуль sklearn.tree
и лес деревьев в модуле sklearn.ensemble
) могут использоваться для вычисления импорта признаков на основе примесей, которые в свою очередь могут использоваться для отбрасывания нерелевантных признаков (в сочетании с мета-преобразователем SelectFromModel
):
>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> clf = ExtraTreesClassifier(n_estimators=50)
>>> clf = clf.fit(X, y)
>>> clf.feature_importances_
array([ 0.04..., 0.05..., 0.4..., 0.4...])
>>> model = SelectFromModel(clf, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 2)
1.13.5. Последовательный выбор признаков¶
Последовательный выбор признаков (Sequential Feature Selection) [sfs] (SFS) доступен в трансформаторе SequentialFeatureSelector
. SFS может быть как прямым (Forward-SFS), так и обратным (Backward-SFS):
Forward-SFS - это жадная процедура, которая итеративно находит лучший новый признак для добавления к набору отобранных признаков.
Конкретно, мы начинаем с нуля признаков и находим один признак, который максимизирует кросс-валидированную оценку при обучении модели на этом единственном признаке.
После того как первый признак выбран, мы повторяем процедуру, добавляя новый признак в набор отобранных признаков.
Процедура останавливается при достижении желаемого количества отобранных признаков, определяемого параметром n_features_to_select
.
Backward-SFS следует той же идее, но работает в обратном направлении: вместо того чтобы начинать с отсутствия признаков и жадно добавлять их, мы начинаем со всех признаков и жадно удаляем признаки из набора.
Параметр direction
управляет тем, используется ли прямой или обратный SFS.
В общем случае прямой и обратный отбор не дают эквивалентных результатов.
Кроме того, один из них может быть намного быстрее другого в зависимости от запрашиваемого количества отобранных признаков: если у нас есть 10 признаков и мы просим отобрать 7 признаков, прямой отбор должен выполнить 7 итераций, в то время как обратный отбор должен выполнить только 3. SFS отличается от
Детали последовательного выбора признаков
Click for more details
¶
RFE
и SelectFromModel
тем, что не требует от базовой модели атрибутов coef_
или feature_importances_
.
Однако он может быть медленнее, учитывая, что необходимо оценить больше моделей, по сравнению с другими подходами.
Например, при обратном отборе итерация от m
признаков к m - 1
признакам с использованием k-кратной кросс-валидации требует обучение m * k
моделей, тогда как RFE
требует только одного обучения, а SelectFromModel
всегда делает только одно обучение и не требует итераций.
1.13.6. Выбор признаков как часть конвейера¶
Выбор признаков обычно используется в качестве этапа предварительной обработки перед выполнением фактического обучения.
Рекомендуемый способ сделать это в scikit-learn - использовать Pipeline
:
clf = Pipeline([
('feature_selection', SelectFromModel(LinearSVC(dual="auto", penalty="l1"))),
('classification', RandomForestClassifier())
])
clf.fit(X, y)
В этом фрагменте мы используем LinearSVC
в сочетании с SelectFromModel
для оценки импорта признаков и выбора наиболее релевантных признаков.
Затем на преобразованном выходе, т.е. с использованием только релевантных признаков, обучается классификатор RandomForestClassifier
.
Аналогичные операции можно выполнять и с другими методами отбора признаков, а также с классификаторами, которые, разумеется, предоставляют возможность оценить значимость признаков.
Подробнее см. примеры Pipeline
.