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

Как с помощью линейной модели отобрать важные признаки?

1.7 Middle🔥 251 комментариев
#Машинное обучение#Статистика и A/B тестирование

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

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

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

Отбор важных признаков с помощью линейной модели

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

Основной принцип

В линейной модели каждому признаку соответствует коэффициент (вес). Абсолютное значение коэффициента показывает, насколько важен этот признак для предсказания:

y = w0 + w1*x1 + w2*x2 + ... + wn*xn

Где w_i коэффициент признака x_i. Большие |w_i| означают, что признак x_i сильно влияет на предсказание.

Способ 1: Логистическая регрессия для классификации

from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
import numpy as np
import pandas as pd

# Стандартизируем признаки (важно для справедливого сравнения коэффициентов!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_train)

# Обучаем логистическую регрессию
model = LogisticRegression(
    penalty=l2,
    C=1.0,          # Параметр регуляризации
    max_iter=1000,
    random_state=42
)
model.fit(X_scaled, y_train)

# Получаем коэффициенты
coefficients = model.coef_[0]  # Для бинарной классификации

# Создаём DataFrame для визуализации
feature_importance = pd.DataFrame({
    feature: X.columns,
    coefficient: np.abs(coefficients),  # Берём абсолютные значения
    direction: np.sign(coefficients)    # +1 если увеличивает вероятность, -1 если уменьшает
}).sort_values(by=coefficient, ascending=False)

print(feature_importance.head(10))

Способ 2: Ridge и Lasso регрессия

Ridge регрессия (L2) сжимает коэффициенты, но не обнуляет:

from sklearn.linear_model import Ridge, RidgeCV

# Кросс-валидированная выборка параметра регуляризации
ridge_cv = RidgeCV(alphas=np.logspace(-3, 3, 100), cv=5)
ridge_cv.fit(X_scaled, y_train)

print(f"Best alpha: {ridge_cv.alpha_:.4f}")
print(f"R2 score: {ridge_cv.score(X_test_scaled, y_test):.4f}")

# Коэффициенты Ridge
ridge_coefs = ridge_cv.coef_

feature_importance = pd.DataFrame({
    feature: X.columns,
    coefficient: np.abs(ridge_coefs)
}).sort_values(by=coefficient, ascending=False)

Lasso регрессия (L1) обнуляет неважные признаки — идеально для отбора:

from sklearn.linear_model import Lasso, LassoCV

# LassoCV автоматически выбирает оптимальный параметр alpha
lasso_cv = LassoCV(
    alphas=np.logspace(-4, 0, 100),
    cv=5,
    random_state=42
)
lasso_cv.fit(X_scaled, y_train)

print(f"Best alpha: {lasso_cv.alpha_:.4f}")
print(f"Non-zero coefficients: {np.sum(lasso_cv.coef_ != 0)}")
print(f"R2 score: {lasso_cv.score(X_test_scaled, y_test):.4f}")

# Lasso обнуляет неважные признаки
important_features = X.columns[lasso_cv.coef_ != 0]
print(f"Important features: {list(important_features)}")

# Визуализируем
feature_importance = pd.DataFrame({
    feature: X.columns,
    coefficient: np.abs(lasso_cv.coef_)
})[lambda df: df[coefficient] > 0].sort_values(
    by=coefficient,
    ascending=False
)

print(feature_importance)

Способ 3: ElasticNet (комбинация Ridge и Lasso)

Comбинирует преимущества обоих подходов:

from sklearn.linear_model import ElasticNetCV

elastic_cv = ElasticNetCV(
    l1_ratio=np.linspace(0, 1, 11),  # 0 = Ridge, 1 = Lasso
    alphas=np.logspace(-3, 1, 50),
    cv=5,
    random_state=42
)

elastic_cv.fit(X_scaled, y_train)

print(f"Best alpha: {elastic_cv.alpha_:.4f}")
print(f"Best l1_ratio: {elastic_cv.l1_ratio_:.2f}")
print(f"Non-zero coefficients: {np.sum(elastic_cv.coef_ != 0)}")

Способ 4: Пошаговый отбор с помощью RFE

Recursive Feature Elimination с линейной моделью:

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

# Рекурсивно исключаем признаки с наименьшими коэффициентами
rfe = RFE(
    estimator=LogisticRegression(max_iter=1000, random_state=42),
    n_features_to_select=10,  # Выбираем топ 10 признаков
    step=1                     # Исключаем по одному признаку за итерацию
)

rfe.fit(X_scaled, y_train)

# Какие признаки выбраны
selected_features = X.columns[rfe.support_]
print(f"Selected features: {list(selected_features)}")

# Рейтинг признаков (1 = выбран, 2 = исключён второй и т.д.)
feature_ranking = pd.DataFrame({
    feature: X.columns,
    ranking: rfe.ranking_
}).sort_values(by=ranking)

print(feature_ranking)

Способ 5: SelectFromModel

Автоматический отбор признаков на основе порога коэффициентов:

from sklearn.feature_selection import SelectFromModel

# Обучаем модель
lasso = Lasso(alpha=0.01, random_state=42)
lasso.fit(X_scaled, y_train)

# Выбираем признаки с коэффициентами, превышающими порог
selector = SelectFromModel(
    lasso,
    prefit=True,
    threshold=0.01  # Или можно использовать mean, median и т.д.
)

selected_features = X.columns[selector.get_support()]
X_selected = selector.transform(X_scaled)

print(f"Selected {X_selected.shape[1]} features out of {X_scaled.shape[1]}")
print(f"Features: {list(selected_features)}")

Практический пример: предсказание цены дома

import pandas as pd
from sklearn.linear_model import LassoCV
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

# Загружаем данные
df = pd.read_csv(houses.csv)
X = df.drop(columns=[price])
y = df[price]

# Разбиваем на train/test
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Стандартизируем
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Применяем Lasso с кросс-валидацией
lasso_cv = LassoCV(
    alphas=np.logspace(-3, 1, 100),
    cv=5,
    random_state=42
)
lasso_cv.fit(X_train_scaled, y_train)

# Результаты
print(f"Best alpha: {lasso_cv.alpha_:.4f}")
print(f"R2 on train: {lasso_cv.score(X_train_scaled, y_train):.4f}")
print(f"R2 on test: {lasso_cv.score(X_test_scaled, y_test):.4f}")

# Важные признаки
feature_importance = pd.DataFrame({
    feature: X.columns,
    coefficient: np.abs(lasso_cv.coef_),
    original_coefficient: lasso_cv.coef_
}).sort_values(by=coefficient, ascending=False)

print("\nTop 10 important features:")
print(feature_importance.head(10))

# Визуализация
import matplotlib.pyplot as plt

top_n = 15
top_features = feature_importance.head(top_n)

plt.figure(figsize=(10, 6))
plt.barh(range(len(top_features)), top_features[coefficient])
plt.yticks(range(len(top_features)), top_features[feature])
plt.xlabel(Absolute Coefficient)
plt.title(Top Feature Importance (Lasso))
plt.tight_layout()
plt.show()

Сравнение методов отбора

МетодТип отбораСкоростьИнтерпретируемостьКогда использовать
Логистическая регрессияВсе коэффициентыБыстроОтличнаяБазовый анализ
RidgeВсе коэффициентыБыстроХорошаяМультиколлинеарность
LassoОбнуляет признакиБыстроОтличнаяНужен компактный набор
ElasticNetГибридныйБыстроХорошаяКогда L1 и L2 вместе
RFEПошаговыйМедленноХорошаяТочный отбор
SelectFromModelПороговыйБыстроОтличнаяАвтоматический отбор

Лучшие практики

1. ВСЕГДА стандартизируй признаки:

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

2. Используй кросс-валидацию для выбора параметра регуляризации:

lasso_cv = LassoCV(cv=5)
lasso_cv.fit(X_scaled, y)

3. Проверяй результаты на тестовом наборе:

test_score = model.score(X_test_scaled, y_test)

4. Если признаков больше 100, начни с Lasso:

lasso = Lasso(alpha=0.01)
lasso.fit(X_scaled, y)
selected = X.columns[np.abs(lasso.coef_) > 0.001]

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