線形回帰⑪ (まとめ)

線形系のアルゴリズムについてまとめます。

  • 単回帰
    1つの説明変数から1つの目的変数を予測する。
    もっとも扱いやすく、モデルの解釈もしやすい。
    精度面においては複数の変数で説明を行う重回帰のほうが優る。
  • 重回帰
    複数の説明変数から1つの目的変数を予測する。
    単回帰よりも精度は上がりやすいが、過学習に陥りやすい。
  • LASSO回帰
    重回帰に正則化項(L1ノルム)を付与し、変数の重みを0に近づける。
    特定の変数の重みを0にする。
    重みを小さくすることで過学習のリスクを軽減できる。
    使用する説明変数が減ることでモデルがシンプルになり、解釈性が上がる。
    重要と思われる変数の重みまで0にしてしまう可能性がある。
  • リッジ回帰
    重回帰に正則化項(L2ノルム)を付与し、変数の重みを0に近づけるが、0にはならない。
    重みを小さくすることで過学習のリスクを軽減できる。
    全ての変数を使用するため、モデルの解釈性は改善されない。

LASSO回帰、リッジ回帰は重回帰の上位互換といえるアルゴリズムです。

全ての変数を使用したい場合はリッジ回帰、一部の変数が削除されても問題ない場合はLASSO回帰を使うのが良いでしょう。

線形回帰⑩ (リッジ回帰)

リッジ回帰を使ったモデルを構築します。

リッジ回帰

リッジ回帰は、L2ノルムという正則化項を使用したアルゴリズムです。

前回までのLASSO回帰は各変数の重みを0に近づけつつ、特定の変数の重みを0にするという特性がありました。

リッジ回帰は各変数の重みを0に近づけますが、完全な0にはなりません。

そのため、LASSO回帰のようにモデルの解釈を簡単にするという特徴はありませんが、モデルの設計上、全ての説明変数が重要であるというケースではリッジ回帰の方が適していると言えます。

リッジ回帰モデルの構築

リッジ回帰モデルの構築はscikit-learnRidgeクラスを使います。

[Google Colaboratory]

1
2
3
from sklearn.linear_model import Ridge

ridge = Ridge().fit(X_train_scaled, y_train)

リッジ回帰モデルの構築と学習が完了しました。

続いて、重回帰分析の時にスケーリングしたデータを使って予測を行います。

[Google Colaboratory]

1
2
3
4
5
y_train_pred = ridge.predict(X_train_scaled)
y_test_pred = ridge.predict(X_test_scaled)

print(y_train_pred[:5])
print(y_test_pred[:5])

[実行結果]

残差プロット

残差プロットを表示します。

[Google Colaboratory]

1
residual_plot(y_train_pred, y_train, y_test_pred, y_test)

[実行結果]

精度評価スコア

精度評価スコアを表示します。

[Google Colaboratory]

1
2
3
4
print("訓練データスコア")
get_eval_score(y_train,y_train_pred)
print("テストデータスコア")
get_eval_score(y_test,y_test_pred)

[実行結果]

精度評価スコアはLASSO回帰(alpha=1.0)よりもやや高く、重回帰と同程度となりました。

重み

各説明変数の重みを表示します。

[Google Colaboratory]

1
2
3
for i, (col, coef) in enumerate(zip(boston.feature_names, ridge.coef_[0])):
print(f"w{i}({col}) = {coef}")
print(f"b = {ridge.intercept_[0]}")

[実行結果]

LASSO回帰では多くの説明変数が0となっていましたが、リッジ回帰では重みが完全に0となっている説明変数はありません。

重回帰と比べると、全体的に変数の重みは小さくなっています。

交差検証

リッジ回帰についても、LASSO回帰と同様にscikit-learnに交差検証用のRidgeCVというクラスがあり交差検証が可能です。


次回は、これまで扱ってきた単回帰、重回帰、LASSO回帰、リッジ回帰といういろいろな線形系のアルゴリズムについてまとめます。

線形回帰⑨ (交差検証)

前回は、ハイパーパラメータのalphaを1つだけ指定して、学習・評価を行いましたが、最適なalphaを見つけるためには複数の値を設定し、その結果を確認する必要があります。

LassoCVクラスを使うと、一度に複数のalphaの結果を確認することができます。

交差検証

LassoCVクラスは複数のalphaで交差検証を行い、最も精度が高かった時のalphaを結果として表示することができます。

alphaが[0.1, 0.5, 1, 5, 10]の場合の交差検証を行うコードは以下の通りです。

[Google Colaboratory]

1
2
3
from sklearn.linear_model import LassoCV

lasso_cv = LassoCV(alphas=[0.1, 0.5, 1, 5, 10]).fit(X_train_scaled, y_train)

[実行結果]

交差検証が正常に終了しました。

重み確認

交差検証により、最も精度のよかった時のalphaでモデルが構築されています。

最適なalphaと各説明変数の重みを確認します。

[Google Colaboratory]

1
2
3
4
print(f"alpha = {lasso_cv.alpha_}")
for i, (col, coef) in enumerate(zip(boston.feature_names, lasso_cv.coef_)):
print(f"w{i}({col}) = {coef}")
print(f"b = {lasso_cv.intercept_}")

[実行結果]

0.1のときの精度が最も高いということが確認できました。

またペナルティが弱くなったため、重みが0になる説明変数がなくなりました。

精度評価スコア

精度評価スコアを確認します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
y_train_pred = lasso_cv.predict(X_train_scaled)
y_test_pred = lasso_cv.predict(X_test_scaled)

y_train_pred = np.expand_dims(y_train_pred, 1)
y_test_pred = np.expand_dims(y_test_pred, 1)

print("訓練データスコア")
get_eval_score(y_train,y_train_pred)
print("テストデータスコア")
get_eval_score(y_test,y_test_pred)

[実行結果]

精度評価スコアが以前のモデルよりも向上しています。

交差検証を使うと、効率的にパラメータの調整を行うことができるので、積極的に活用していきましょう。

次回は、リッジ回帰を行います。

線形回帰⑧ (LASSO回帰モデルのパラメータ変更)

LASSO回帰モデルのハイパーパラメータを変更します。

ハイパーパラメータとは、機械学習モデルがもつパラメータの中で人間が任意に調整するパラメータです。

ハイパーパラメータの設定次第で、モデルの精度が大きく変わってしまいますので適切な値を設定する必要があります。

ハイパーパラメータ(alpha)変更

Lassoクラスにはalphaというハイパーパラメータがあり、正則化項によるペナルティの強さを調整できます。

alphaの値が大きいほど、重みを0にする力が強くなります。

alphaのデフォルトは1.0ですが、試しに10に変更してモデルを構築・学習してみます。

[Google Colaboratory]

1
lasso_change_param = Lasso(alpha=10).fit(X_train_scaled, y_train)

重みを表示して、結果を確認します。

[Google Colaboratory]

1
2
3
for i, (col, coef) in enumerate(zip(boston.feature_names, lasso_change_param.coef_)):
print(f"w{i}({col}) = {coef}")
print(f"b = {lasso_change_param.intercept_}")

[実行結果]

ペナルティを強くしすぎたようで、全ての説明変数の重みが0.0となってしまいました。

最適なalphaを見つけるためには、さらに試行錯誤が必要なようです。

線形回帰⑦ (LASSO回帰モデルの評価)

前回構築したLASSO回帰モデルの評価を行います。

残差プロット

予測値と実測値の残差プロットを表示します。

以前に定義したresidual_plot関数を使います。

[Google Colaboratory]

1
residual_plot(y_train_pred, y_train, y_test_pred, y_test)

[実行結果]

重回帰と比較し、残差の分布に違いはないようです。

精度評価スコア

次に精度評価スコアを算出します。

以前に定義したget_eval_score関数を使います。

[Google Colaboratory]

1
2
3
4
print("訓練データスコア")
get_eval_score(y_train,y_train_pred)
print("テストデータスコア")
get_eval_score(y_test,y_test_pred)

[実行結果]

重回帰と比べて、やや低いスコアとなっていまいました。

重み

説明変数の重みを表示します。

[Google Colaboratory]

1
2
3
for i, (col, coef) in enumerate(zip(boston.feature_names, lasso.coef_)):
print(f"w{i}({col}) = {coef}")
print(f"b = {lasso.intercept_[0]}")

[実行結果]

RMやLSTATのような重要な変数の重みは残っていますが、多くの説明変数の重みが0になりました。

このようにLASSO回帰では各説明変数の重みを0に近づけ、特定の説明変数の重みを0にします。

次回は、LASSO回帰のハイパーパラメータを変更してみます。

線形回帰⑥ (LASSO回帰モデル)

今回はLASSO回帰モデルを構築します。

LASSO回帰モデルは、重みが大きくなるのを抑えるために重回帰による各変数の重みの算出時に正則化項というペナルティを設定しています。

この正則化項はL1ノルムと言われ、変数の重みを0に近づけると同時に、特定の変数の重みを完全に0にする効果があります。

この効果によって過学習を抑えられるだけでなく、一部の変数の重みが0になることでモデルがシンプルになり、分かりやすくなるというメリットもあります。

LASSO回帰モデルの構築

LASSO回帰モデルを構築するためにはscikit-learnに用意されているLassoクラスを使用します。

データは前回の重回帰分析でスケーリングしたものを使います。

[Google Colaboratory]

1
2
3
from sklearn.linear_model import Lasso

lasso = Lasso().fit(X_train_scaled, y_train)

続いて予測値を出力します。

[Google Colaboratory]

1
2
3
4
5
y_train_pred = lasso.predict(X_train_scaled)
y_test_pred = lasso.predict(X_test_scaled)

print(y_train_pred[:5])
print(y_test_pred[:5])

[実行結果]

予測値を確認すると、前回重回帰分析で出力されたデータ形式とは違うようです。

データ形式の変更

データ形式をこれまで出力したものと合わせておきます。

Numpyのexpand_dims関数を使い次元を追加します。

第1引数にデータを指定し、第2引数に次元を追加する位置を指定します。

[Google Colaboratory]

1
2
3
4
5
y_train_pred = np.expand_dims(y_train_pred, 1)
y_test_pred = np.expand_dims(y_test_pred, 1)

print(y_train_pred[:5])
print(y_test_pred[:5])

[実行結果]

次回は、今回構築したLASSO回帰モデルの評価を行います。

線形回帰⑤ (各説明変数の重み)

構築した重回帰モデルの重み切片を確認します。

重みと切片

重み切片を表示するコードは次のようになります。

[Google Colaboratory]

1
2
3
for i, (col, coef) in enumerate(zip(boston.feature_names, multi_reg.coef_[0])):
print(f"w{i}({col}) = {coef}")
print(f"b = {multi_reg.intercept_[0]}")

wの値が大きいものほど、モデルへの貢献度が高い変数です。

[実行結果]

参考までに以前作成した相関係数のヒートマップを表示します。

[相関係数のヒートマップ]

RMLSTATなど、目的変数と相関の大きい変数の重みが比較的大きいことが分かります。

今回の精度評価スコアからは過学習の傾向は見られませんでしたが、過学習が起きている兆候の1つに説明変数の重みが大きいことが挙げられます。

そして過学習のリスクを減らすには、説明変数の重みを小さくする処理が重要となります。

次回の回帰モデルでは、過学習を抑えるために説明変数の重みが大きくならないように制限を行います。

線形回帰④ (重回帰モデルの精度評価)

前回構築した重回帰モデルの精度評価を行います。

散布図

散布図で予測結果を可視化してみます。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
%matplotlib inline

print(X_train.shape)
print(y_train_pred.shape)
#plt.scatter(X_train, y_train_pred, label="train") # ValueError: x and y must be the same size
#plt.scatter(X_test, y_test_pred, label="test") # ValueError: x and y must be the same size
plt.xlabel("X")
plt.ylabel("y")
plt.title("multi_reg")
plt.legend()
plt.show()

エラーが発生したため、6~7行目をコメントアウトしました。

ValueError: x and y must be the same sizeというエラーメッセージは引数にしている変数の次元数が同じではないために発生したエラーになります。

単回帰のように説明変数と目的変数が1つずつであれば散布図で表示することができますが、今回の重回帰では説明変数が13種類あるので散布図では表示できません。

[実行結果]

という訳で予測結果を散布図で表示するのは省略します。

残差プロット

残差プロットで予測結果を可視化します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
def residual_plot(y_train_pred, y_train, y_test_pred, y_test):
plt.scatter(y_train_pred, y_train_pred - y_train, label="train")
plt.scatter(y_test_pred, y_test_pred - y_test, label="test")
plt.plot([0, 50], [0,0] ,color="red")
plt.xlabel("Pred")
plt.ylabel("Pred - True")
plt.title("Residual Plot")
plt.legend()
plt.show()

residual_plot(y_train_pred, y_train, y_test_pred, y_test)

[実行結果]

外れ値はあるようですが、単回帰の時ほど値は大きくなく、密集部分の範囲も±10程度に収まっており精度が改善しています。

精度評価スコア

精度評価スコアを算出します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np

def get_eval_score(y_true,y_pred):
mae = mean_absolute_error(y_true,y_pred)
mse = mean_squared_error(y_true,y_pred)
rmse = np.sqrt(mse)
r2score = r2_score(y_true,y_pred)

print(f" MAE = {mae}")
print(f" MSE = {mse}")
print(f" RMSE = {rmse}")
print(f" R2 = {r2score}")

print("訓練データスコア")
get_eval_score(y_train,y_train_pred)
print("テストデータスコア")
get_eval_score(y_test,y_test_pred)

[実行結果]

十分高い精度とはいきませんでしたが、テストデータのR2スコアが0.67と単回帰よりもかなり改善しています。

また、過学習の傾向もないようです。

線形回帰③ (重回帰モデル構築)

重回帰を使ったモデルの構築を行います。

重回帰は、複数の説明変数を用いて1つの目的変数を予測するアルゴリズムです。

単回帰と式の複雑さは変わりますが、学習により係数(傾き・重み)と切片を求めることは変わりません。

  • 単回帰
    学習により傾き(a)と切片(b)を求める。
     y = ax + b
  • 重回帰
    学習により各説明変数の重み(w1~wn)と切片(b)を求める。
     y = w1x1 + w2x2 + ・・・・ + wnxn + b

重回帰モデルの構築

scikit-learnLinearRegressionクラスを使って重回帰モデルを構築します。

単回帰と重回帰は説明変数を複数使用するかどうかの違いだけなので、LinearRegressionの引数であるデータセットを変更するだけで対応可能です。

[Google Colaboratory]

1
2
3
from sklearn.linear_model import LinearRegression

multi_reg = LinearRegression().fit(X_train_scaled, y_train)

次に予測値を算出します。

[Google Colaboratory]

1
2
3
4
5
6
7
y_train_pred = multi_reg.predict(X_train_scaled)
y_test_pred = multi_reg.predict(X_test_scaled)

print(len(y_train_pred))
print(y_train_pred[:5])
print(len(y_test_pred))
print(y_test_pred[:5])

[実行結果]

以上で、モデルの構築と予測値の算出まで完了しました。非常に簡単ですね。

次回は、今回作成したモデルの精度評価を行います。

線形回帰② (データ準備)

重回帰問題を解くのに適したボストンの住宅価格データを準備します。

データの読み込み

まずはデータを読み込みます。(2行目)

読み込んだデータをデータフレームに格納し(5行目)、目的変数の項目名は“MEDV”とします。(6行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
from sklearn.datasets import load_boston
boston = load_boston()

import pandas as pd
df = pd.DataFrame(boston.data,columns=boston.feature_names)
df["MEDV"] = boston.target

display(df.head())

[実行結果]

ホールドアウト法

説明変数を変数 Xに代入し、目的変数を変数 yに代入します。

今回は、説明変数に13種類全ての変数を使用することにします。

[Google Colaboratory]

1
2
3
4
5
X = df[boston.feature_names]
y = df[["MEDV"]]

display(X.head())
display(y.head())

[実行結果]

ホールドアウト法で、訓練データとテストデータに分割します。(2行目)

test_size=0.3と指定しているので、訓練データが70%、テストデータが30%の割合に分割されます。

[Google Colaboratory]

1
2
3
4
5
6
7
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y,test_size=0.3,random_state=0)

print(len(X_train))
display(X_train.head())
print(len(X_test))
display(X_test.head())

[実行結果]

スケーリング

データのスケーリングを行います。

スケーリングとは、複数の説明変数間でのデータの尺度をそろえることを意味します。

重回帰のような複数の説明変数を扱う線形系のアルゴリズムは、データの尺度による影響を特に受けやすいため、正しく学習させるためにはデータのスケーリングが必要になります。

スケーリングには、主に次のような手法があります。

  • 標準化
    説明変数の平均が0、標準偏差が1になるようにスケーリングを行います。
    正規分布に従うデータに有効です。
  • 正規化
    説明変数の値が0~1の範囲に収まるようにスケーリングを行います。
    一様分布のようなデータに有効です。

正規分布でも一様分布でもない場合は、ロバストZスコアという手法が用いられることがあります。

スケーリングには明確な正解はなく、モデル精度と合わせて検討していくことが多くなります。


sklearnには、スケーリングをするためのクラスがありますのでこれを利用します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print(X_train_scaled[:3])
print(X_test_scaled[:3])

fit_transform関数ではfit関数とtransform関数をまとめて実行します。(4行目)

transform関数では、fit関数の実行した結果を用いて、実際に正規化を 実行します 。(5行目)

訓練データにはfit_transform関数を使い、テストデータにはtransform関数を使うと覚えておくとよいでしょう。

[実行結果]

以上で、モデル構築の準備ができました。

次回は、今回準備したデータを使って重回帰モデルの構築を行います。


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×