← Назад к вопросам
Как меняется 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 по регуляризации
| Параметр | Без регуляризации | Слабая регуляризация | Сильная регуляризация |
|---|---|---|---|
| Alpha | 0 | Умеренно | Высоко |
| 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)
Итоги
При регуляризации:
-
L2 (Ridge): все коэффициенты уменьшаются пропорционально
- Bias ↑ (гибкость ↓)
- Variance ↓ (стабильность ↑)
-
L1 (Lasso): некоторые коэффициенты обнуляются
- Bias ↑ (гибкость ↓)
- Variance ↓ (стабильность ↑)
- Bonus: feature selection
-
Оптимум: находится через Cross-Validation, баланс минимизирует общую ошибку
-
Практика: начни с Ridge, если нужна интерпретируемость → используй Lasso