scikit-learnによる、はじめてのPython機械学習(2)
学習モデルの改善と過学習
では次に、線形モデルではなく非線形モデルを使ってみましょう。非線形モデルとして多次元の多項式を使います。np.vanderメソッドと組み合わせることで線形回帰を利用することができます。ここでは2次・3次・10次の多次元多項式での学習を試みてみましょう。
[コラム] numpyのvanderメソッド
多次元の多項式を表現するための行列式はnumpyのvanderメソッドで利用できます。この行列式はヴァンデルモンドの行列式と呼ばれます。ヴァンデルモンドの行列式は多次元の多項式を表現する以外にもさまざまな特徴があります。より詳しくヴァンデルモンドの行列式を理解したい方はWikipediaの下記記事を参照してください。
lr2 = lm.LinearRegression()
fig, ax = plt.subplots(1, 1, figsize=(7, 4))
ax.plot(x_target, y_target, '--k')
for deg, style in zip([2, 3,10], ['.', '.', '-']):
lr2.fit(np.vander(x, deg + 1), y)
y_lr2 = lr2.predict(np.vander(x_target, deg + 1))
ax.plot(x_target, y_lr2, style,label=f'degree {deg}')
ax.legend(loc=2)
ax.set_xlim(0, 1.5)
ax.set_ylim(0, 90)
# モデルの係数
print(f'次元 {deg}の場合の係数:\n\t',' '.join(f'{c:.1f}' for c in lr2.coef_))
ax.plot(x, y, 'o', ms=10)
ax.set_title("Linear regression")
結果は下記になります。
次元 2の場合の係数:
18.2 0.5 0.0
次元 3の場合の係数:
82.3 -145.1 103.1 0.0
次元 10の場合の係数:
-20240521.6 102820634.8 -201942763.6 159316105.0 49193764.3 -220981770.4 215878812.8 -113353443.3 34758868.6 -5873519.6 0.0
Text(0.5,1,'Linear regression')
ここでは2次、3次、10次の多項式をモデルとしてそれぞれ学習してみました。10次の場合におかしな結果になっています。3次の場合はうまく学習しているように見えますがxが0.4未満の範囲を見てみると大きく外れています。このような現象は「過学習」と呼ばれます。学習が訓練データに”適応しすぎた”ことによるものです。そのため訓練データ以外のデータ(xが1以上や0.4未満の範囲)に対してうまく予測ができない状態になってしまいました。
リッジ回帰による改善
これを改善するため、リッジ回帰を使うことにします。リッジ回帰は線形回帰の応用の学習モデルです。正則化最小二乗学習とも呼ばれます。先ほどの過学習では多項式の係数が大きくなりすぎる現象が起こりました。リッジ回帰は多項式の係数が大きくなりすぎないように自ら調整し適した学習を行います。
scikit-learnはリッジ回帰のモデルをRidgeCVメソッドで利用できます。先ほどのコードlm.LinearRegression()をlm.RidgeCV()に置き換えます。この箇所以外は同じです。
ridge = lm.RidgeCV()
fig, ax = plt.subplots(1, 1, figsize=(7, 4))
ax.plot(x_target, y_target, '--k')
for deg, style in zip([2, 3,10], ['.', '.', '-']):
ridge.fit(np.vander(x, deg + 1), y)
y_ridge = ridge.predict(np.vander(x_target, deg + 1))
ax.plot(x_target, y_ridge, style, label='degree ' + str(deg))
ax.legend(loc=2)
ax.set_xlim(0, 1.5)
ax.set_ylim(0, 90)
print(f'次元 {deg}の場合の係数:\n\t', ' '.join(f'{c:.1f}' for c in ridge.coef_))
ax.plot(x, y, 'o', ms=10)
ax.set_title("Ridge regression")
結果は下記になります。
次元 2の場合の係数:
11.1 7.8 0.0
次元 3の場合の係数:
6.9 6.5 5.0 0.0
次元 10の場合の係数:
0.3 0.3 0.4 0.6 1.0 1.6 2.4 3.5 4.4 4.3 0.0
Text(0.5,1,'Ridge regression')
今度の図では10次の式は3次や2次の式より正確に正解モデルを予測しているようです。また3次の式の過学習も改善されました。これはリッジ回帰が複雑なモデルでも過学習を回避するように働いたためです。多項式の係数が過学習が起きた際とくらべて小さくなってることを確認してください。
まとめ
今回はPythonによる機械学習に挑戦しました。機械学習は複雑な処理もありますがライブラリの力をかりて手軽に可能であることを確認していきました。今回解説した手法以外にもさまざまなアルゴリズムが利用可能ですので手元の環境で確認してみてください。
