2. Pythonで綴る多変量解析　1-1. 単回帰分析(scikit-learn)

ここ数年来 AI やビッグデータへの関心の高まりに伴い、機械学習のためのアプローチ法として、例えばk-meansといった分析手法を耳目にするようになりました。それらは、いずれも昭和の昔から何十年とビジネスや学術分野で活用されてきた**多変量解析**の手法です。
その中でも特にポピュラーな手法の一つが**回帰分析**です。
そこで、まず機械学習ライブラリの scikit-learn（サイキット・ラーン）を利用して**単回帰分析**を実装してみます。
（原則として Google Colaboratory 上でコードの記述や結果の確認をおこないます）

##**<font color="Gray">単回帰分析</font>**

回帰分析は、２つの変量を対象とする**単回帰分析**と、３つ以上の変量を対象とする**重回帰分析**に分けられます。
まず、**単回帰分析**を考えます。
単回帰分析とは、データ（現象）の中に**線形**ないし**非線形**の法則性を導くもの･･････、平たく言えば、$x$が増えると$y$も一定の比率で増える/減るというような法則性を明らかにするものです。
![002_001_007.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/62691d0a-36d5-2c8c-7bf4-297fe0f9d0d9.png)

ごくシンプルな**線形の単回帰分析**は、次の式で表わされます。
![002_001_013.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/34321137-bfac-c9f1-10fd-be1f951c6425.png)
この方程式を**回帰式（単回帰式）**といいます。
この$a$と$b$さえ決まってしまえば自ずと直線は引けます。すると、$x$で$y$を説明することができる、あるいは$x$から$y$を予測することができる。
変数$y$ を変数$x$ によって説明するということから、ターゲットとなる $y$ を**目的変数**（従属変数）、これを説明する $x$ を**説明変数**（独立変数）と呼びます。
また、回帰直線の傾きを示す$a$を**回帰係数**、$y$軸との交点を示す$b$を**切片**といいます。
すなわち回帰係数aと切片bを求めることが、単回帰分析の目標です。



####**⑴ ライブラリをインポートする**

```python
# 数値計算に必要なライブラリ
import numpy as np
import pandas as pd
# グラフを描画するパッケージ
import matplotlib.pyplot as plt
# scikit-learnの線形モデル
from sklearn import linear_model
```


####**⑵ データを読み込み、中身を確認する**

```python
df = pd.read_csv("https://raw.githubusercontent.com/karaage0703/machine-learning-study/master/data/karaage_data.csv")
df
```
![002_001_001.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/cca88543-59da-6ff6-5b82-9bf8bcdafede.png)


####**⑶ 変量x, yをNumpyのArray型に変換する**
データが格納された変数dfは、Pandasのデータフレームの形式になっています。これを後々の計算のために、NumpyのArray型に変換するなどして変数x, yにそれぞれ格納します。

```python
x = df.loc[:, ['x']].values
y = df['y'].values
```
![002_001_002.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/7ea25035-4dfc-acb1-54f0-838b8ddff750.png)
変量$x$は、pandasの`loc`関数で [全行, x列] の要素を切り出して`values`でNumpy配列に変換し、２次元データとして格納しました。また変量$y$は、列名$y$を指定して１次元データとして取り出し、同様にNumpy配列に変換しています。


####**⑷ 散布図にデータをプロットしてみる**
描画パッケージ matplotlib を利用して、`plot`関数の引数に(変数x, 変数y, ''マーカーの種類'')を指定します。

```python
plt.plot(x, y, "o")
```
![002_001_003.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/749d9457-6c52-1d9c-b359-5ada4d117030.png)


**ここから機械学習ライブラリscikit-learn の線形回帰モデルを利用して、回帰係数$a$ と切片$b$ を計算していきます。**


####**⑸ 線形回帰モデルに変量x, yを適用する**

```python
# 線形回帰モデルを読み込み、関数clfとする
clf = linear_model.LinearRegression()
# 関数clfに対して変量x, yをあてはめる
clf.fit(x, y)
```


####**⑹ 回帰係数・切片を算出する**
回帰係数は`coef_`、切片は`intercept_`で取得できます。

```python
# 回帰係数
a = clf.coef_
# 切片
b = clf.intercept_
```
![002_001_005.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/7b2aac32-36f4-809e-1dae-829518b8f369.png)


####**⑺ 決定係数を算出する**
次いで、決定係数を`score(変数x, 変数y)`として取得します。

```python
# 決定係数
r = clf.score(x, y)
```
![002_001_006.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/4a02fa17-ec2e-8b67-e79a-c2be444c258f.png)


##**<font color="Gray">決定係数</font>**

決定係数は、得られた**回帰式の精度**をあらわす指標です。
精度とはこの場合、「回帰式がデータの分布をどの程度よく説明できているか」ということです。
決定係数は、次のように定義されます。
![002_001_014.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/cb51ae1c-3f7e-426f-bf0f-4921afcefaef.png)
実際に観測されたデータのことを**実測値**と呼びます。散布図を見て明らかなように実測値は座標上に散らばっています。
これを一本の直線に要約するわけですから、もとの分散の持っている情報をいくらか棄却することになります。
この棄却した部分、すなわち回帰式に伴う誤差のことを**残差**といい、次のような分数の形に表わすことができます。
![002_001_008.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/158eb1c2-9a1d-d26b-f2db-f2aafcaaa7a1.png)
分母は実測値である目的変数$y$の分散で、分子は回帰式による予測値$\hat{y}$の分散と、残差という目減り分を置いて上下は均衡します。
つまり決定係数とは、実測値の分散のうち予測値の分散が何割を占めるかということです。
割合ですから、決定係数$R^2$は必ず0以上1以下の値をとり、1に近いほど回帰式の精度がよいと解釈されます。


####**⑻ 回帰直線を描くためのx値を設定する**
まず回帰直線の元となる$x$値を、Numpyの`linspace`関数をつかって生成します。
引数には `(始点, 終点, 区切る数)` を指定します。

```python
fig_x = np.linspace(0, 40, 40)
```
![002_001_009.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/455f74b9-43aa-e58f-bb4f-d5e7813e15ba.png)



####**⑼ 回帰係数、切片、x値の形状を確認する**
```python
print(a.shape) # 回帰係数
print(b.shape) # 切片
print(fig_x.shape) # x値
```
![002_001_010.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/6fda5032-a601-7a14-d3ed-34672b144364.png)

##**<font color="Gray">Tips</font>**

このまま $y = ax + b$ に代入するとエラーになってしまいます。
なぜなら、回帰係数$a$ は1行×1列のarray型、$x$値は40行×1列のarray型なので、配列同士を乗算するときのルールに合っていないからです。
そこで、回帰係数$a$ を単一の値に変換し、$x$値のすべてに等しく乗算されるようにしておく必要があります。



####**⑽ 変量yを定義する**
y値すなわち変数 fig_y の計算式を定義するに際し、Numpyの`reshape`関数をつかって回帰係数$a$ の形状を変換します。

```python
fig_y = a.reshape(1)*fig_x + b
```
![002_001_011.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/046a9480-430f-55f4-e85b-1bc971ef3fd7.png)



####**⑾ 回帰直線を描画する**
```python
# 散布図
plt.plot(x, y, "o")
# 回帰直線
plt.plot(fig_x, fig_y, "r") # 第3引数で線の色を"r"に指定

plt.show()
```
![002_001_012.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/c92fa424-1319-35e0-55bd-680ef3a0e435.png)

---
以上のように、機械学習ライブラリを利用することで、複雑な計算をしなくとも分析結果を得ることはできます。
しかし、回帰分析に限ったことではありませんが、計算結果に対していかにそれを適切に解釈するか、あるいは手法を運用する上で微妙なチューニングを行なうとなると、やはり計算の仕組み（アルゴリズム）を知っておくことが望ましいといえます。
そこで次は、scikit-learn を利用しないで、すべて自前で単回帰分析を学びます。