Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Ridge回帰

モデル

リッジ回帰(ridge regression)は誤差関数に正則化項を追加した線形回帰モデルである。

モデル自体は線形回帰と同様で目的変数yyをパラメータβ=(β1,β2,...,βd)\boldsymbol{\beta}=(\beta_1, \beta_2, ..., \beta_d)^\topと特徴量x=(x1,x2,...,xd)\boldsymbol{x}=(x_1, x_2, ..., x_d)^\topの線形関数と誤差ε\varepsilonで表現するものになる。

y=β0+β1x1++βdxd+εy = \beta_0 + \beta_1 x_1 + \cdots + \beta_d x_d + \varepsilon

サンプルサイズがnnのデータセット{xi,yi}i=1n\{\boldsymbol{x}_i, y_i\}^n_{i=1}があるとして、目的変数をy=(y1,y2,...,yn)\boldsymbol{y} = (y_1, y_2, ..., y_n)^\top、特徴量をX=(x1,x2,...,xn)\boldsymbol{X}=(\boldsymbol{x}_1, \boldsymbol{x}_2, ..., \boldsymbol{x}_n)^\topとおくと

y=Xβ+ε\boldsymbol{y}=\boldsymbol{X} \boldsymbol{\beta}+\boldsymbol{\varepsilon}

と表記することもできる。

パラメータの推定

制約付き最小化問題

リッジ回帰が線形回帰と違う点は、パラメータの推定(誤差関数の最小化)に関して制約条件があること。

線形回帰は目的変数の実測値yiy_iと予測値y^i=j=1dxijβj\hat{y}_i=\sum^d_{j=1} x_{ij} \beta_jの誤差二乗和SSE=i=1n(yiy^i)2SSE=\sum^n_{i=1} (y_i - \hat{y}_i)^2を最小にするパラメータを求めるものであった。

\newcommand{\argmin} attempting to redefine \argmin; use \renewcommand

\newcommand{\argmin}{\mathop{\rm arg~min}\limits}
\hat{\boldsymbol{\beta}}^{\text{LS}} = \argmin_{\boldsymbol{\beta}}
\sum^n_{i=1} (y_i - \hat{y}_i)^2

リッジ回帰はこれに「パラメータβj\beta_jの二乗和がある値RR以下である」という制約条件が付いた下でパラメータを推定する。

\newcommand{\argmin} attempting to redefine \argmin; use \renewcommand

\newcommand{\argmin}{\mathop{\rm arg~min}\limits}
\begin{align}
\hat{\boldsymbol{\beta}}^{\text{Ridge}} = \text{ } 
& \argmin_{\boldsymbol{\beta}} \sum^n_{i=1} (y_i - \hat{y}_i)^2
\\
& \text{subject to } \sum^d_{i=1} \beta_j^2 \leq R
\end{align}

この制約条件は円の方程式と呼ばれるもので、2次元で描くと円の形になる。円の範囲内で誤差を最小化するパラメータを選ぶという条件付き最適化問題を解くことになる。

この問題を解くために、ラグランジュの未定乗数法を利用する。

Source
# 二乗和が円になるイメージ
import numpy as np
import matplotlib.pyplot as plt
import itertools

R = 0.5
b1 = np.linspace(-1, 1, 300)
b2 = np.linspace(-1, 1, 300)
b = np.array(list(itertools.product(b1, b2)))
is_in_R = (b[:, 0]**2 + b[:, 1]**2) <= R

fig, ax = plt.subplots(figsize=[4, 4])
ax.scatter(b[is_in_R, 0], b[is_in_R, 1], color="lightblue", label=r"$\beta_1^2 + \beta_2^2 \leq 0.5$")
ax.axvline(color="black", linewidth=1)
ax.axhline(color="black", linewidth=1)
ax.set(xlabel=r"$\beta_1$", ylabel=r"$\beta_2$", xlim=(-1,1), ylim=(-1,1))
ax.legend()
fig.show()
Output
<Figure size 400x400 with 1 Axes>

誤差関数の整理

ラグランジュの未定乗数法を利用して、誤差関数を以下のように書くことができる。

J(β)=i=1n(yiy^i)2+λj=1dβj2J({\boldsymbol{\beta}}) = \sum_{i=1}^n(y_i - \hat{y}_i)^2 + \lambda \sum_{j=1}^d \beta_j^2

この右辺第二項は正則化項λ\lambda正則化パラメータと呼ばれる。λ=0\lambda=0のときは最小二乗法と同じ誤差関数になり、得られる推定量も最小二乗推定量と等しくなる。

一般的なラグランジュ双対問題とは異なり、リッジ回帰では最適なλ\lambdaを推定することはせず、あらかじめλ\lambdaを指定してxxを推定する。(誤差を最小にするλ\lambdaはゼロであり、正則化の意味がなくなるためだと思われる。)

また、最初の制約問題で登場したRRは誤差関数に含めない(おそらく誤差関数をβ\betaについて微分したときに定数項のRRは消えて特に影響をもたらさないため)

ちなみに行列表記するとこんな感じに表される。

J(β)=i=1n(yiy^i)2+λj=1dβj2=yXβ22+λβ22=(yXβ)(yXβ)+λββ\begin{align} J({\boldsymbol{\beta}}) &= \sum_{i=1}^n(y_i - \hat{y}_i)^2 + \lambda \sum_{j=1}^d \beta_j^2 \\ &= \| \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\beta}\|^2_2 + \lambda\| \boldsymbol{\beta}\|^2_2 \\ &= (\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\beta})^\top (\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\beta}) + \lambda \boldsymbol{\beta}^\top \boldsymbol{\beta} \end{align}

リッジ回帰の推定量β^Ridge\hat{\boldsymbol{\beta}}^{\text{Ridge}}は解析的に解くことができ、

J(β)=(yXβ)(yXβ)+λββ=yyyXβ(Xβ)y+(Xβ)(Xβ)+λββ=yy2βXy+βXXβ+λββ\begin{align} J(\boldsymbol{\beta}) &= (\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\beta})^\top (\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\beta}) + \lambda \boldsymbol{\beta}^\top \boldsymbol{\beta} \\ &= \boldsymbol{y}^\top \boldsymbol{y} - \boldsymbol{y}^\top \boldsymbol{X}\boldsymbol{\beta} - (\boldsymbol{X}\boldsymbol{\beta})^\top \boldsymbol{y} + (\boldsymbol{X}\boldsymbol{\beta})^\top (\boldsymbol{X}\boldsymbol{\beta}) + \lambda \boldsymbol{\beta}^\top \boldsymbol{\beta} \\ &= \boldsymbol{y}^\top \boldsymbol{y} - 2 \boldsymbol{\beta}^\top \boldsymbol{X}^\top \boldsymbol{y} + \boldsymbol{\beta}^\top \boldsymbol{X}^\top \boldsymbol{X} \boldsymbol{\beta} + \lambda \boldsymbol{\beta}^\top \boldsymbol{\beta} \end{align}

なので、誤差関数の傾きがゼロ(誤差が最小値)の点を求めると

J(β)β=2Xy+2(XX)β+2λβ=0(XX)β+λβ=Xy(XX+λI)β=Xy\frac{\partial J(\boldsymbol{\beta})}{\partial \boldsymbol{\beta}} = -2\boldsymbol{X}^\top\boldsymbol{y} + 2(\boldsymbol{X}^\top\boldsymbol{X})\boldsymbol{\beta} + 2\lambda\boldsymbol{\beta} =\boldsymbol{0} \\ \Longrightarrow (\boldsymbol{X}^\top\boldsymbol{X})\boldsymbol{\beta} + \lambda\boldsymbol{\beta} =\boldsymbol{X}^\top\boldsymbol{y} \\ \Longrightarrow (\boldsymbol{X}^\top\boldsymbol{X} + \lambda \boldsymbol{I})\boldsymbol{\beta} =\boldsymbol{X}^\top\boldsymbol{y}

となり、

β^Ridge=(XX+λI)1Xy\hat{\boldsymbol{\beta}}^{\text{Ridge}} = (\boldsymbol{X}^\top \boldsymbol{X} + \lambda \boldsymbol{I})^{-1} \boldsymbol{X}^\top \boldsymbol{y}

となる。

リッジ回帰の特徴

リッジ回帰は制約をかけたことにより通常の線形回帰(最小二乗法)とは異なる特徴をもっている。

正則化

線形回帰の最小二乗推定量β^LS\hat{\boldsymbol{\beta}}^{\text{LS}}は次のようなものだった。

β^LS=(XX)1Xy\hat{\boldsymbol{\beta}}^{\text{LS}} = (\boldsymbol{X}^\top \boldsymbol{X})^{-1} \boldsymbol{X}^\top \boldsymbol{y}

このとき、

  1. X\boldsymbol{X}の列数が行数よりも多い(サンプルサイズより特徴量の次元数のほうが多い)

  2. 特徴量間の相関が非常に強い

といった状況においては、XX\boldsymbol{X}^\top \boldsymbol{X}が正則でなくなって逆行列が計算できなくなったり、あるいは推定が不安定になることがある。

そこでリッジ回帰の推定量β^Ridge\hat{\boldsymbol{\beta}}^{\text{Ridge}}では

β^Ridge=(XX+λI)1Xy\hat{\boldsymbol{\beta}}^{\text{Ridge}} = (\boldsymbol{X}^\top \boldsymbol{X} + \lambda \boldsymbol{I})^{-1} \boldsymbol{X}^\top \boldsymbol{y}

と、XX\boldsymbol{X}^\top \boldsymbol{X}の対角成分にλ\lambdaを足すことで尾根(ridge)を作り、正則にすることで逆行列が計算できるようにしている。

過学習の抑制

リッジ回帰の誤差関数

J(β)=i=1n(yiy^i)2+λj=1dβj2J(\beta)= \sum_{i=1}^n(y_i - \hat{y}_i)^2 + \lambda \sum_{j=1}^d \beta_j^2

は、λ\lambdaを大きくすると誤差に占める第二項の比重が大きくなり、パラメータβj\beta_jの値をゼロに向けて縮小(shrink)させる。

パラメータが学習データに過学習して大きい値になっているような状況ではパラメータをうまく縮小させることによって過学習を抑制してモデルの汎化誤差を下げることができる。

OLS推定量との関係

A:=XX\boldsymbol{A}:=\boldsymbol{X}^\top \boldsymbol{X}とおくと

β^Ridge=(XX+λI)1Xy=(A+λI)1Xy\begin{aligned} \hat{\boldsymbol{\beta}}^{\text{Ridge}} &= (\boldsymbol{X}^\top \boldsymbol{X} + \lambda \boldsymbol{I})^{-1} \boldsymbol{X}^\top \boldsymbol{y}\\ &= (\boldsymbol{A} + \lambda \boldsymbol{I})^{-1} \boldsymbol{X}^\top \boldsymbol{y}\\ \end{aligned}

となる。このとき

A+λI=A(I+λA1)\boldsymbol{A} + \lambda \boldsymbol{I} = \boldsymbol{A} (\boldsymbol{I} + \lambda \boldsymbol{A}^{-1})

であり、この逆行列をとると(AB)1=B1A1(AB)^{-1}=B^{-1}A^{-1}より

(A+λI)1=[A(I+λA1)]1=(I+λA1)1A1(\boldsymbol{A} + \lambda \boldsymbol{I})^{-1} = [\boldsymbol{A} (\boldsymbol{I} + \lambda \boldsymbol{A}^{-1})]^{-1} = (\boldsymbol{I} + \lambda \boldsymbol{A}^{-1})^{-1} \boldsymbol{A}^{-1}

よって

β^Ridge=(I+λA1)1A1Xy=[I+λ(XX)1]1(XX)1Xy=[I+λ(XX)1]1β^OLS=Zβ^OLS\begin{aligned} \hat{\boldsymbol{\beta}}^{\text{Ridge}} &= (\boldsymbol{I} + \lambda \boldsymbol{A}^{-1})^{-1} \boldsymbol{A}^{-1} \boldsymbol{X}^\top \boldsymbol{y} \\ &= [\boldsymbol{I} + \lambda (\boldsymbol{X}^\top \boldsymbol{X})^{-1}]^{-1} (\boldsymbol{X}^\top \boldsymbol{X})^{-1} \boldsymbol{X}^\top \boldsymbol{y} \\ &= [\boldsymbol{I} + \lambda (\boldsymbol{X}^\top \boldsymbol{X})^{-1}]^{-1} \hat{\boldsymbol{\beta}}^{\text{OLS}} \\ &= \boldsymbol{Z} \hat{\boldsymbol{\beta}}^{\text{OLS}} \end{aligned}

と変形することができる。ここで

Z:=[I+λ(XX)1]1\boldsymbol{Z} := [\boldsymbol{I} + \lambda (\boldsymbol{X}^\top \boldsymbol{X})^{-1}]^{-1}

とおいた。つまりRidge推定量はOLS推定量をZZで変換したもの。

なおλ=0\lambda=0のときにRidge推定量とOLS推定量が一致することは以下のようにわかる。

β^Ridge=[I+λ(XX)1=0]1β^OLS=I1β^OLS=β^OLS(I1=I)\begin{aligned} \hat{\boldsymbol{\beta}}^{\text{Ridge}} &= [\boldsymbol{I} + \underbrace{ \lambda (\boldsymbol{X}^\top \boldsymbol{X})^{-1} }_{=0} ]^{-1} \hat{\boldsymbol{\beta}}^{\text{OLS}} \\ &= \boldsymbol{I}^{-1} \hat{\boldsymbol{\beta}}^{\text{OLS}} \\ &= \hat{\boldsymbol{\beta}}^{\text{OLS}} \quad (\because I^{-1} = I)\\ \end{aligned}

推定量のバイアスとバリアンス

正則化しない通常の最小二乗推定量はBLUE(最良線形不偏推定量:線形不偏推定量のなかでバリアンスが最小)だった。 リッジ回帰やlassoの推定量は不偏ではない(バイアスがある)推定量であるが、最小二乗推定量よりも小さなバリアンスとなる可能性がある。 そのため、最小二乗推定法を使用する線形回帰よりもリッジ回帰のほうが予測の2乗誤差を小さくする可能性がある。

バイアス・バリアンスのトレードオフ

Ridge推定量のバイアスとバリアンスは次のようになっている(鈴木 (2018)

Bias=λ2(XX+λI)1β2Variance=σ2Tr[(XX+λI)2XX]\begin{aligned} \mathrm{Bias} &= \lambda^2 \| ( X^\top X + \lambda I)^{-1} \boldsymbol{\beta} \|^2 \\ \mathrm{Variance} &= \sigma^2 \operatorname{Tr}\left[\left(X^{\top} X+\lambda I\right)^{-2} X^{\top} X\right] \end{aligned}

これらにはトレードオフの関係がある。

(1) λ0\lambda \to 0のとき(OLSに近づくとき)、Bias0,Varianceσ2Tr[(XX)1]\mathrm{Bias}\to 0, \mathrm{Variance} \to \sigma^2 \operatorname{Tr}[(X^{\top} X)^{-1}]となる。

limλ0Bias=0×(XX)1β20limλ0Variance=σ2Tr[(XX)2XX]=σ2Tr[(XX)1]\begin{aligned} \lim_{\lambda \to 0} \mathrm{Bias} &= 0 \times \| ( X^\top X )^{-1} \boldsymbol{\beta} \|^2 \to 0\\ \lim_{\lambda \to 0} \mathrm{Variance} &= \sigma^2 \operatorname{Tr}\left[(X^{\top} X)^{-2} X^{\top} X\right] = \sigma^2 \operatorname{Tr}[(X^{\top} X)^{-1}] \end{aligned}

(2) λ\lambda \to \inftyのとき、Biasβ2,Variance0\mathrm{Bias} \to \|\beta\|^2, \mathrm{Variance} \to 0となる。

Biasについては、 (XX+λI)1=λ1(I+1λXX)1\left(X^{\top} X+\lambda I\right)^{-1}=\lambda^{-1}\left(I+\frac{1}{\lambda} X^{\top} X\right)^{-1} となることとノルムの斉次性 cx2=c2x2\| c \boldsymbol{x} \|^2 = c^2 \| \boldsymbol{x} \|^2を用いると

λ2(XX+λI)1β2=λ2λ1(I+1λXX)1β2=(I+1λXX)1β2\begin{aligned} \lambda^2\left\|\left(X^{\top} X+\lambda I\right)^{-1} \beta\right\|^2 =\lambda^2\left\|\lambda^{-1}\left(I+\frac{1}{\lambda} X^{\top} X\right)^{-1} \beta\right\|^2 =\left\|\left(I+\frac{1}{\lambda} X^{\top} X\right)^{-1} \beta\right\|^2 \end{aligned}

となる。

ここでλ\lambda \to \inftyなので、 (I+1λXX)1β2\left\|\left(I+\frac{1}{\lambda} X^{\top} X\right)^{-1} \beta\right\|^21λXX0\frac{1}{\lambda} X^{\top} X \to 0 となり、I1=II^{-1} = Iのため

limλBias=(I+1λXX)1β2=I1β2(1λXX0)=β2(I1=I)\begin{aligned} \lim_{\lambda \to \infty} \mathrm{Bias} &= \left\|\left(I + \frac{1}{\lambda} X^{\top} X \right)^{-1} \beta\right\|^2 \\ &= \left\|I^{-1} \beta\right\|^2 \quad (\because \frac{1}{\lambda} X^{\top} X \to 0 ) \\ &= \left\| \beta \right\|^2 \quad (\because I^{-1} = I) \end{aligned}

Variance σ2Tr[(XX+λI)2XX]\sigma^2 \operatorname{Tr}\left[\left(X^{\top} X+\lambda I\right)^{-2} X^{\top} X\right] については、

(XX+λI)2=λ2(I+1λXX)2(X^{\top} X +\lambda I)^{-2} =\lambda^{-2}\left(I+\frac{1}{\lambda} X^{\top} X \right)^{-2}

であり、 (I+1λXX)2\left(I+\frac{1}{\lambda} X^{\top} X \right)^{-2}λ\lambda \to \inftyIIになるため

limλVariance=σ2Tr[λ2XX]=λ2σ2Tr[XX]=1λ2σ2Tr[XX]=0\begin{aligned} \lim_{\lambda \to \infty} \mathrm{Variance} &= \sigma^2 \operatorname{Tr}\left[\lambda ^{-2} X^{\top} X\right]\\ &= \lambda^{-2} \cdot \sigma^2 \operatorname{Tr}\left[X^{\top} X\right]\\ &= \frac{1}{\lambda^{2}} \cdot \sigma^2 \operatorname{Tr}\left[X^{\top} X\right]\\ &= 0 \end{aligned}

バリアンス

Var(β^Ridge)=σ2(XX+λI)1XX(XX+λI)1σ2(XX)1=Var(β^LS)\begin{aligned} \operatorname{Var}(\hat{\beta}^{\text{Ridge}}) &= \sigma^2 (X^\top X + \lambda I)^{-1} X^\top X(X^\top X + \lambda I)^{-1}\\ &\leq \sigma^2 (X^\top X)^{-1} = \operatorname{Var}(\hat{\beta}^{\text{LS}}) \end{aligned}

https://hastie.su.domains/StatLearnSparsity_files/SLS.pdf

証明

C:=(XX)1XC := (X^\top X)^{-1} X^\topとおけば

C=[(XX)1X]=X[(XX)1]((AB)=BA)=X[(XX)]1((A1)=(A)1)=X(XX)1((XX)=XX)\begin{aligned} C^\top = [(X^\top X)^{-1} X^\top]^\top &= X [(X^\top X)^{-1}]^\top \quad (\because (AB)^\top = B^\top A^\top) \\ &= X [(X^\top X)^\top]^{-1} \quad (\because (A^{-1})^\top = (A^\top)^{-1} ) \\ &= X (X^\top X)^{-1} \quad (\because (X^\top X)^\top=X^\top X ) \\ \end{aligned}

であるため、uN(0,σ2I)u\sim N(0, \sigma^2 I) の仮定が満たされるとき、

β+CuN(β,σ2CC)=β+(XX)1XuN(β,σ2(XX)1XX(XX)1)=β+(XX)1XuN(β,σ2(XX)1)\begin{aligned} &\beta + C u \sim N(\beta, \sigma^2 CC^\top)\\ &= \beta + (X^\top X)^{-1} X^\top u \sim N(\beta, \sigma^2 (X^\top X)^{-1} X^\top X (X^\top X)^{-1} )\\ &= \beta + (X^\top X)^{-1} X^\top u \sim N(\beta, \sigma^2 (X^\top X)^{-1}) \end{aligned}

モンテカルロ・シミュレーション

多項式をつかったデータに、多項式回帰をfittingしてみる

y=β0+β1x+β2x2+uy = \beta_0 + \beta_1 x + \beta_2 x^2 + u
import numpy as np
beta = np.array([3, 2, 1])

def gen_data(seed=0, n=500):
    np.random.seed(seed)
    x = np.random.uniform(-5, 3, size=n)
    X = np.array([np.ones(n), x, x**2]).T
    u = np.random.normal(scale=3, size=n)
    y = X @ beta + u
    return X, y

import matplotlib.pyplot as plt
X, y = gen_data(seed=0, n=30)
plt.scatter(X[:, 1], y)
<Figure size 640x480 with 1 Axes>
Source
class OLS:
    def fit(self, X, y):
        self.beta_ = np.linalg.inv(X.T @ X) @ X.T @ y
        return self

    def predict(self, X):
        return X @ self.beta_


class Ridge:
    def __init__(self, lamb = 0.1):
        self.lambda_ = lamb

    def fit(self, X, y):
        d = X.shape[1]
        I = np.ones((d, d))
        self.beta_ = np.linalg.inv((X.T @ X) + self.lambda_ * I) @ X.T @ y
        return self

    def predict(self, X):
        return X @ self.beta_


from sklearn.metrics import mean_squared_error

results = []
for i in range(500):
    result = {}
    X_train, y_train = gen_data(seed=i, n=30)
    X_test, y_test = gen_data(seed=i+1, n=100)

    reg = OLS().fit(X_train, y_train)
    y_pred = reg.predict(X_test)
    result["ols_beta"] = reg.beta_[1]
    result["ols_error"] = mean_squared_error(y_test, y_pred)
    
    reg = Ridge(lamb=1).fit(X_train, y_train)
    y_pred = reg.predict(X_test)
    result["ridge_beta"] = reg.beta_[1]
    result["ridge_error"] = mean_squared_error(y_test, y_pred)

    results.append(result)

import pandas as pd
results = pd.DataFrame(results)
print(f"""
beta1

bias:
- ols: {beta[1] - results["ols_beta"].mean():.3f}
- ridge: {beta[1] - results["ridge_beta"].mean():.3f}

variance:
- ols: {results["ols_beta"].var():.3f}
- ridge: {results["ridge_beta"].var():.3f}
""")

beta1

bias:
- ols: -0.026
- ridge: 0.038

variance:
- ols: 0.115
- ridge: 0.110

ridgeのほうがvarianceが若干小さくbiasが大きくなっている

Source
fig, ax = plt.subplots()
ax.hist(beta[1] - results["ols_beta"], label="OLS", alpha=0.5, bins=20)
ax.hist(beta[1] - results["ridge_beta"], label="Ridge", alpha=0.5, bins=20)
ax.axvline(beta[1] - results["ols_beta"].mean(), label="Bias(OLS)", color="steelblue")
ax.axvline(beta[1] - results["ridge_beta"].mean(), label="Bias(Ridge)", color="darkorange")
ax.legend()
ax.set(xlabel=r"$\beta_1 - \hat\beta_1$", ylabel="Frequency")
fig.show()
<Figure size 640x480 with 1 Axes>
fig, ax = plt.subplots()
ax.hist(results["ols_error"], label="OLS", alpha=0.5, bins=20)
ax.hist(results["ridge_error"], label="Ridge", alpha=0.5, bins=20)
ax.axvline(results["ols_error"].mean(), label="Mean(OLS)", color="steelblue")
ax.axvline(results["ridge_error"].mean(), label="Mean(Ridge)", color="darkorange")
ax.legend()
ax.set(xlabel="Mean Squared Error", ylabel="Frequency")
fig.show()
<Figure size 640x480 with 1 Axes>