機械学習を学びなおしてみた2（重回帰モデル）

# はじめに
前投稿の[「機械学習を学びなおしてみた1（単回帰モデル）」](https://qiita.com/Sora_Yamamoto/items/6cb59a3d8b926422bdea)の続きです。
今回は重回帰分析について勉強します。

とは言っても扱うのは単回帰と同じでsklearnのLinearRegressionなのでパラメータ等は同じの為、省略します。

*注意：
前処理やチューニング等は特に行ってません。
重回帰分析が何なのか等の細かい部分は記述していません。


# データの用意
今回はsignateの練習用コンペの「自動車の走行距離予測」のデータを使用します。
データから"weight", "model year"（独立変数）、"mpg"（従属変数）のみを取り出して使用します。


# 重回帰分析をする前に
重回帰分析をする前に単回帰とは違って、最低限しないといけない前処理があるので説明していきます。

- 多重共線性 
回帰モデルを扱っていく上で、独立変数同士が大きな相関を持ってしまっているとモデルに悪影響を及ぼしてしまいます。（多重共線性）
これを避ける為に相関が強い独立変数をあらかじめ削除しておく必要があります。
今回は相関の無い独立変数を使用しています。
```
df.corr()
```
![スクリーンショット 2023-10-18 191638.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/a18be31b-2ba4-60a6-bfd7-8edc96bfc0ea.png)

- 標準化
標準化は変数の平均を0、標準偏差を1にスケールすることです。
線形回帰においてはスケールが大きい変数ほど回帰係数が小さくなるので、正則化がかかりにくくなってしまいモデルに悪影響を及ぼす可能性があります。
標準化を簡単に行う方法としてsklearnのStandardScalerを使用する方法があります。
```
# モジュールのインポート
from sklearn.preprocessing import StandardScaler

# インスタンス化と当てはめ
sc = StandardScaler()
sc.fit(df[["weight", "model year"]])

# transformによってndarray型が返されるので、dfのシリーズに代入する。
df[["weight", "model year"]] = sc.transform(df[["weight", "model year"]])
```

- カテゴリ変数の変換
線形回帰モデルでは基本的にカテゴリ変数を扱うことができません。
したがってOne-Hot-Encoding等の手法によって数値型に変える必要があります。
今回は数値型のみ使用しています。


# やってみる
それでは学習を始めたいと思います。
今回使用するライブラリは次の通りです。
```
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
```

### 標準化前
標準化前のモデルはどのようになっているのでしょうか。
まずは相関と統計量を見ていきます。
```
df.corr()
```
![スクリーンショット 2023-10-18 191638.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/a18be31b-2ba4-60a6-bfd7-8edc96bfc0ea.png)

```
df.describe()
```
![スクリーンショット 2023-10-18 193209.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/e5a3a050-1306-952e-4da8-419abc73d24a.png)

多重共線性の心配はないですが、2つの独立変数のスケールは大きく離れています。

このままモデルに学習させて結果を見ていきます。
```
X = df[["weight", "model year"]]
y = df[["mpg"]]

reg = LinearRegression()
reg.fit(X,y)

# r_2値の計算 #
reg.score(X,y)
# 0.8056805626243541

# 回帰係数の表示 #
reg.coef_
# array([[-0.00685351,  0.77328453]])

# 切片の表示 #
reg.intercept_
# array([-14.82639473])
```

今回はデータがそこまで複雑ではないこともあってか、r_2値は高かったです。
値の大きかったweightは回帰係数がmodel yearと比べて100倍程小さくなっています。
この状態だと独立変数が実際、どの位モデルに影響を与えたのかが分からなくなってしまいます。

最後に図で見てみます。
```
# プロット用のメッシュグリッドを作成
x1 = np.linspace(X["weight"].min(), X["weight"].max())
x2 = np.linspace(X["model year"].min(), X["model year"].max())
X1, X2 = np.meshgrid(x1, x2)
Y = reg.predict(np.c_[X1.ravel(), X2.ravel()])
Y = Y.reshape(X1.shape)

# 3Dプロット
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X["weight"], X["model year"], y, c='b', marker='o', label='Actual')
ax.plot_surface(X1, X2, Y, color='r', alpha=0.5, label='Predicted')
ax.set_xlabel("Weight")
ax.set_ylabel("Model Year")
ax.set_zlabel("MPG")
ax.set_title("3D Plot of Regression Model")
plt.show()
```

![スクリーンショット 2023-10-18 195016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/77db2c79-d578-7dfe-7f88-57d136d3ddd0.png)


# 標準化後
標準化前と同様の方法でモデルの状態を見ていきます。

```
# 標準化 #
sc = StandardScaler()
sc.fit(df[["weight", "model year"]])
df[["weight", "model year"]] = sc.transform(df[["weight", "model year"]])

X = df[["weight", "model year"]]
y = df[["mpg"]]

reg = LinearRegression()
reg.fit(X,y)

# r_2値の計算 #
reg.score(X,y)
# 0.8056805626243541

# 回帰係数の表示 #
reg.coef_
# array([[-5.60414833,  2.93334723]])

# 切片の表示 #
reg.intercept_
# array([24.30703518])
```

r_2値は変わりませんでした。
回帰係数がスケーリングしたことで差が小さくなり、weightの方がモデルに影響を与えたことが分かります。

最後に図で見てみます。

![スクリーンショット 2023-10-18 200130.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491855/84bff430-4cbc-5199-840c-92e88249a72a.png)


次回は実際に重回帰モデルで、この練習問題に結果をサブミットしていこうと思います。