SVM~カーネル法

概要

書籍”Pythonではじめる機械学習”の2.3.7 カーネル法を用いた”サポートベクタマシン”の写経

線形特徴量の非線形化

線形モデルでは分離不可能なデータ

以下は、scikit-learnのmake_blobs()により生成した2特徴量、2クラス分類のデータに線形サポートベクターマシンを適用した例。このとき、決定境界は以下のように得られる。

(1)    \begin{gather*} b + w_0 f_0 + w_1 f_1 = 0\\ b \approx -0.2817,\; w_0 \approx 0.1261,\; w_1 \approx -0.0918 \end{gather*}

決定境界より上側では多項式の値は負となり、下側では正となるが、この境界は明らかに2つのクラスを分割していない。このように単純な例でも、線形モデルでは的確なクラス分類はできない。

以下のコードでは、原典と以下が異なっている。

  • 収束しないという警告を受けて、LinearSVCmax_iterをデフォルトの1000より大きな値としている

非線形特徴量の追加

ここで、特徴量1の2乗を新たな特徴量として加える。この場合、3つの特徴量に対して3次元空間内に各点が位置し、それぞれがクラス0/1に属している。新たな特徴量の追加によって、その軸の方向に各点が立ち上がり、真ん中の三角形の点群と両側の丸印の点群が平面でうまく分割できそうである。

このデータセットに対して、線形SVMを適用し、決定境界を描いたのが以下の画像。特徴量が2つの場合の決定境界は直線だったが、特徴が3つになると決定境界は平面となる。予想通り、単純な平面で2つのクラスが分けられている。この決定境界の式は以下のようになる。

(2)    \begin{gather*} b + w_0 f_0 + w_1 f_1 + w_2 {f_1}^2 = 0\\ b \approx 1.1734,\; w_0 \approx 0.1301,\; w_1 \approx -0.2203,\; w_2 = -0.0597 \end{gather*}

この平面に対して上側(f12が小さい側)では多項式の値は正となり、その反対側では負となる。

以下のコードは、原典と以下が異なっている。

  • 収束しないという警告を受けて、LinearSVCmax_iterをデフォルトの1000より大きな値としている
  • Axes3Dの生成の仕方を最新のバージョンに合ったものとしている
    • 原典ではFigureオブジェクトを生成し、それをビューに関する引数とともにAxes3Dコンストラクターに渡している
    • 本コードでは、subplotsの引数でprojectionを指定してFigureAxes3Dを同時に生成し、veiw_init()でビューに関する引数を指定

元の特徴量に対する決定境界

上の例では特徴量は3つだが、最後の特徴量は2つ目の特徴量f1から計算される量であり、実質は2つの特徴量が決まれば決定境界が決まる。3次元空間内の平面の決定境界を以下のように書きなおすと、このことが確認できる。

(3)    \begin{align*} f_0 &= \frac{-b - w_1 f_1 - w_2 {f_1}^2}{w_0} \\ &= -9.02 +1.69 f_1 + 0.46 {f_1}^2 \\ &= 0.46(f_1 +1.83)^2 - 10.56 \end{align*}

これを2つの特徴量に対する決定境界として描画したのが以下の図で、境界が2次関数となっているのが確認できる。

SVMそのものは線形の決定境界しか得られないが、非線形化した特徴量を追加することによって、より複雑な決定境界とすることができる。

カーネルトリック

概要

上記の例では特徴量の1つを2次として新たな特徴量とした。特徴量の非線形化としては、このように特徴量の累乗とするほか、異なる特徴量同士の積を交互作用として導入することが考えられる。ただし、特徴量の数が多くなった時に、それらの全ての組み合わせに対する積を考えると、計算量が膨れ上がる。カーネルトリック(kernel trick)とは、拡張された特徴量空間でのデータ間の距離を、実際の拡張計算をせずに行う方法らしい。

受け売りをそのまま書いておくと、SVMで広く用いられているカーネルトリックのマッピング方法は以下の2つとのこと。

  • 多項式カーネル(polynomial kernel):もとの特徴量の特定の次数までの全ての多項式を計算
  • 放射既定関数(radial basis function: RBF)カーネルとも呼ばれるガウシアンカーネル:直感的には全次数の全ての多項式を考えるが、次数が高くなるにつれて特徴量の重要性を小さくする

以下はforgeデータセットに対して、カーネルトリックを用いたSVCを適用した例。直線はLinearSVCによる決定境界で、曲線はガウシアンカーネル(RBF)によるSVCの決定境界で、カーネル関数は以下のような形。

(4)    \begin{equation*} k_{\rm rbf}(x_1, x_2) = \exp \left( -\gamma || x_1 - x_2 ||^2 \right) \end{equation*}

scikit-learnのSVCの引数で、kernel='rbf'C=10gamma=0.1と指定している。

線形モデルの決定境界が直線なのに対して、カーネルトリックによる決定境界は、非線形化した特徴量を導入していることから曲線となっている。

scikit-learnのSVCクラスには、サポートベクターに関する以下のパラメーターがある。

  • support_:データセットにおけるサポートベクターのインデックス(1次元配列)
  • support_vector_:サポートベクターの配列(2次元配列)

38~44行目で、これらのパラメーターを使ってサポートベクターを強調表示している。

パラメータ調整

SVCモデルでパラメーターCとgammaの値を変化させたときの決定境界は以下の通り。

gammaはガウシアンカーネルの直径(σ2に相当)の逆数で、この値が小さいと直径が大きくなり、より多くの点を近いと判断するようになる。左の方はgammaが小さく広域のデータをまとめようとするため、決定境界は大まかとなり、右の方はgammaが大きく近いもの同士をまとめようとする傾向となる。

Cは正則化の強さの逆数で、上の方ほどCの値が小さく正則化が強く効くため、決定境界はよりまっすぐとなり、下の方ほど正則化が弱く個々のデータの影響を受ける。

 

今後の課題~覚え書き

カーネル関数

(5)    \begin{equation*} K(\boldsymbol{x}_1, \boldsymbol{x}_2) = \sum \phi(\boldsymbol{x}_1) \phi(\boldsymbol{x}_2) \end{equation*}

多項式カーネル

(6)    \begin{equation*} K(\boldsymbol{x}_1, \boldsymbol{x}_2) = (\boldsymbol{x}_1 \cdot \boldsymbol{x}_2 + 1 )^d \end{equation*}

ガウシアンカーネル

(7)    \begin{equation*} K(\boldsymbol{x}_1, \boldsymbol{x}_2) = \exp \left(- \frac{||(\boldsymbol{x}_1 - \boldsymbol{x}_2 ||^2}{2\sigma^2} \right) \end{equation*}

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です