scikit-learnでは外れ値検知の手法の1つであるLOF(Local Outlier Factor)が提供されていますが、versionが0.19以前ではテストデータに対する正常データ・異常データの判定ができませんでした。version0.20からテストデータに対する正常データ・異常データの判定機能が実装されましたので、そちらを紹介します。
使い方
One Class SVMのようなscikit-learnに実装されている外れ値検知の手法では、正常データが大多数であるような訓練データを与え、fitメソッドで学習をおこないます。学習済みのモデルのpredictメソッドを使うことで、テストデータが正常か異常かが判定されます。LOFを使う場合にも同様の流れになりますが、fitメソッドを使うときにちょっとだけ違いがあり、novelty=Trueという引数が必要になります。例えば、次のように訓練と予測をおこないます。
from sklearn.neighbors import LocalOutlierFactor
model = LocalOutlierFactor(n_neighbors=1,
novelty=True,
contamination=0.1)
model.fit(train_data) # train_dataは正常データが大多数であるような訓練データ
prediction = model.predict(test_data) # テストデータに対する予測
score = model.score_samples(test_data) # テストデータの異常度
使ってみる
人工的にデータを生成し、それらに対してLOFを適用していきたいと思います。
以下のような訓練データとテストデータを生成しました。緑が正常の訓練データ、オレンジが正常のテストデータ、赤が異常のテストデータになります。(手書き風のグラフはmatplotlibの機能を使っていて、自分の趣味です)。
上記のデータを生成するコードは以下のとおりです。
from sklearn.datasets import make_blobs
X, _ = make_blobs(n_features=2, centers=1, cluster_std=[1], random_state=0, n_samples=100)
test_normal = X[:4]
train = X[4:]
test_anomaly = np.array([[0, 0], [-2.5, 2], [5, 4], [-2, 7]])
さて、実際にこれらのデータに対して訓練と予測を適用してみます。
model = LocalOutlierFactor(n_neighbors=2, novelty=True, contamination=0.1)
model.fit(train)
normal_result = model.predict(test_normal)
anomaly_result = model.predict(test_anomaly)
print("各正常データのスコア", normal_result)
print("各異常データのスコア", anomaly_result)
# 次のように出力される
# 各正常データのスコア [1 1 1 1]
# 各異常データのスコア [-1 -1 -1 -1]
正常データに対しては1が出力され、異常データに対しては-1が出力されますが、きちんと正しい結果を得られていることがわかります。