リッジ回帰のパラメータの大きさの計算と、λを変化させたときの結果の変化
この記事は何?
リッジ回帰は、正則化項としてパラメータの大きさの項を足したものです。 ただ自分の場合は、「パラメータの大きさって具体的に何?🤔」とか、「パラメータが変化すると、回帰直線にどんな影響を与えるの?🤔」とか気になったので、簡単な実験をしました。
今回の内容は、「機械学習のエッセンス 第05章 03 リッジ回帰」を非常に参考にしています。
機械学習のエッセンス -実装しながら学ぶPython,数学,アルゴリズム- (Machine Learning) | 加藤 公一 |本 | 通販 | Amazon
3行で
- 2次元において、リッジ回帰のパラメータの計算を行った。
- を変化させた時に、リッジ回帰のフィッティングがどう変化するかをグラフで示した。
- が大きくなると、リッジ回帰の傾きが小さくなる。
前提
リッジ回帰は下記の関数を最小化するようなを決定します。
- : 入力データ
- : 出力データ
- : パラメータ
- : の大きさをどのぐらい重視するかのハイパーパラメータ
線形回帰に対し、第二項目が加わり、がパラメータの大きさを考慮するようになっています。
パラメータの大きさって具体的に何?🤔
簡単のため、今回は2次元に絞った話をします。
(1)式のを見ると、はの係数となっており、どうやら回帰直線の傾きのようだと分かります。
また、は を重視する具合を決めるハイパーパラメータのようです。
理解を深めるため、例えば、=1のとき、入力点に対し、どのような計算を行うのか確認しましょう。
まずはをグラフ上にプロットします。
次に、sklearn.linear_model.Ridgeでfittingを行います。理解のためにbias項は省いています。そのため、必ず原点を通るという条件でのfittingになります。
リッジ回帰の結果は上図のようになりました。
この時、どのような計算を裏で行なっているのか考えてみましょう。
(1)式にを当てはめると下記式のような計算になります。
この式が最も小さな値を取る際の、を計算することになります。
手計算でも解けるので、実際に解いてみます。
よって、 = 5/3 ≒ 1.66のとき、最小値10/3を取りそうです。
は、回帰直線の傾きだと最初に説明しました。 計算が合っているのか確認するため、今回の例における回帰直線の傾きに該当する、sklearnのridgeの係数を確認してみます。
import numpy as np from sklearn.linear_model import Ridge x = np.array([1, 2]) y = np.array([2, 4]) xx = x.reshape(-1, 1) yy = y.reshape(-1, 1) model = Ridge(alpha=1, fit_intercept=False) model.fit(xx, yy) print(model.coef_)
sklearnのridgeでは、(1)式のが引数alphaで実装されています。
また、bias項を0にするため、fit_intercept=False
を行なっています。
出力は下記になります。
[[1.66666667]]
よって、手計算のの値と、sklearnのridgeの係数が一致することが確認できました。
では、次からはを変化させ、パラメータの大きさを考慮する具合を変化させた時に、リッジ回帰の結果がどう変わるかを見てみましょう。
が変化すると、回帰直線にどんな影響を与えるの?🤔
の変化に伴い、回帰直線がどう変わるかを見ていくため、徐々にデータ点が増える状況を想定します。
具体的には下記のような増え方を想定しています。
赤い点が外れ値の想定です。
各図に対し、を変えるとリッジ回帰の結果がどう変化するかを見てみましょう。
実装はこんな感じです。
import matplotlib.pyplot as plt import numpy as np from sklearn.linear_model import Ridge x = np.arange(12) y = 1 + 2 * x y[2] = 20 y[4] = 0 xmin = min(x) xmax = max(x) + 1 ymin = -1 ymax = max(y) + 1 fig, axes = plt.subplots(nrows=3, ncols=5, figsize=(10, 8)) def plot_fig(axes: np.ndarray, xx: np.ndarray, yy: np.ndarray, row: int, col: int, alpha: int): axes[row, col].set_xlim([xmin, xmax]) axes[row, col].set_ylim([ymin, ymax]) axes[row, col].scatter(xx, yy, color="k") model = Ridge(alpha) model.fit(xx, yy) predict = model.predict(xx) xs = [xmin, xmax] ys = [predict[0], predict[-1]] axes[row, idx].plot(xs, ys, color="k") for idx in range(5): xx = x[: 2 + idx * 2].reshape(-1, 1) yy = y[: 2 + idx * 2].reshape(-1, 1) plot_fig(axes=axes, xx=xx, yy=yy, row=0, col=idx, alpha=0) plot_fig(axes=axes, xx=xx, yy=yy, row=1, col=idx, alpha=10) plot_fig(axes=axes, xx=xx, yy=yy, row=2, col=idx, alpha=100) fig.tight_layout() plt.show()
結果の図はこちらです。
1行目はが0のとき、つまり線形回帰と同じ条件での結果になります。 それに対し、2行目、3行目では、を10, 100と変化させています。
1行目では、外れ値が加わると傾きを大きく変化しているように見えるのに対し、2行目、3行目では傾きの変化が小さくなっていることが分かります。ただ、今回のリッジ回帰の結果においては、傾きの変化が小さいことが良いわけではありません。データによって良い場合と悪い場合がありそうですね。
終わりに
リッジ回帰の気になる点を調べました。おかしい点があれば教えて下さい。