線形モデルの係数と決定境界の比較

分類アルゴリズムは基本的に2値分類の場合は特に線形の場合ルールベースとしてモデルで算出結果が0.5を超えた場合に陽性、0.5未満の場合に陰性と判断する事が多いです。
ところで線形モデルと一言で言っても色々とあります。
例えば
- SVM
- ロジスティック回帰
- 線形回帰
- ポアソン回帰

などがあります。
しかしそれぞれアルゴリズムが違ったり、数式が違ったり、確率分布(ベイズ統計)が違うなどあります。
そこで、上記4つのアルゴリズムについて実際に係数と切片を見てみようと思います。
# コーディング
## ライブラリのインポート
使用するデータセットにはScikit-Learnのmake_blobsを使ってみます。
```Python3
from sklearn.datasets import make_blobs
from sklearn import preprocessing
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import PoissonRegressor
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
```

## データセットの可視化
どんなデータセットか可視化します。
```Python3
x, y = make_blobs(n_samples=100, centers=2,random_state=0, cluster_std=0.60)
plt.scatter(x[:, 0], x[:, 1], c=y, s=50, cmap="brg")
plt.show()
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/8def123d-ade9-ddd4-8a2f-4e5f19b3c74c.png)
## 係数の名前を入れる
```Python3
index = ["x0", "x1", "intercept"]
columns = ["coef"]
```
とても分類しやすいようになっています。
では実際に分類をしてみましょう。
## 係数と切片の確認
### SVM
SVMは2値分類の場合陽性と陰性のデータの境目について平行に支持直線(多次元の場合超平面)と呼ばれる線を引き、その線と線の間の幅が最も広くなるように決定境界を作ります。
```Python3
model1 = SVC(kernel="linear")
model1.fit(x, y)
model1.coef_
model1.intercept_
svm_coef = np.array([])
svm_coef = np.append(svm_coef, model1.coef_)
svm_coef = np.append(svm_coef, model1.intercept_)
df_svm = pd.DataFrame(svm_coef)
df_svm.index = index
df_svm.columns = columns
```

### ロジスティック回帰
ロジスティック回帰は陽性と陰性に対してシグモイド関数を多次元化してしきい値を設定する事で分類しています。
```Python3
model2 = LogisticRegression()
model2.fit(x, y)
model2.coef_
model2.intercept_
lor_coef = np.array([])
lor_coef = np.append(lor_coef, model2.coef_)
lor_coef = np.append(lor_coef, model2.intercept_)
df_lor = pd.DataFrame(lor_coef)
df_lor.index = index
df_lor.columns = columns
```

### 線形回帰
線形回帰はExcelにもあります重回帰分析と同じく最小二乗法と呼ばれる方法で回帰するアルゴリズムです。
本来は回帰に用いるアルゴリズムですが先述した通りしきい値を用いる事で1と0の場合だと回帰の算出結果が0.5以上だと陽性でそうでなければ陰性なら分類にも使えます。
```Python3
model3 = LinearRegression()
model3.fit(x, y)
model3.coef_
model3.intercept_
lir_coef = np.array([])
lir_coef = np.append(lir_coef, model3.coef_)
lir_coef = np.append(lir_coef, model3.intercept_)
df_lir = pd.DataFrame(lir_coef)
df_lir.index = index
df_lir.columns = columns
```
### ポアソン回帰
主にカウントデータを分析するアルゴリズムで名前の通りポアソン分布を基にしています。
```Python3
model4 = PoissonRegressor()
model4.fit(x, y)
model4.coef_
model4.intercept_
pos_coef = np.array([])
pos_coef = np.append(pos_coef, model4.coef_)
pos_coef = np.append(pos_coef, model4.intercept_)
df_pos = pd.DataFrame(pos_coef)
df_pos.index = index
df_pos.columns = columns
```

## 結果を見てみる
```Python3
df_coef = pd.concat([df_svm, df_lor, df_lir, df_pos], axis=1)
df_coef.columns = ["SVM", "LogisticRegression", "LinearRegression", "PoissonRegressor"]
df_coef
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/3a400bac-c8af-c302-f77d-94d89afc4e74.png)

こうやってみてみると意外とというか全然違うことが分かります。やはり使う数式やアルゴリズムが違うから当然と言えば当然の結果なのでしょうね。
※でも線形回帰は単純に当てはめられるし、ロジスティック回帰はオッズ比に使えるから←ここ重要
## 図示
ここまで係数と切片について見ましたが今度は図示してみましょう。
### 図示する関数
まず分類用の関数です。
仕組みとしては正規化した二次元平面に対してデータを学習して細かく平面を分割し、分割した場所を予測して色を付けるということです。
```Python3
def showline_clf(x, y, model, modelname, x0="x0", x1="x1"):
    fig, ax = plt.subplots(figsize=(8, 6))
    X, Y = np.meshgrid(np.linspace(*ax.get_xlim(), 1000), np.linspace(*ax.get_ylim(), 1000))
    XY = np.column_stack([X.ravel(), Y.ravel()])
    x = preprocessing.minmax_scale(x)
    model.fit(x, y)
    Z = model.predict(XY).reshape(X.shape)
    plt.contourf(X, Y, Z, alpha=0.1, cmap="brg")
    plt.scatter(x[:, 0], x[:, 1], c=y, cmap="brg")
    plt.xlim(min(x[:, 0]), max(x[:, 0]))
    plt.ylim(min(x[:, 1]), max(x[:, 1]))
    plt.title(modelname)
    plt.colorbar()
    plt.xlabel(x0)
    plt.ylabel(x1)
    plt.show()
```
次に回帰で分類用の関数です。回帰の場合はしきい値を設定します。
```Python3
def showline_reg(x, y, model, modelname, x0="x0", x1="x1"):
    fig, ax = plt.subplots(figsize=(8, 6))
    X, Y = np.meshgrid(np.linspace(*ax.get_xlim(), 1000), np.linspace(*ax.get_ylim(), 1000))
    XY = np.column_stack([X.ravel(), Y.ravel()])
    x = preprocessing.minmax_scale(x)
    model.fit(x, y)
    Z = model.predict(XY)
    Z = np.where(Z >= 0.5, 1, 0).reshape(X.shape)
    plt.contourf(X, Y, Z, alpha=0.1, cmap="brg")
    plt.scatter(x[:, 0], x[:, 1], c=y, cmap="brg")
    plt.xlim(min(x[:, 0]), max(x[:, 0]))
    plt.ylim(min(x[:, 1]), max(x[:, 1]))
    plt.title(modelname)
    plt.colorbar()
    plt.xlabel(x0)
    plt.ylabel(x1)
    plt.show()
```
### SVM
```Python3
showline_clf(x, y, SVC(kernel="linear"), modelname="SVM")
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/89064c71-f21a-e08e-a760-cd9a98dab653.png)


### ロジスティック回帰
```Python3
showline_clf(x, y, LogisticRegression(), modelname="LogisticRegression")
```
![Untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/9e5ec6b4-c677-e7c5-32ee-4603381380a9.png)

### 線形回帰
```Python3
showline_reg(x, y, LinearRegression(), modelname="LinearRegression")
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/c4e74835-4847-6e85-51db-b46c699a879e.png)

### ポアソン回帰
```Python3
showline_reg(x, y, PoissonRegressor(), modelname="PoissonRegressor")
```
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/c930bdb2-ab4b-56aa-5a63-bf7dd7f4153c.png)

こうやって見てみると、ポアソン回帰とロジスティック回帰が少し似ていて、SVMと線形回帰が似ているように見えます。

# まとめ
そりゃアルゴリズム違えば係数は違うよ。

# 参考文献
<a href="https://jakevdp.github.io/PythonDataScienceHandbook/05.08-random-forests.html">In-Depth: Decision Trees and Random Forests</a>