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

Как меняется bias и variance при регуляризации в линейной или логистической регрессии?

2.0 Middle🔥 191 комментариев
#Машинное обучение

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

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

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

Как меняется bias и variance при регуляризации в линейной или логистической регрессии

Регуляризация — это инструмент для контроля компромисса между bias (смещение) и variance (дисперсия). Понимание этого компромисса — ключевой навык для Data Scientists.

Теория: Bias-Variance Decomposition

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge, Lasso, LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error

# Генерация данных с истинной моделью
np.random.seed(42)
n_samples = 100
n_features = 20

X = np.random.randn(n_samples, n_features)
# Истинные коэффициенты (спарсивная модель)
true_coef = np.zeros(n_features)
true_coef[:5] = [1.5, -2.0, 0.8, 1.2, -0.5]
y = X @ true_coef + np.random.normal(0, 0.5, n_samples)

# Разделение
X_test = np.random.randn(200, n_features)
y_test = X_test @ true_coef + np.random.normal(0, 0.5, 200)

print(f"True coefficients (non-zero): {true_coef[:5]}")
print(f"Number of true features: {np.sum(true_coef != 0)}")
print(f"Number of total features: {n_features}")
print(f"Overfitting risk: HIGH (features >> important features)")

Без регуляризации (Ridge alpha=0)

from sklearn.linear_model import Ridge

# Обычная линейная регрессия (alpha=0)
model_no_reg = Ridge(alpha=0)
model_no_reg.fit(X, y)

y_pred = model_no_reg.predict(X_test)
mse_no_reg = mean_squared_error(y_test, y_pred)

print(f"\n=== WITHOUT REGULARIZATION (alpha=0) ===")
print(f"MSE on test: {mse_no_reg:.4f}")
print(f"Max coefficient: {np.max(np.abs(model_no_reg.coef_)):.4f}")
print(f"Mean coefficient magnitude: {np.mean(np.abs(model_no_reg.coef_)):.4f}")
print(f"\nCharacteristics:")
print(f"- HIGH VARIANCE: коэффициенты принимают экстремальные значения")
print(f"- LOW BIAS: модель может очень близко подогнать тренировочные данные")
print(f"- Риск: переобучение на шумных признаках")

L2 регуляризация (Ridge)

# Ridge регрессия
alpha_values = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
ridge_results = []

for alpha in alpha_values:
    model = Ridge(alpha=alpha)
    model.fit(X, y)
    y_pred = model.predict(X_test)
    mse = mean_squared_error(y_test, y_pred)
    
    ridge_results.append({
        'alpha': alpha,
        'mse': mse,
        'max_coef': np.max(np.abs(model.coef_)),
        'mean_coef': np.mean(np.abs(model.coef_)),
        'coef_norm': np.linalg.norm(model.coef_)
    })
    
    print(f"\nalpha={alpha}:")
    print(f"  MSE: {mse:.4f}")
    print(f"  Max coef: {ridge_results[-1]['max_coef']:.4f}")
    print(f"  Mean coef: {ridge_results[-1]['mean_coef']:.4f}")
    print(f"  L2 norm: {ridge_results[-1]['coef_norm']:.4f}")

print(f"\n=== RIDGE (L2) REGULARIZATION ===")
print(f"Эффект при УВЕЛИЧЕНИИ alpha:")
print(f"1. Variance УМЕНЬШАЕТСЯ (коэффициенты становятся меньше)")
print(f"2. Bias УВЕЛИЧИВАЕТСЯ (модель менее гибкая)")
print(f"3. L2 norm коэффициентов УМЕНЬШАЕТСЯ")
print(f"4. Все признаки сохраняются (плотное решение)")

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

from sklearn.linear_model import Lasso

# Lasso регрессия
alpha_values = [0.001, 0.01, 0.05, 0.1, 0.5]
lasso_results = []

for alpha in alpha_values:
    model = Lasso(alpha=alpha, max_iter=10000)
    model.fit(X, y)
    y_pred = model.predict(X_test)
    mse = mean_squared_error(y_test, y_pred)
    
    n_nonzero = np.sum(model.coef_ != 0)
    
    lasso_results.append({
        'alpha': alpha,
        'mse': mse,
        'n_nonzero': n_nonzero,
        'max_coef': np.max(np.abs(model.coef_)),
        'l1_norm': np.linalg.norm(model.coef_, ord=1)
    })
    
    print(f"\nalpha={alpha}:")
    print(f"  MSE: {mse:.4f}")
    print(f"  Non-zero coefs: {n_nonzero}/{n_features}")
    print(f"  Max coef: {lasso_results[-1]['max_coef']:.4f}")
    print(f"  L1 norm: {lasso_results[-1]['l1_norm']:.4f}")

print(f"\n=== LASSO (L1) REGULARIZATION ===")
print(f"Эффект при УВЕЛИЧЕНИИ alpha:")
print(f"1. Variance УМЕНЬШАЕТСЯ (коэффициенты становятся меньше)")
print(f"2. Bias УВЕЛИЧИВАЕТСЯ (модель менее гибкая)")
print(f"3. Спарсивность УВЕЛИЧИВАЕТСЯ (коэффициенты обнуляются)")
print(f"4. Feature selection происходит автоматически")

Визуализация компромисса

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 1. Ridge: MSE vs Alpha
alphas_ridge = np.logspace(-3, 2, 100)
mse_ridge = []
for alpha in alphas_ridge:
    model = Ridge(alpha=alpha)
    model.fit(X, y)
    mse = mean_squared_error(y_test, model.predict(X_test))
    mse_ridge.append(mse)

axes[0, 0].plot(alphas_ridge, mse_ridge, 'b-', linewidth=2)
axes[0, 0].set_xscale('log')
axes[0, 0].set_xlabel('Alpha')
axes[0, 0].set_ylabel('MSE')
axes[0, 0].set_title('Ridge: MSE vs Alpha')
axes[0, 0].grid()

# 2. Ridge: Coefficient magnitudes vs Alpha
alphas_for_coef = np.logspace(-3, 2, 50)
coef_norms = []
for alpha in alphas_for_coef:
    model = Ridge(alpha=alpha)
    model.fit(X, y)
    coef_norms.append(np.linalg.norm(model.coef_))

axes[0, 1].plot(alphas_for_coef, coef_norms, 'g-', linewidth=2)
axes[0, 1].set_xscale('log')
axes[0, 1].set_xlabel('Alpha')
axes[0, 1].set_ylabel('L2 Norm of Coefficients')
axes[0, 1].set_title('Ridge: Coefficient Shrinkage')
axes[0, 1].grid()

# 3. Lasso: MSE vs Alpha
alphas_lasso = np.logspace(-3, 0, 50)
mse_lasso = []
for alpha in alphas_lasso:
    model = Lasso(alpha=alpha, max_iter=10000)
    model.fit(X, y)
    mse = mean_squared_error(y_test, model.predict(X_test))
    mse_lasso.append(mse)

axes[1, 0].plot(alphas_lasso, mse_lasso, 'r-', linewidth=2)
axes[1, 0].set_xscale('log')
axes[1, 0].set_xlabel('Alpha')
axes[1, 0].set_ylabel('MSE')
axes[1, 0].set_title('Lasso: MSE vs Alpha')
axes[1, 0].grid()

# 4. Lasso: Feature selection vs Alpha
n_nonzero_lasso = []
for alpha in alphas_lasso:
    model = Lasso(alpha=alpha, max_iter=10000)
    model.fit(X, y)
    n_nonzero_lasso.append(np.sum(model.coef_ != 0))

axes[1, 1].plot(alphas_lasso, n_nonzero_lasso, 'purple', linewidth=2, marker='o')
axes[1, 1].set_xscale('log')
axes[1, 1].set_xlabel('Alpha')
axes[1, 1].set_ylabel('Number of Non-Zero Coefficients')
axes[1, 1].set_title('Lasso: Feature Selection')
axes[1, 1].grid()

plt.tight_layout()
plt.show()

В логистической регрессии

from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
from sklearn.metrics import accuracy_score, roc_auc_score

# Данные с классификацией
X_clf, y_clf = make_classification(
    n_samples=200,
    n_features=50,
    n_informative=10,
    n_redundant=20,
    random_state=42
)

X_train_clf, X_test_clf = X_clf[:150], X_clf[150:]
y_train_clf, y_test_clf = y_clf[:150], y_clf[150:]

# Лог-регрессия с разными C (C = 1/alpha)
C_values = np.logspace(-4, 2, 20)
results_logistic = []

for C in C_values:
    # L2 регуляризация (по умолчанию)
    model_l2 = LogisticRegression(C=C, penalty='l2', solver='lbfgs', max_iter=1000)
    model_l2.fit(X_train_clf, y_train_clf)
    
    train_acc = accuracy_score(y_train_clf, model_l2.predict(X_train_clf))
    test_acc = accuracy_score(y_test_clf, model_l2.predict(X_test_clf))
    
    results_logistic.append({
        'C': C,
        'train_acc': train_acc,
        'test_acc': test_acc,
        'gap': train_acc - test_acc,
        'coef_norm': np.linalg.norm(model_l2.coef_)
    })

print("\n=== LOGISTIC REGRESSION WITH L2 ===")
for r in results_logistic[::4]:  # каждый 4-й результат
    print(f"C={r['C']:.4f}: Train={r['train_acc']:.3f}, Test={r['test_acc']:.3f}, Gap={r['gap']:.3f}")

print(f"\nОбъяснение:")
print(f"- Маленький C = сильная регуляризация (высокий bias, низкая variance)")
print(f"- Большой C = слабая регуляризация (низкий bias, высокая variance)")

Таблица: Bias-Variance по регуляризации

ПараметрБез регуляризацииСлабая регуляризацияСильная регуляризация
Alpha0УмеренноВысоко
BiasНизкийСреднийВысокий
VarianceВысокаяСредняяНизкая
КоэффициентыБольшиеСредниеМаленькие
ПереобучениеВероятноВероятноМенее вероятно
Train errorНизкаяНизкаяВысокая
Test errorВысокаяСредняяМинимальная

Оптимальный выбор регуляризации

from sklearn.model_selection import cross_val_score

def find_optimal_alpha(X, y, alphas):
    """
    Найти оптимальное значение alpha через cross-validation
    """
    cv_scores = []
    
    for alpha in alphas:
        model = Ridge(alpha=alpha)
        scores = cross_val_score(model, X, y, cv=5, scoring='neg_mean_squared_error')
        cv_scores.append(-scores.mean())
    
    optimal_idx = np.argmin(cv_scores)
    optimal_alpha = alphas[optimal_idx]
    
    print(f"Optimal alpha: {optimal_alpha}")
    print(f"CV MSE at optimal: {cv_scores[optimal_idx]:.4f}")
    
    return optimal_alpha, cv_scores

alphas = np.logspace(-3, 3, 50)
optimal_alpha, scores = find_optimal_alpha(X, y, alphas)

Итоги

При регуляризации:

  1. L2 (Ridge): все коэффициенты уменьшаются пропорционально

    • Bias ↑ (гибкость ↓)
    • Variance ↓ (стабильность ↑)
  2. L1 (Lasso): некоторые коэффициенты обнуляются

    • Bias ↑ (гибкость ↓)
    • Variance ↓ (стабильность ↑)
    • Bonus: feature selection
  3. Оптимум: находится через Cross-Validation, баланс минимизирует общую ошибку

  4. Практика: начни с Ridge, если нужна интерпретируемость → используй Lasso