クラス分類問題において、データ数がそれほど多くない場合にまず使用するLinear SVC(SVM Classification)について、実装・解説します。
本シリーズでは、Pythonを使用して機械学習を実装する方法を解説します。
また各アルゴリズムの数式だけでなく、その心、意図を解説していきたいと考えています。
Linear SVCは、以下のscikit-learnマップの黒矢印に対応します。
START→データが50以上→カテゴリーデータ→ラベルありデータ→データ数10万以下→「Linear SVC」
Linear SVCは、カーネルを使用しないSVM(サポートベクトル・マシン)に基づくクラス分類手法です。
実装例
まずはじめに実装例を紹介します。
使用するデータは第1回のSGDと同じくワインの分類データです。
これに対してLinear SVCを行うと、以下のような結果となります。
SGDのときより少し結果が良い気がします。
コードは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | # 1:ライブラリのインポート-------------------------------- import numpy as np #numpyという行列などを扱うライブラリを利用 import pandas as pd #pandasというデータ分析ライブラリを利用 import matplotlib.pyplot as plt #プロット用のライブラリを利用 from sklearn import svm, metrics, preprocessing, cross_validation #機械学習用のライブラリを利用 from mlxtend.plotting import plot_decision_regions #学習結果をプロットする外部ライブラリを利用 # 2:Wineのデータセットを読み込む-------------------------------- df_wine_all=pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None) #品種(0列、1~3)と色(10列)とプロリンの量(13列)を使用する df_wine=df_wine_all[[0,10,13]] df_wine.columns = [u'class', u'color', u'proline'] pd.DataFrame(df_wine) #この行を実行するとデータが見れる # 3:プロットしてみる------------------------------------------------------ %matplotlib inline x=df_wine["color"] y=df_wine["proline"] z=df_wine["class"]-1 #plt.scatter(x,y, c=z) #plt.show # 4:データの整形------------------------------------------------------- X=df_wine[["color","proline"]] sc=preprocessing.StandardScaler() sc.fit(X) X_std=sc.transform(X) #解説 5:機械学習で分類する--------------------------------------------------- clf_result=svm.LinearSVC(loss='hinge', C=1.0,class_weight='balanced', random_state=0)#loss='squared_hinge' #loss="hinge", loss="log" clf_result.fit(X_std, z) # 6:K分割交差検証(cross validation)で性能を評価する--------------------- scores=cross_validation.cross_val_score(clf_result, X_std, z, cv=10) print("平均正解率 = ", scores.mean()) print("正解率の標準偏差 = ", scores.std()) # 7:トレーニングデータとテストデータに分けて実行してみる------------------ X_train, X_test, train_label, test_label=cross_validation.train_test_split(X_std,z, test_size=0.1, random_state=0) clf_result.fit(X_train, train_label) #正答率を求める pre=clf_result.predict(X_test) ac_score=metrics.accuracy_score(test_label,pre) print("正答率 = ",ac_score) #plotする X_train_plot=np.vstack(X_train) train_label_plot=np.hstack(train_label) X_test_plot=np.vstack(X_test) test_label_plot=np.hstack(test_label) #plot_decision_regions(X_train_plot, train_label_plot, clf=clf_result, res=0.01) #学習データをプロット plot_decision_regions(X_test_plot, test_label_plot, clf=clf_result, res=0.01, legend=2) #テストデータをプロット # 8:任意のデータに対する識別結果を見てみる------------------ #predicted_label=clf_result.predict([1,-1]) #print("このテストデータのラベル = ", predicted_label) # 9:識別平面の式を手に入れる-------------------------------- print(clf_result.intercept_) print(clf_result.coef_ ) #coef[0]*x+coef[1]*y+intercept=0 |
コードに関してはSGDのときとほぼ同じです。
解説5の部分だけ異なります。
#解説 5:機械学習で分類する—————————————————
clf_result=svm.LinearSVC(loss=’hinge’, C=1.0,class_weight=’balanced’, random_state=0)
このコードは、識別器としてLinearSVCを使用します。
分類ミスに対して損失の大きさにhinge関数を使用します。
損失の大きさをどれくらい考慮するかを決めるパラメータCは1.0とします。
またクラスごとのデータ数の違いを補正します(weight=’balanced’)。
乱数のシードは0に固定しておきます。
という命令になっています。
今回はクラスが3つあるので、マルチクラスの分類です。
Linear SVCは、“one versus all” (OVA) もしくは“one-vs-the-rest” と呼ばれ、クラス1とその他、クラス2とその他、クラス3とその他を分ける線を求めて分離します。
つまり識別器の数はクラス数と同じになります。
今回は3つです。
それでは「結局、Linear SVCって何をやっていたの?」を説明します。
Linear SVCの心
正確な情報は以下をご覧ください。
SVCはサポートベクトルマシンというアルゴリズム手法に基づいて、線形な識別平面を作成します。
非線形な識別平面が欲しい場合にはカーネル関数でデータから非線形成分を作成します。
(カーネルについて詳細は第2回のカーネル近似をごらんください。)
ただし、Linear SVCはカーネルは使用せずに、ただデータから線形な識別平面を作成します。
それではSGDで損失関数を最小化しているのと違いが分かりにくい・・・
と感じますが、かなり違うアルゴリズムになっています。
SVMを理解するには、ハードマージンSVMとソフトマージンSVMを理解する必要があります。
まずはハードマージンSVMから説明します。
これは完全に識別平面で学習データが分類できるケースの問題です。
そのときにどう識別平面を作成するのかですが、損失関数などは使用しません。
代わりに識別平面からそれぞれのクラスの最も近い点までの距離が最大となるようなところに識別平面を引きます。
マージン最大化と呼びます。
この問題はすなわち
f(w)→最大
ただし、g(w, D)→ちゃんと識別できている
という条件付最大化問題となります。
ここでwは求めたい識別平面の係数ベクトル、f(w)は一番近い点までの距離、g(w,D)は全データDに対して、wで決まる識別平面で識別した結果を示します。
ですが、この問題はg(w,D)が解きにくいです。
そこでラグランジェの未定乗数法という手法を使用して、拘束条件であったg(w,D)を扱いやすい形のものに置き換える工夫を行います。
その結果、
1.4.7.1. SVCの、dual以下の式となります。
なおここまでの解説は以下のページがとても分かりやすいです。
以上がハードマージンSVMですが、識別平面で学習データが100%完璧に識別できるとは限りません。
その場合識別をうまくいかないデータに対して損失関数を定義し、その損失を考慮してSVMを行う必要があります。
それがソフトマージンSVMです。
このとき損失関数として実装例ではhinge関数を使用しました。
この各データの損失の大きさを求めた変数をスラック変数と呼びます。
また、損失関数をどれくらい考慮するのかを変数Cでコントロールします。
Cが小さい損失を許し、Cが大きいほど損失を大きく計上します。
つまりCが無限のときはハードマージンSVMとなります。
損失関数はdefaultではhingeの2乗関数が使用されます。
以上が、Linear SVMの心となります。
SGDとのLinear SVMの違いを簡単に整理します。
SGDは外れ値があったときに、その点が大きな誤差になりひっぱられます。
一方でSVMはマージン最大化がメインであり識別平面近傍の点で決まるので、外れ値に影響されにくいです(ソフトマージンの逆側に外れ値がある特殊な場合以外は・・・)。
以上、Pythonとscikit-learnで学ぶ機械学習入門|第3回:クラス分類 -Linear SVC-でした。
次回は、k近傍法について解説します。