読者です 読者をやめる 読者になる 読者になる

drilldripper’s blog

機械学習とソフトウェア開発を頑張ってます

SVMの基本原理と不均衡データに対するパラメータ調整

Python 機械学習

前回の記事では不均衡データをサンプリングすることで、学習の精度を上げる方法を書きました。今回はSVMのパラメータを調整することで、不均衡データの学習の精度を上げる方法について書こうと思います。
そのためにSVMの基本を理解しておいたほうがよいと思うで、簡単にまとめてみたいと思います。

SVMの基本原理

SVMのイメージは以下のページを見てもらうとわかりやすいと思います。

SVMを使うとなにが嬉しいの?

簡単に言うとSVMの目的は、データを2つのクラスに分離する線を引こうとしたときに、2つのクラスとのユークリッド距離が最も大きくなるようにする(マージンを最大化する)ことです。これだけではわからないと思うので、数式で原理を追ってみます。

正方向の傾きをx_p、負方向の傾きをx_n w をクラスを2つに分離する直線したとき、正の超平面は式(1)、負の超平面は式(2)のように表せます。
w_0 + w^T x_p = 1 \tag{1}
w_0 + w^T x_n = -1\tag{2}
式(1) - 式(2)から式(3)を得ます。

w^T(x_p - x_n) = 2\tag{3}

これをベクトルの長さとして標準化すると式(4)が得られます。

|| w || = \sqrt{\sum_{j=1}^{m} w^2 _ j}\tag{4}

超平面について表した式(3)とベクトルの長さ式(4)から、式(5)が得られます。
\frac{ w^T(x_p - x_n)}{||w||} = \frac{2}{||w||}\tag{5}

左辺は超平面の距離(マージン)なので、右辺を最大化することで最大マージンを得ることができます。
最大マージンを得るためには、式(5)について、式(6)、式(7)の制約を満たすような問題を解く必要があります。

w_0 + w^T x^i \geq 1 \tag{6}
w_0 + w^T x^i < -1 \tag{7}
(iはすべてのデータです)

ただし式(5)の右辺は逆数をとって2乗した\frac{1}{2} ||w||^2を解く方が簡単になることが知られている*1ので、この式を使うことにします。

ここまでがSVMの基本的な原理です。さらにこれを改良して非線形なデータに対しても分類が行えるようにしたいと思います。
制約を緩和するための変数を\zeta*2を式(6)、式(7)に導入して式(8)、式(9)を得ます。

w_0 + w^T x^i \geq 1 - \zeta \tag{8}
w_0 + w^T x^i < -1 + \zeta\tag{9}

これを\frac{1}{2} ||w||^2に当てはめることで式(10)を得ます。
\frac{1}{2} ||w||^2 + C\sum_{i}^{}\zeta^i \tag{10}

これで変数Cの値を変えることで、データの分類に対するペナルティを設定できるようになりました。Cの値を大きくすると誤分類にペナルティを与え、Cの値が小さいときには誤分類を許容するようになります。

不均衡データへの適応

不均衡データの学習がうまくいかない理由は、殆どのデータを偏った大きなクラスに分類することで「正答率」が上がってしまうためです。

例えば天気予報を行うことを考えてみます。天気は一年を通して多くの日が晴れとなるので、仮にすべての日を晴れと予報しても「正答率」は高くなります。しかし当然のことながら、私たちはいつ雨が降るかということが知りたいです。つまり雨の日を晴れの日とご分類するケースをできるだけ少なくしたいということです。これは式(10) においてCの値を大きくするということに値します。

Scikit-learnのSVMではこのCのパラメータを簡単に変更することができます。
以下のように、分類器をインスタンス化するときに引数に設定するだけです。詳しくはドキュメントを読んでみてください。

clf = SVC(kernel='rbf', C=1000)

sklearn.svm.SVC — scikit-learn 0.18.1 documentation

また不均衡データについても公式ドキュメントで触れられているので、目を通しておくといいと思います。
1.4. Support Vector Machines — scikit-learn 0.18.1 documentation

参考文献

*1:二次計画法を使うことで解くことができる

*2:スラック変数といいます