分類モデル比較（データ可視化→学習→予測結果可視化→評価関数の比較）※testver

# 0. はじめに

分類モデルの構築、評価について、
理論・実装を合わせて整理するために投稿いたしました。

学習モデル・評価関数等一部を更新する等で、ご利用いただければ幸いです。


# 1. データセットの可視化


- 学習データ
    - x:説明変数 $[(x_{11},x_{12},...x_{1M}),...(x_{N1}...x_{NM}) ]$
    - y:目的変数 $y_1, y_2, ...y_N$

        - N:サンプル
        - M:説明変数の数 


```math
\begin{pmatrix}
x_{11} &x_{12} & ... &x_{1M} \\
x_{21} &x_{22} & ... &x_{2M} \\
：     &       &     & \\
x_{N1} &x_{N2} & ... &x_{NM} 
\end{pmatrix}
```


```python

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

```

## 1.1. 表

```python
iris_df = sns.load_dataset('iris') # データセットの読み込み
iris_df.head()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/e0eb49a0-644d-9ea3-f3e0-a30e67caf869.png)


## 1.2. 散布図

```python
sns.pairplot(iris_df,  hue='species')
```
![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/f4854b67-b6d9-d304-398e-b96b199ae392.png)

#2. 学習
##2.0.訓練データ(train)・テストデータ(test)に分割する

```python
from sklearn.model_selection import train_test_split


X = iris_df[['sepal_length','sepal_width','petal_length','petal_width']] # 説明変数
Y = iris_df['species']

#訓練データ80%、テストデータ20%に分割。
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2, random_state = 0) # 80%のデータを学

```

##2.1. ロジスティック回帰

モデル : $Y_{pred} = \pi(\alpha  X + \beta) $

ロジスティック関数：$\pi = \frac{e^x}{(1 + e^x)}$


```python
from sklearn.linear_model import LogisticRegression


model_LR = LogisticRegression() # ロジスティック回帰モデルのインスタンスを作成
model_LR.fit(X_train.to_numpy(), Y_train.to_numpy()) # ロジスティック回帰モデルの重みを学習
```

## 2.2. サポートベクターマシン 

マージン(識別境界と、識別境界と最短距離のサンプル　との距離)を最大化

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/2cc88e63-0e7e-8980-c0c1-f080a550bac6.png)

```python
from sklearn.svm import LinearSVC

model_LinearSVC = LinearSVC() # サポートベクターマシンのインスタンス生成
model_LinearSVC.fit(X_train, Y_train) # サポートベクターマシンモデルの重みを学習

```


## 2.3. Kmeans

1. クラスター数KとK個の重心を決める。
2. クラスター(重心)の位置が変化しなくなるまで、以下を繰返す。
    1. 各サンプルX_i     とクラスターK(重心)との距離を計算。
    2. で計算した距離が最も近いクラスターに、各サンプルを割り当てる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/c130ec37-698c-f0d6-9d3f-f752358d31a2.png)

```python
from sklearn.cluster import KMeans

kmeans = KMeans(n_clusters=len(iris_df["species"].unique()))
model_kmeans = kmeans.fit(X)
```

## 2.4.ニューラルネットワーク
### ニューラルネットワークの学習

- 目的：損失関数を最小化するような、モデルのパラメータ$W$を求める。
    - 損失関数: $L = (正解 - モデルによる予測値)^2$
    - モデルによる予測値： $activation( W_2  activation(W_1 X))$   ※中間層2つの時
        - activation:活性化関数
        - $W_i$: 中間層iの重みベクトル
        - X:説明変数


### MLPClassifier のパラメータについて
- hidden_layer_size: 中間層の層数および、各中間層のニューロン数
    - (50,50,50)の場合、中間層は3つ。各中間層のニューロン数は、それぞれ50。
- activation: 中間層の活性化関数
    - identity（恒等関数）: $f(x) = x$
    - relu（ReLU関数）:　
        $f(x) = \begin{cases} 
         0 & (x \leq 0) \\
         x & (x > 0)
                \end{cases}
        $
    - logistic（シグモイド関数）: $f(x) = \frac{e^x}{1+e^x}$
    
- solver:重みWを最適化する方法
    - sgd: 確率的勾配降下法
    - adam: 
    - lbfgb:準ニュートン法
    
- max_iter:学習反復回数の、"最大回数"

```python
from sklearn.neural_network import MLPClassifier


model_NN = MLPClassifier(hidden_layer_sizes=(50,50,50), max_iter=1000, activation = "relu", solver = "sgd")
model_NN.fit(X_train, Y_train)

```


# 3. 識別境界の可視化 
## 3.3 K近傍法 （教師なし学習の一種）

```python
#iris_df = iris_df[["petal_length","petal_width", "species"]] 
iris_df["cluster"] = model_kmeans.labels_


markers = ["o", "x", "+"] #正解ラベルごとに図形を変える。
pos = 0

for i in iris_df["cluster"].unique():
    tmp = iris_df.loc[iris_df["cluster"] == i]
   #plt.scatter(tmp.loc["petal_length"], tmp.loc["petal_width"])
    plt.scatter(tmp["petal_length"], tmp["petal_width"], marker = markers[pos])
    pos += 1
    
plt.title("Scatter Plot of Kmeans")
plt.xlabel("petal_length")
plt.ylabel("petal_width")
plt.show()

```
![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/507d071e-178a-8ad9-fc0d-559a5d4edf7e.png)

# 4. 評価指標ごとの精度

## 4.1. 評価指標を計算

### 評価指標
    - confusion_matrix（混同行列）
    - logloss (交差エントロピー誤差)
    
    
### confusion_matrix

|          |        |Predict(学習モデルの予想)|    |
|----------|--------|-------------------------|--------|
|          |        |Negative|Positive|
|True(正解)|Negative|TN      |FP      |
|          |Positive|FN      |TP      |

- TP(True Positive): モデルがPositiveと予想し、正解(True)
- TN(True Negative): モデルがNegativeと予想し、正解(True)
- FP(True Positive): モデルがPositiveと予想し、不正解(False)
- FN(True Negative): モデルがNegativeと予想し、不正解(False)


### 交差エントロピー誤差 $H(x)$

$H(p, q) = - \sum_{1}^{クラス数} p(x)log(q(x)) $
- p: 正解$y_{true}$の確率分布
- q: 学習モデルが予測した目的変数の値$y_{predict}$の確率分布

#### p:[1.0,0.0,0.0], q:[0.7, 0.2,0.1] の場合
$ H(p, q) = - (1.0 \times \log(0.7) + 0.0 \times 0.2 + 0.0 \times 0.1) $ 　<br>
    = - log(0.7)


```python

from sklearn.metrics import accuracy_score 
from sklearn.metrics import log_loss
from sklearn.preprocessing import OneHotEncoder
from sklearn.metrics import confusion_matrix

#評価のため、目的変数の値を数値型へ変換する。
Y_test = Y_test.replace({"virginica":0,"setosa":1,"versicolor":2})
Y_test = pd.DataFrame(Y_test)

#logloss計算用に、目的変数の値をOneHot表現に変換。予測値(Y_pred*)のみ変換。
encoder_OneHot = OneHotEncoder(categories="auto", sparse=False, dtype=np.float32)

Y_test_OneHot = encoder_OneHot.fit_transform(Y_test)

#ロジスティック回帰
Y_pred_LR =  model_LR.predict(X_test)
Y_pred_LR = pd.DataFrame(Y_pred_LR).replace({"virginica":0,"setosa":1,"versicolor":2})
Y_pred_LR_OneHot = encoder_OneHot.fit_transform(Y_pred_LR)


cm_LR = confusion_matrix(Y_test, Y_pred_LR)
logloss_LR = log_loss(Y_test, Y_pred_LR_OneHot)

#サポートベクターマシン
Y_pred_LinearSVC =  model_LinearSVC.predict(X_test)
Y_pred_LinearSVC = pd.DataFrame(Y_pred_LinearSVC).replace({"virginica":0,"setosa":1,"versicolor":2})
Y_pred_LinearSVC_OneHot = encoder_OneHot.fit_transform(Y_pred_LinearSVC)

cm_LinearSVC = confusion_matrix(Y_test, Y_pred_LinearSVC)
logloss_LinearSVC = log_loss(Y_test, Y_pred_LinearSVC_OneHot)


#kmeans
Y_pred_kmeans =  model_kmeans.predict(X_test)
Y_pred_kmeans = pd.DataFrame(Y_pred_kmeans)
Y_pred_kmeans_OneHot = encoder_OneHot.fit_transform(Y_pred_kmeans)

cm_kmeans = confusion_matrix(Y_test, Y_pred_kmeans)
logloss_kmeans = log_loss(Y_test, Y_pred_kmeans_OneHot)

#ニューラルネットワーク
Y_pred_NN =  model_NN.predict(X_test)
Y_pred_NN = pd.DataFrame(Y_pred_NN).replace({"virginica":0,"setosa":1,"versicolor":2})
Y_pred_NN = pd.DataFrame(Y_pred_NN)
Y_pred_NN_OneHot = encoder_OneHot.fit_transform(Y_pred_NN)

cm_NN = confusion_matrix(Y_test, Y_pred_NN)
logloss_NN = log_loss(Y_test, Y_pred_NN_OneHot)

```

## 4.2.評価結果を可視化
### 4.2.1. Confusion_matrix （混同行列）
#### ロジスティック回帰

```python
cm_LR = pd.DataFrame(data=cm_LR, index=["virginica", "setosa", "versicolor"], 
                           columns=["virginica", "setosa", "versicolor"])

sns.heatmap(cm_LR, square=True, cbar=True, annot=True, cmap='Blues')
plt.xlabel("True Label", fontsize=15)
plt.ylabel("Predict", fontsize=15)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/4495eb1e-3a40-da18-af0b-bd229540dc0d.png)





#### サポートベクターマシン
```python
cm_LR = pd.DataFrame(data=cm_LinearSVC, index=["virginica", "setosa", "versicolor"], 
                           columns=["virginica", "setosa", "versicolor"])

sns.heatmap(cm_LinearSVC, square=True, cbar=True, annot=True, cmap='Blues')
plt.xlabel("True Label", fontsize=15)
plt.ylabel("Predict", fontsize=15)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/586923c7-683d-ea00-6fa9-a0eb4ee2724a.png)


####ニューラルネットワーク
```python
cm_NN = pd.DataFrame(data=cm_NN, index=["virginica", "setosa", "versicolor"], 
                           columns=["virginica", "setosa", "versicolor"])

sns.heatmap(cm_NN, square=True, cbar=True, annot=True, cmap='Blues')
plt.xlabel("True Label", fontsize=15)
plt.ylabel("Predict", fontsize=15)
plt.show()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/1469e126-3961-dd08-e85d-1029e9ac1922.png)


### 4.2.2. Logloss
```python
logloss = pd.DataFrame([[logloss_LR],[logloss_LinearSVC],[logloss_kmeans],[logloss_NN]],
                       index = ["LR","LinearSVC","kmeans","logloss_NN"],columns = ["logloss"])
logloss
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194473/02972494-a44c-3830-8e8a-43e0d4f3a460.png)