サポートベクターマシーンのパラメータをいろいろといじってみる(画像データの分類問題)

##初めに
機械学習の教科書では(紙面の都合上やらなさそうな)様々なパラメータを変えた際にどのように変化するのかについて、SVCを用いてやってみました。<br>ちなみに使用したのは0~9までの数字が書かれたDigitsの画像データ。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3134313939332f63636565353763652d363234612d363964662d613731392d6663306366656430633838382e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/141993/bc394ef3-b66d-025a-0846-f80ce435222c.png)

Digitsのデータについて[こちら](https://qiita.com/koryor/items/930f1e516280a856fbc0)で可視化等は行ってみています。

##LinearSVC

まずはsvm.LinearSVCで正則化定数Cのチューニングを行ってみたいと思います。カーネル法を試す前に線形のSVMから始めた方が良いらしいです。結果はロジスティクス回帰分析とだいたい同じような感じになります。<br>svm.LinearSVCはLinearに特化したアルゴリズムのため、svm.SVCよりも高速で動くとのこと(未検証)<br>交差検証は10分割で行い、正答率の平均値を今回はscoreとして、プロットしてみました。(本来はテストデータを訓練データを分けてから交差検証した方が、よいでしょうが、今回は省略)

```python
# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
from sklearn import model_selection
from sklearn import datasets
from sklearn import svm

digits = datasets.load_digits()
data = digits["data"]
target = digits["target"]

#正則化の変数
alpha = [0.0001,0.001,0.01,0.1,1.,10.,100.,1000.]

#alphaに対応する交差検証の精度を記録する配列
accuracy = np.empty([len(alpha)])
for i in np.arange(len(alpha)):    
    clf = svm.LinearSVC(C=alpha[i])
    #cross validation
    cv_clf = model_selection.cross_validate(clf,data,target,cv=10)
        #test_scoreの平均値をscoreとして記録
    accuracy[i]= np.mean(cv_clf["test_score"])

plt.subplot(211)
plt.plot(alpha,accuracy)
plt.ylim(0,1)
plt.xscale("log")
plt.xlabel("C")
plt.ylabel("accuracy score")

plt.subplot(212)
plt.plot(alpha,accuracy)
plt.ylim(0.9,1)
plt.xscale("log")
plt.xlabel("C")
plt.ylabel("accuracy score")
plt.show()

```
結果の上のグラフは正答率スコアが0~100％の範囲、下のグラフは正答率スコアが90~100％の範囲に拡大したものである。<br>![figure1.png](https://qiita-image-store.s3.amazonaws.com/0/141993/cdbb07ae-cf0a-e93a-d964-37a5d53c2338.png)
最大の正答率はC=0.001の時の93.9％でした。

Digitsのそれぞれのピクセルは0~16までの数字で明るさが表現されています。そこでピクセルの明るさを0~1になるように変更。

```python
digits = datasets.load_digits()
data = digits["data"]
target = digits["target"]

#データが0~1の範囲になるように変更
data/=16

#正則化の変数
alpha = [0.00001,0.0001,0.001,0.01,0.1,1.,10.,100.,1000.,10000.]
```
正答率はC=1.0で最大で94.0％。0.1%良くなっているけど、誤差の範囲かな…。正答率が高いCの値が最初より大きくなった。<br>![figure2.png](https://qiita-image-store.s3.amazonaws.com/0/141993/6c3dc23c-7a8e-c1c1-9848-f27700552d83.png)




#主成分分析+LinearSVC

今度はLinearSVCの前に主成分分析を行ってからLinearSVCをやってみる。

```python

digits = datasets.load_digits()
data = digits["data"]
target = digits["target"]

#データが0~1の範囲になるように変更
data/=16

#dataに主成分分析
pca = PCA()
data = pca.fit_transform(data)

#正則化の変数
alpha = [0.00001,0.0001,0.001,0.01,0.1,1.,10.,100.,1000.,10000.]
```
![figure3.png](https://qiita-image-store.s3.amazonaws.com/0/141993/a09a9d99-e29b-a0a5-4d8b-8e77aad16573.png)

正答率最大はC=0.1の時の94.1％、やっぱり0.1%良くなっているけど、誤差の範囲かな…。

##SVCのlossを変更してみる

svm.LinearSVCのlossはsquared_hinge（デフォルト)
lossにhinge変更

```python
digits = datasets.load_digits()
data = digits["data"]
target = digits["target"]

#正則化の変数
alpha = [0.0001,0.001,0.01,0.1,1.,10.,100.,1000.,10000.]

#alphaに対応する交差検証の精度を記録する配列
accuracy = np.empty([len(alpha)])
for i in np.arange(len(alpha)):    
    clf = svm.LinearSVC(C=alpha[i],penalty="l2",loss="hinge")
    #cross validation
    cv_clf = model_selection.cross_validate(clf,data,target,cv=10)
        #test_scoreの平均値をscoreとして記録
    accuracy[i]= np.mean(cv_clf["test_score"])
```
![ssss.png](https://qiita-image-store.s3.amazonaws.com/0/141993/a78a7fa1-762f-296c-d90e-2432dbe10030.png)
94.0%で変わらず…


##カーネルSVM

非線形問題にも対応できるカーネルSVMを使ってチューニングしてみる。linearは上でやったのでkernel="rbf"で固定。

```python

# -*- coding: utf-8 -*-
"""
sklearn 0.19.1
"""

import numpy as np
import matplotlib.pyplot as plt
from sklearn import model_selection
from sklearn import datasets
from sklearn import svm

digits = datasets.load_digits()
data = digits["data"]
target = digits["target"]

#正則化の変数
alpha = [0.0001,0.001,0.01,0.1,1.,10.,100.,1000.]

#jはsvcのパラメーターガンマ
for j in [0.0001,0.001,0.01,0.1]:
    #alphaに対応する交差検証の精度を記録する文字列
    accuracy = np.empty([len(alpha)])
    for i in np.arange(len(alpha)):        
        clf = svm.SVC(gamma=j,C=alpha[i],kernel="rbf")
        #cross validation
        cv_clf = model_selection.cross_validate(clf,data,target,cv=10)
        accuracy[i]= np.mean(cv_clf["test_score"])

    plt.subplot(211)
    plt.plot(alpha,accuracy,label=str(j))
    plt.ylim(0,1)
    plt.xscale("log")
    plt.ylabel("accuracy score")

    plt.subplot(212)
    plt.plot(alpha,accuracy,label=str(j))
    plt.ylim(0.9,1)
    plt.xscale("log")
    plt.xlabel("C")
    plt.ylabel("accuracy score")

plt.subplot(211)
plt.legend(loc="upper left")
plt.subplot(212)
plt.legend(loc="upper left")
plt.show()
```
γが0.1の時に赤,γが0.01の時に緑,0.001の時にオレンジ,0.0001の時青である。

![sv.png](https://qiita-image-store.s3.amazonaws.com/0/141993/324a1eb2-86cc-53e6-7e22-b09285dfe357.png)

正答率は最大でγ=0.001,C=10の時で98.1%。Cの値が10より大きくなっても同様の正答率を維持していた。やはりLinearSVCよりかなり精度が高い。

###kernelを変更してみる
kernel="rbf"をkernel="poly"に変更するだけ!

clf = svm.SVC(gamma=j,C=alpha[i],kernel="poly")

![poly.png](https://qiita-image-store.s3.amazonaws.com/0/141993/f46606c7-0277-fc5b-d725-0432df571906.png)
正答率は97.8%でrbfには及ばず。


##最後に

scikit_learnのSVMのパラメータをいろいろと変更してみました。<br>defaultと比較して、中々精度は向上せず、残念。<br>defaultが良い案配の設定になっています。<br>SVMを試す際はまずはdefaultでいったん精度を確認した方が良さそうですね。