Lesson3: SVM まとめ Intro to Machine learning@Udacity

#Lesson3の概要
SVMはよく使われる教師あり学習のアルゴリズムで、
SVMは2クラスの入力に対し、それを分割する超平面を出力する。
超平面は近傍のデータからの距離(マージン)を最大化するような位置にひかれる。
使い方は[1.4. Support Vector Machines¶](https://scikit-learn.org/stable/modules/svm.html#svm-classification)参照。


#講義内容

手順の基本は
インポート→分類器(clf)生成→clf.fitで学習→clf.predictで推定
の手順

```python
##ドキュメンテーションの例そのまま
from sklearn import svm
X = [[0, 0], [1, 1]]
y = [0, 1]
clf = svm.SVC(gamma='scale')#生成
clf.fit(X, y)  #学習
clf.predict([[2., 2.]])#推定
```

ドキュメンテーションを読むと、
>Support vector machines (SVMs) are a set of supervised learning methods used for classification, regression and outliers detection.
と書いてある。分類、回帰、外れ値検知にも使えるみたい。
Lesson8で外れ値の話があるから、そこも参照したい。

SVMは基本、線形(直線)でしか分類できないが**kernelトリックを使えば、非線形でも分類できる。**
SVMには低次元の入力を高次元の座標へマッピングする機能がある。そうすると、高次元空間では、線形で分類でき、それを低次元空間にマッピングしなおせば、非線形で分類できる。
ただ、この説明はkernel法を知っている人からしたら気持ちが悪いらしい。
[機械学習におけるカーネル法について](http://enakai00.hatenablog.com/entry/2017/10/13/145337)
正直読んでもよくわからんかった。。。

どのような高次元空間にマッピングするかは、人が選ばなきゃなのかな？それもそれで、大変だよね。

<SVCのパラメーター>
引数としては、kernel, C, gammaの3つを主につかう。
・kernel・・・‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’ or a callableのうちのどれかを指定。デフォルトはrbf。

・C・・・[ドキュメンテーション](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC)によると、誤差の罰則項みたい。大きくすれば誤差が小さくなる→境界がより複雑に入り組んだ形になると解説してくれている。つまり過学習しやすいってことですね。

・gamma・・・デフォルト0。‘rbf’, ‘poly’ and ‘sigmoid’のkernel係数というものらしい。下図参照。![svm.gif](https://qiita-image-store.s3.amazonaws.com/0/333380/28cffa28-8431-375a-b012-62c752f35ba9.gif)

上記のパラメーターを調整して過学習を防いでいく。

SVMは境界が複雑でないデータ（可能なら線形分離できる）の分類に適している。あと、ノイズが少ないもの。ノイズが入っていたり、複雑なデータだと、距離の計算をしているので、計算時間が膨大にかかるのが弱点。

#Mini-project
[Lesson2:Naive Bayes](https://qiita.com/Allovertom/items/11115145d4a3ff53d1e4)の時と一緒で、メールの分類を行う。後半では、パラメーターによって、計算時間がどのくらいかかるかも見ていく。
video28-29ではlinearで、分類して精度・学習時間がかかるかを見ていく。

```python:svm_author_id.py
#########################################################
### your code goes here ###
from sklearn import svm
from sklearn.metrics import accuracy_score

clf = svm.SVC(kernel='linear')
t0 = time()
clf.fit(features_train, labels_train)
print "training time:", round(time()-t0,3),"s"  
t1 = time()
pred = clf.predict(features_test)
print "predicting time:", round(time()-t1,3),"s"
accuracy = accuracy_score(labels_test, pred)
print "accuracy=",accuracy
print "END processing"

```
出力
no. of Chris training emails: 7936
no. of Sara training emails: 7884
training time: 520.904 s
predicting time: 58.787 s
accuracy= 0.9840728100113766
END processing


学習時間がNaive [Bayes:lesson2](https://qiita.com/Allovertom/items/11115145d4a3ff53d1e4)に比べて10倍くらいかかってますね。推定も時間かかってるなぁ。

video30(ビデオないけど)では、これを早くするには、trainingデータを1/100にする。この時の背反は精度が落ちること。
実行すると　0.885　となる。これ以降はパラメーターチューニングしていくので、1/100の分量のデータであたりをつけながら進める。

もし学習時間が優先事項であれば、**少しの精度の犠牲で、時間が1/100になるので、このようなことを考えてもいいのかもしれない。**例えば、クレジットカードの異常使用検知やSiriのような音声認識の場合。

video32では、
clf = svm.SVC(kernel='linear')
↓
clf = svm.SVC(C=x, kernel='rbf')
とした場合に精度はどうなるか？

出力
0.616
まだ、あてずっぽうよりはいいのかな。

video 33,34では
Cを10, 100, 1000, 10000とパラメーターを振って精度を見ていく。
10000の時に精度が0.892と一番よくなった。
個人的にはCを順に大きくしていくと、どこかで過学習して、精度下がるのかなと思ったけど、その現象は起こらなかった。

video35：一般に、パラメーターチューニングして、学習量が多いと、いい精度になることが知られている。このため、rbfの分類器で、C=10000、学習量を1/100解除で学習させた場合、どうなるか

```python

for x in [10000]:
    print "C=",x    
    clf = svm.SVC(C=x, kernel='rbf')
    t0 = time()
    clf.fit(features_train, labels_train)
    print "training time:", round(time()-t0,3),"s"  
    
    t1 = time()
    pred = clf.predict(features_test)
    print "predicting time:", round(time()-t1,3),"s"
    
    accuracy = accuracy_score(labels_test, pred)
    print "accuracy=",accuracy
print "END processing"

```
出力
no. of Chris training emails: 7936
no. of Sara training emails: 7884
C= 10000
training time: 360.181 s
predicting time: 29.977 s
accuracy= 0.9908987485779295
END processing

あれ、rbfのほうが学習時間160秒くらい早い。へー。
forが入っているのはパラメーターCを振ったときの名残。

video38では、クリスと推定されたtestデータがいくつあるか聞かれた。
上記コードに、下記コードを加えた。

```python

 Chri = 0
Sar = 0
AllEmails = len(pred)

for x1 in range(AllEmails):
    if pred[x1] == 1:
        Chri += 1
    elif pred[x1] ==0:
        Sar += 1
print "Chris ", Chri
print "Sara ", Sar
print "ALL", AllEmails
```

出力
Chris  877
Sara  881
ALL 1758

答えは877

最後のビデオでは、
・SVMはtext learningには向いていない(Naive Bayesが向いている)。
・問題に対し、いろんなアルゴリズムの特徴を知った上で、どれを適用するのがよいか見極められるようになることがポイント。
・パラメーターチューニングはやらなきゃだが、このコースの後半では、それを自動でやってくれるGridCVを紹介する。
そのレッスンはこちら:[Lesson14: Validationまとめ](https://qiita.com/Allovertom/items/1847a7fc9b1e8fca1965)
簡単に言うと、GridCVにアルゴリズムとパラメーターを指定して渡せば、それぞれに振ったclfを生成して、一番精度のいいclfを返してくれる。

#まとめ・感想
・text learningはSVMよりNaive Bayes!
・SVMはkernelトリック使えば非線形も分類可能！
・学習スピード重視の場合は、あえて学習量を減らすのも手(パラメーターチューニング時、音声認識時等)

カーネルトリックの考え方をもう少し詳しく知りたい。

#調べた英単語
hyperplane・・n, 超平面
coefficient・・・n, 係数、率
polynomial・・・adj, 多項式の