← Назад к вопросам

Как отсеять лишние признаки при создании модели машинного обучения?

1.0 Junior🔥 201 комментариев
#Машинное обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как отсеять лишние признаки при создании ML-модели

Отбор признаков (Feature Selection) — критический этап, который влияет на качество, скорость и интерпретируемость модели. Разберу все основные методы.

Почему нужно отбирать признаки

  1. Переобучение — лишние признаки добавляют шум
  2. Производительность — меньше признаков = быстрее обучение и inference
  3. Интерпретируемость — модель с 10 важными признаками понятнее, чем с 1000
  4. Затраты на features — если признак дорогой в получении, не включаем его

Метод 1: Filter-based (Статистический анализ)

Удаляем признаки с низкой статистической связью с целевой переменной.

Для классификации — Mutual Information:

from sklearn.feature_selection import mutual_info_classif, SelectKBest
import pandas as pd

# Вычисляем mutual information между каждым признаком и целевой переменной
mi_scores = mutual_info_classif(X, y, random_state=42)

# Выбираем top-10 признаков
selector = SelectKBest(mutual_info_classif, k=10)
X_selected = selector.fit_transform(X, y)

# Смотрим, какие признаки выбрались
selected_features = X.columns[selector.get_support()].tolist()
print(f"Selected features: {selected_features}")

Для регрессии — Корреляция:

# Вычисляем корреляцию с целевой переменной
corr_with_target = X.corr(y).abs()

# Выбираем признаки с корреляцией > 0.1
selected_features = corr_with_target[corr_with_target > 0.1].index.tolist()

# Удаляем мультиколлинеарные признаки (корреляция > 0.95)
corr_matrix = X.corr().abs()
upper_triangle = corr_matrix.where(
    np.triu(np.ones(corr_matrix.shape), k=1).astype(bool)
)
to_drop = [col for col in upper_triangle.columns if any(upper_triangle[col] > 0.95)]
X_cleaned = X.drop(columns=to_drop)

Преимущества:

  • Быстро
  • Не зависит от модели
  • Хорошо работает для начального отбора

Недостатки:

  • Не учитывает взаимодействие признаков
  • Не учитывает нелинейные зависимости

Метод 2: Wrapper-based (Поиск с моделью)

Итеративно выбираем/удаляем признаки на основе качества модели.

Forward Selection (постепенное добавление):

from sklearn.feature_selection import SequentialFeatureSelector
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(n_estimators=100, random_state=42)

# Добавляем признаки по одному
selector = SequentialFeatureSelector(
    model,
    n_features_to_select=10,  # Хотим 10 признаков
    direction='forward'  # Добавляем
)
X_selected = selector.fit_transform(X, y)

# Лучшие признаки
best_features = X.columns[selector.get_support()].tolist()
print(f"Best features: {best_features}")

Backward Elimination (постепенное удаление):

selector = SequentialFeatureSelector(
    model,
    n_features_to_select=10,
    direction='backward'  # Удаляем
)
X_selected = selector.fit_transform(X, y)

Рекурсивное исключение (RFE):

from sklearn.feature_selection import RFE
from sklearn.linear_model import LinearRegression

model = LinearRegression()

# Рекурсивно удаляем самые неважные признаки
rfe = RFE(estimator=model, n_features_to_select=10, step=1)
X_selected = rfe.fit_transform(X, y)

# Ранг важности
print(f"Feature ranking: {rfe.ranking_}")
selected_features = X.columns[rfe.support_].tolist()

Преимущества:

  • Учитывает взаимодействие признаков
  • Работает лучше, чем filter методы

Недостатки:

  • Медленно (нужно переобучать модель много раз)
  • Зависит от выбранной модели

Метод 3: Embedded (Встроенный отбор в модель)

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

Tree-based importance (Decision Tree, Random Forest, XGBoost):

from sklearn.ensemble import RandomForestClassifier
import numpy as np

model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X, y)

# Важность признаков
feature_importance = model.feature_importances_

# Выбираем top-15
top_15_idx = np.argsort(feature_importance)[-15:][::-1]
best_features = X.columns[top_15_idx].tolist()

# Визуализация
import matplotlib.pyplot as plt
plt.barh(X.columns[top_15_idx], feature_importance[top_15_idx])
plt.xlabel('Importance')
plt.show()

Коэффициенты линейной модели:

from sklearn.linear_model import Lasso
from sklearn.preprocessing import StandardScaler

# Нормализуем признаки (важно для Lasso)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Lasso обнуляет малозначимые коэффициенты
lasso = Lasso(alpha=0.01)  # Увеличиваем alpha -> больше нулевых коэффициентов
lasso.fit(X_scaled, y)

# Признаки с ненулевыми коэффициентами
selected_features = X.columns[lasso.coef_ != 0].tolist()
print(f"Selected features: {selected_features}")
print(f"Number of features: {len(selected_features)}")

Permutation Importance (для любой модели):

from sklearn.inspection import permutation_importance

model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)

# Перемешиваем каждый признак и смотрим, насколько упадет качество
result = permutation_importance(
    model, X_test, y_test, 
    n_repeats=10, 
    random_state=42
)

# Признаки с низкой важностью можно удалить
importances = result.importances_mean
selected_idx = np.where(importances > 0.01)[0]
selected_features = X.columns[selected_idx].tolist()

Метод 4: L1-регуляризация (Sparse models)

from sklearn.linear_model import LogisticRegression

# L1 регуляризация обнуляет малозначимые коэффициенты
model = LogisticRegression(
    penalty='l1',
    solver='liblinear',
    C=0.1  # Меньше C = сильнее регуляризация = больше нулей
)
model.fit(X, y)

# Выбираем признаки с ненулевыми коэффициентами
selected_features = X.columns[model.coef_[0] != 0].tolist()
print(f"Selected {len(selected_features)} features")

Практический пример: Комбинированный подход

from sklearn.feature_selection import (
    SelectKBest, f_classif, 
    SequentialFeatureSelector
)
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler

# Шаг 1: Filter — быстрый отбор top-30
filter_selector = SelectKBest(f_classif, k=30)
X_filtered = filter_selector.fit_transform(X, y)
filtered_features = X.columns[filter_selector.get_support()].tolist()
X_filtered = X[filtered_features]

# Шаг 2: Tree importance
rf = RandomForestClassifier(n_estimators=100)
rf.fit(X_filtered, y)
importance_threshold = np.percentile(rf.feature_importances_, 50)
tree_selected_idx = np.where(rf.feature_importances_ > importance_threshold)[0]
X_tree_selected = X_filtered.iloc[:, tree_selected_idx]

# Шаг 3: Forward selection для финализации
model = RandomForestClassifier(n_estimators=100)
selector = SequentialFeatureSelector(
    model, 
    n_features_to_select=15,
    direction='forward'
)
X_final = selector.fit_transform(X_tree_selected, y)

final_features = X_tree_selected.columns[selector.get_support()].tolist()
print(f"Final selected features: {final_features}")

Когда использовать какой метод

МетодКогда использоватьПлюсыМинусы
FilterБольшой датасет, быстрый отборБыстро, простоНе учитывает модель
WrapperСредний датасет, нужна точностьХорошее качествоМедленно, переобучение
EmbeddedЛюбой размерЭффективно, быстроЗависит от модели
L1 регуляризацияЛинейные моделиВстроено в обучениеТолько для линейных

Итоговый чеклист

  1. Удалить очевидный мусор: null/constant признаки
  2. Анализ корреляции: удалить мультиколлинеарные
  3. Статистический отбор: SelectKBest с mutual_info
  4. Модель-зависимый отбор: feature_importances_
  5. Валидация: проверить качество на test set
  6. Итеративное уточнение: если нужно лучше
Как отсеять лишние признаки при создании модели машинного обучения? | PrepBro