リッジ回帰(Ridge Regression)は、通常の最小二乗法による重回帰分析にL2正則化項を加えた手法です。多重共線性(説明変数間の高い相関)がある場合や、特徴量の数がサンプル数に比べて多い場合に、過学習を防ぐ効果があります。
本記事では、リッジ回帰の損失関数と解析解の導出、正則化の幾何学的な意味、そしてPythonでの実装を解説します。
本記事の内容
- リッジ回帰の損失関数の定義
- 解析解の導出
- 正則化パラメータの幾何学的意味
- Pythonでの実装と正則化パラメータの影響
前提知識
この記事を読む前に、以下の概念を押さえておくと理解が深まります。
- 重回帰分析の基礎(最小二乗法)
- 行列の微分
リッジ回帰とは
通常の重回帰では、損失関数として残差の二乗和を最小化します。
$$ L_{\text{OLS}}(\bm{w}) = \|\bm{y} – \bm{X}\bm{w}\|^2 = (\bm{y} – \bm{X}\bm{w})^T(\bm{y} – \bm{X}\bm{w}) $$
リッジ回帰では、これにパラメータのL2ノルムの二乗を正則化項として加えます。
$$ L_{\text{Ridge}}(\bm{w}) = \|\bm{y} – \bm{X}\bm{w}\|^2 + \lambda \|\bm{w}\|^2 $$
ここで $\lambda > 0$ は正則化パラメータで、大きいほど正則化が強くなります。
解析解の導出
リッジ回帰の損失関数を展開します。
$$ \begin{align} L(\bm{w}) &= (\bm{y} – \bm{X}\bm{w})^T(\bm{y} – \bm{X}\bm{w}) + \lambda \bm{w}^T\bm{w} \\ &= \bm{y}^T\bm{y} – 2\bm{w}^T\bm{X}^T\bm{y} + \bm{w}^T\bm{X}^T\bm{X}\bm{w} + \lambda \bm{w}^T\bm{w} \end{align} $$
$\bm{w}$ で微分して0とおきます。
$$ \frac{\partial L}{\partial \bm{w}} = -2\bm{X}^T\bm{y} + 2\bm{X}^T\bm{X}\bm{w} + 2\lambda \bm{w} = \bm{0} $$
$$ (\bm{X}^T\bm{X} + \lambda \bm{I})\bm{w} = \bm{X}^T\bm{y} $$
したがって、リッジ回帰の解析解は次のようになります。
$$ \hat{\bm{w}}_{\text{Ridge}} = (\bm{X}^T\bm{X} + \lambda \bm{I})^{-1}\bm{X}^T\bm{y} $$
通常の最小二乗法の解 $\hat{\bm{w}}_{\text{OLS}} = (\bm{X}^T\bm{X})^{-1}\bm{X}^T\bm{y}$ と比較すると、$\lambda \bm{I}$ が加わることで、$\bm{X}^T\bm{X}$ が特異であっても逆行列が計算可能になります。
正則化の幾何学的な意味
正則化項 $\lambda\|\bm{w}\|^2$ を加えることは、パラメータ空間上で以下の制約付き最適化を解くことと等価です。
$$ \min_{\bm{w}} \|\bm{y} – \bm{X}\bm{w}\|^2 \quad \text{subject to} \quad \|\bm{w}\|^2 \leq t $$
すなわち、パラメータ $\bm{w}$ の値が原点の近くに拘束されます。$\lambda$ が大きいほど($t$ が小さいほど)、パラメータは原点に近づき、モデルの複雑さが制限されます。
ベイズ的解釈
リッジ回帰はベイズ推定の観点から解釈することもできます。パラメータに正規分布の事前分布を置いた場合、
$$ \bm{w} \sim \mathcal{N}(\bm{0}, \tau^2 \bm{I}) $$
MAP(Maximum A Posteriori)推定を行うと、$\lambda = \sigma^2 / \tau^2$ としたリッジ回帰の解と一致します。ここで $\sigma^2$ は観測ノイズの分散です。
Pythonでの実装
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error
np.random.seed(42)
# --- データ生成 ---
n_samples = 30
X = np.sort(np.random.uniform(0, 1, n_samples))
y_true = np.sin(2 * np.pi * X)
y = y_true + np.random.randn(n_samples) * 0.3
# 多項式特徴量(10次)
poly = PolynomialFeatures(degree=10, include_bias=True)
X_poly = poly.fit_transform(X.reshape(-1, 1))
# --- リッジ回帰のスクラッチ実装 ---
def ridge_regression(X, y, lam):
"""リッジ回帰の解析解"""
n_features = X.shape[1]
I = np.eye(n_features)
w = np.linalg.solve(X.T @ X + lam * I, X.T @ y)
return w
# --- 正則化パラメータによる比較 ---
lambdas = [0, 1e-6, 1e-3, 1.0]
X_test = np.linspace(0, 1, 200)
X_test_poly = poly.transform(X_test.reshape(-1, 1))
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
for ax, lam in zip(axes.ravel(), lambdas):
w = ridge_regression(X_poly, y, lam)
y_pred = X_test_poly @ w
y_train_pred = X_poly @ w
mse = mean_squared_error(y, y_train_pred)
ax.scatter(X, y, c='red', s=30, zorder=5, label='Data')
ax.plot(X_test, np.sin(2 * np.pi * X_test), 'k--', alpha=0.5, label='True')
ax.plot(X_test, y_pred, 'b-', label='Ridge')
ax.set_title(f'$\\lambda$ = {lam} (MSE = {mse:.4f})')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_ylim(-2, 2)
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
plt.suptitle('Effect of Regularization Parameter', fontsize=14)
plt.tight_layout()
plt.show()
# --- パラメータの大きさの比較 ---
fig, ax = plt.subplots(figsize=(10, 5))
lambdas_range = np.logspace(-8, 2, 50)
w_norms = []
for lam in lambdas_range:
w = ridge_regression(X_poly, y, lam)
w_norms.append(np.linalg.norm(w))
ax.semilogx(lambdas_range, w_norms, 'b-o', markersize=3)
ax.set_xlabel('$\\lambda$ (log scale)')
ax.set_ylabel('$\\|\\mathbf{w}\\|$')
ax.set_title('Parameter Norm vs Regularization Strength')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
$\lambda = 0$ では過学習が起き、$\lambda$ が大きすぎると未学習になることが確認できます。適切な $\lambda$ の選択には交差検証を用いるのが一般的です。
まとめ
本記事では、リッジ回帰の理論と実装について解説しました。
- リッジ回帰は最小二乗法にL2正則化項 $\lambda\|\bm{w}\|^2$ を加えた手法
- 解析解 $\hat{\bm{w}} = (\bm{X}^T\bm{X} + \lambda\bm{I})^{-1}\bm{X}^T\bm{y}$ が存在し、多重共線性にも対応可能
- 正則化パラメータ $\lambda$ はパラメータを原点に近づける制約として機能する
- ベイズ推定の観点ではパラメータに正規分布の事前分布を仮定したMAP推定に対応
次のステップとして、以下の記事も参考にしてください。