カーネルSVM（make_circles）

## ■ はじめに
今回は、簡単なカーネルSVMの実装をまとめていきます。

【対象とする読者の方】
・カーネルSVMの簡単なコードを学びたい方
・理論は分からないが、実装を見てイメージをつけたい方　など
<br>
## ■ カーネルSVMの手順

次の7つのSTEPで進めます。

1. モジュールの用意
2. データの準備
3. データの可視化
4. モデルの作成
5. モデルのプロット
6. 予測値の出力
7. モデルの評価
<br>

##1. モジュールの用意
最初に、必要なモジュールをインポートしておきます。

```python

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

from sklearn.datasets import make_circles
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.metrics import accuracy_score, f1_score
from sklearn.metrics import confusion_matrix, classification_report
```

<br>
##2. データの準備
今回はsklearnに用意されている、make_circlesというデータセットを使用します。

最初にデータの取得をし、標準化を行ってから分割します。

```python

X , y = make_circles(n_samples=100, factor = 0.5, noise = 0.05)

std = StandardScaler()
X = std.fit_transform(X)
```
標準化は、例えば2桁と4桁の特徴量（説明変数）があった際に、後者の影響が大きくなってしまうため
全ての特徴量に対して平均が0・分散は1になるように調整して、スケールを揃えています。

```python

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state=123)

print(X.shape)
print(y.shape)
# (100, 2)
# (100,)

print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)
# (70, 2)
# (70,)
# (30, 2)
# (30,)
```
<br>

##3. データの可視化
カーネルSVMで、二値分類をする前のデータプロットを見ておきます。

```python

fig, ax = plt.subplots()

ax.scatter(X_train[y_train == 0, 0], X_train[y_train == 0, 1], c = "red", label = 'class 0' )
ax.scatter(X_train[y_train == 1, 0], X_train[y_train == 1, 1], c = "blue", label = 'class 1')

ax.set_xlabel('X0')
ax.set_ylabel('X1')
ax.legend(loc = 'best')

plt.show()
```
class 0 (y_train ==0) に対応する特徴量（X0 を横軸, X1 を縦軸）：赤
class 1 (y_train ==1) に対応する特徴量（X0 を横軸, X1 を縦軸）：青
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/725082/366a1e2a-da76-acd2-675d-172ec6c4cd67.png)
上記は少し冗長なコードとなっていますが、簡潔に短く書くことも可能です。

```python

plt.scatter(X_train[:, 0], X_train[:, 1], c = y_train)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/725082/013e826e-a567-b8a4-366b-69b70f3211af.png)
##4. モデルの作成
カーネルSVMのインスタンスを作成し、学習させます。

```python

svc = SVC(kernel = 'rbf', C = 1e3, probability=True)
svc.fit(X_train, y_train)
```
今回はすでに線形分離（1本の直線で分ける）が不可能なため、引数に kernel = 'rbf' を設定しています。

また C はハイパーパラメータで、出力数値やプロットを見ながら自身で調整していくものです。
<br>
##5. モデルのプロット
カーネルSVMのモデルが作成できたので、プロットして確認します。

前半は、先ほどの散布図コードと全く同じです。
それ以降は少し難しいですが、そのままペーストするだけで、他データでもプロットできます。
（多少の微調整は必要となります）

```python

fig, ax = plt.subplots()
    
ax.scatter(X_train[y_train == 0, 0], X_train[y_train == 0, 1], c='red', marker='o', label='class 0')
ax.scatter(X_train[y_train == 1, 0], X_train[y_train == 1, 1], c='blue', marker='x', label='class 1')

xmin = -2.0
xmax = 2.0
ymin = -2.0
ymax = 2.0

xx, yy = np.meshgrid(np.linspace(xmin, xmax, 100), np.linspace(ymin, ymax, 100))
    
xy = np.vstack([xx.ravel(), yy.ravel()]).T
p = svc.decision_function(xy).reshape(100, 100)  
ax.contour(xx, yy, p, colors='k', levels=[-1, 0, 1], alpha=1, linestyles=['--', '-', '--'])

ax.scatter(svc.support_vectors_[:, 0], svc.support_vectors_[:, 1],
           s=250, facecolors='none', edgecolors='black')
    
ax.set_xlabel('X0')
ax.set_ylabel('X1')
   
ax.legend(loc = 'best')
    
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/725082/1302a0ab-960e-c40a-fba2-c44eccd7b344.png)
##6. 予測値の出力
作成したモデルで、分類の予測値を出していきます。

```python

y_proba = svc.predict_proba(X_test)[: , 1]
y_pred = svc.predict(X_test)

print(y_proba[:5])
print(y_pred[:5])
print(y_test[:5])

# [0.99998279 0.01680679 0.98267058 0.02400808 0.82879465]
# [1 0 1 0 1]
# [1 0 1 0 1]
```
<br>
##7. 性能評価
ROC曲線を用いて、AUCの値を求めます。

```python

fpr, tpr, thresholds = roc_curve(y_test, y_proba)
auc_score = roc_auc_score(y_test, y_proba)
plt.plot(fpr, tpr, label='AUC = %.3f' % (auc_score))
plt.legend()
plt.title('ROC curve')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.grid(True)

print('accuracy:',accuracy_score(y_test, y_pred))
print('f1_score:',f1_score(y_test, y_pred))

# accuracy: 1.0
# f1_score: 1.0
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/725082/42395cd6-e05f-fef1-6928-f1825bc0d6e7.png)

```python

classes = [1, 0]
cm = confusion_matrix(y_test, y_pred, labels=classes)

cmdf = pd.DataFrame(cm, index=classes, columns=classes)

sns.heatmap(cmdf, annot=True)
print(classification_report(y_test, y_pred))

'''
              precision    recall  f1-score   support

           0       1.00      1.00      1.00        17
           1       1.00      1.00      1.00        13

    accuracy                           1.00        30
   macro avg       1.00      1.00      1.00        30
weighted avg       1.00      1.00      1.00        30

'''
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/725082/b5c2607c-7f30-3fa3-8412-fca0e2956f9d.png)
<br>
##■ 最後に
上記1～7の手順をもとに、カーネルSVMのモデル作成・性能評価ができました。

初学者の方にとって、少しでもお役に立てたようでしたら幸いです。
<br>
## ■ 参考文献
・[Pythonによるあたらしいデータ分析の教科書](https://www.shoeisha.co.jp/book/detail/9784798158341)