静かなる名辞

pythonとプログラミングのこと


【python】sklearnのOneClassSVMを使って外れ値検知してみる

はじめに

 OneClassSVMというものがあると知ったので使ってみます。

 「1クラスSVM?」と思われると思いますが、要するに異常検知・外れ値検出などで使う手法です。信頼区間を出すのに似ていますが、複雑な分布だったりそもそも分布が想定できないようなデータでも計算してくれるので、シチュエーションによっては役に立ちそうです。

 なお、わかりやすい記事があったので先に紹介しておきます。

異常検知のための One Class SVM - Qiita

実験

 異常検知・外れ値検出系で使える手法なので、センサデータの処理とか、為替や株価のアルゴリズム取引用の処理なんかをやると適当だと思いますが、私はそんなカッコいいデータは持っていません。

 なので、例によって例のごとく、irisをPCAで二次元に落としたデータを使います。

 使い方は簡単で、nuに異常値の割合を指定すれば良いようです。なんかドキュメントには意味深なことが書いてありますが、この理解で良さそうです。

 ちなみにデフォルトはnu=0.5なので、データの半数が異常値扱いになります。最初は、一体何事かと思いました。あと、predictすると正常値=1,異常値=-1という予測になります。

 ドキュメント

 sklearn.svm.OneClassSVM — scikit-learn 0.21.3 documentation

 コードは以下のとおりです。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import OneClassSVM
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA

def main():
    iris = load_iris()
    pca = PCA(n_components=2)
    data = pca.fit_transform(iris.data)

    x = np.linspace(-5, 5, 500)
    y = np.linspace(-1.5, 1.5, 250)    
    X, Y = np.meshgrid(x, y)
    
    ocsvm = OneClassSVM(nu=0.1, gamma="auto")
    ocsvm.fit(data)
    df = ocsvm.decision_function(
        np.array([X.ravel(), Y.ravel()]).T).reshape(X.shape)
    preds = ocsvm.predict(data)

    plt.scatter(data[:,0], data[:,1], c=preds,
                cmap=plt.cm.RdBu, alpha=0.8)
    r = max([abs(df.min()), abs(df.max())])
    plt.contourf(X, Y, df, 10, vmin=-r, vmax=r,
                 cmap=plt.cm.RdBu, alpha=.5)
    plt.savefig("result.png")

if __name__ == "__main__":
    main()

 予測と決定関数を見るだけという手抜き。雰囲気はこれでわかると思うので、勘弁してください。

 なんかcontourfあたりでごちゃごちゃやっていますが、決定境界がcmapの中心と一致するように配慮しています。こうすることで、白色のあたり(というか青と赤の境界)が決定境界になります。

 余談ですが、このコードのためにlevelsをキーワード引数で指定しようとしたら、matplotlibのバグを踏みました。ひどい。

plt.contour levels parameter don't work as intended if receive a single int · Issue #11913 · matplotlib/matplotlib · GitHub


スポンサーリンク



結果

 プロットされる図を示します。

result.png
result.png

 このように、お手軽に良さげな結果が得られます。分布の形状が複雑でもうまく推定できる訳です。良いですね。

まとめ

 SVMなので使いやすくて、うまく動くようです。手軽に良好な異常検知ができる手法としては、かなり便利だと思います。