Pythonの異常検知ライブラリPyOD(その3)

前回のプログラム事例の発展型として、PyODライブラリ付属のデモ描画システムを利用することができる。まず以下の2つのライブラリのインポートを追加する。

from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

そして異常検知手法のループの部分を以下に置き換える。

# Loop for outlier detection tools
for i, (clf_name, clf) in enumerate(classifiers.items()):
    # train kNN detector
    clf.fit(X_train)
    # get the prediction labels and outlier scores of the training data
    Y_train_pred = clf.labels_  # binary labels (0: inliers, 1: outliers)
    Y_train_scores = clf.decision_scores_  # raw outlier scores
    # get the prediction on the test data
    Y_test_pred = clf.predict(X_test)  # outlier labels (0 or 1)
    Y_test_scores = clf.decision_function(X_test)  # outlier scores
    # evaluate and print the results
    print("\nOn Training Data:")
    evaluate_print(clf_name, Y_train, Y_train_scores)
    print("\nOn Test Data:")
    evaluate_print(clf_name, Y_test, Y_test_scores)
    # visualize the results
    visualize(clf_name, X_train, Y_train, X_test, Y_test, Y_train_pred,
              Y_test_pred, show_figure=True, save_figure=True)

そうすると以下のようなデモバージョンのグラフが描かれる。

Pythonの異常検知ライブラリPyOD(その2)

前回の補足。以下はテストデータのグラフである。

次は主成分分析、ヒストグラムベース異常検知、k-近傍法の図である。

以下、各手法について簡単に解説する。
主成分分析:変数間の連関性をもとに多変数を少数の主成分に縮約する。
k-近傍法:任意のデータ点について、そのk番目に近い近傍との距離を異常度として用いる。
Isolation Forest: この手法では、木の集合を用いてデータの区分けが行われる。Isolation Forestは、その点が構造の中でいかに孤立しているかを示す異常度スコアを与える。それゆえ異常度スコアは正常なデータ点から外れた点を識別するために用いられる。Isolation Forestは多次元データで高い性能を発揮する。
ヒストグラムに基づく異常検知法:効率的な教師なし学習手法である。特徴間の独立を仮定し、ヒストグラムを構築することにより異常スコアを計算する。多変量アプローチよりも高速であるが、精度は落ちる。
クラスタリングに基づく局所外れ値因子法:データを大きなクラスターと小さなクラスターに分類する。異常度スコアはその点が属するクラスターのサイズと、最も近い大型クラスターとの距離で計算される。

Pythonの異常検知ライブラリPyOD(その1)

昨年より仕事のデータ解析のためにPythonプログラムを書いている。昨年はデータ前処理と作図が殆どだったが、今年から統計手法のライブラリを使い始めた。最近、異常検知のためのPythonライブラリを探していたら、PyODというライブラリを見つけた。PyODは、多変量の観測データの異常検知が行えるライブラリで、提供されている手法は、統計モデルや機械学習など20に及ぶ。多様な異常検知手法を統一したインタフェースで適用して結果を相互比較できるという優れものである。リリースされてから日が浅く、日本語の解説記事はまだ殆どないようである。

今回は、英語のチュートリアル記事を参考に、PyODのデータ生成機能で作った人工データを用いて、教師なし学習の8つの手法を適用してみた。尚、PyODライブラリ利用のためにはインストールが必要です。Anacondaの場合は、ターミナルから「conda install -c conda-forge pyod」と入力して下さい。

【ライブラリのインポート】PyODライブラリは、各手法毎にインポートする。

import numpy as np
import pandas as pd
import matplotlib. pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'MS Gothic'
from pyod.utils.data import generate_data, get_outliers_inliers
# import PyOD library models
from pyod.models.abod import ABOD
from pyod.models.cblof import CBLOF
from pyod.models.hbos import HBOS
from pyod.models.iforest import IForest
from pyod.models.knn import KNN
from pyod.models.lof import LOF
from pyod.models.pca import PCA

【人工データの生成】変数の数、異常データの出現割合(ここではデフォルト0.1)を指定して、分析用の人工データ(観測データ、正常/異常データ)を生成することができる。

# generate random data with two features
X_train,X_test,Y_train,Y_test=generate_data(n_train=200,n_test=100,n_features=2,behaviour='new')

# plot training data
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(X_train[:,0], label='Col 1')
ax1.plot(X_train[:,1], label='Col 2')
ax1.set_title('PyOD Training Data')
ax1.legend()
plt.show()

【手法の記述】分析に用いる手法を辞書型変数として記述する。

# Define eight outlier detection tools to be compared
random_state = np.random.RandomState(42)
outliers_fraction = 0.05
classifiers = {
    'Angle-based Outlier Detector (ABOD)': ABOD(contamination=outliers_fraction),
    'Principal Component Analysis (PCA)': PCA(contamination=outliers_fraction),
    'Cluster-based Local Outlier Factor(CBLOF)': CBLOF(contamination=outliers_fraction,check_estimator=False,random_state=random_state),
    'Histogram-base Outlier Detection (HBOS)': HBOS(contamination=outliers_fraction),
    'Isolation Forest': IForest(contamination=outliers_fraction,random_state=random_state),
    'K Nearest Neighbors (KNN)': KNN(contamination=outliers_fraction),
}

【各手法のデータへの当てはめと異常判定】ここでは辞書リストの要素についてのループを組んでいる。

# Loop for outlier detection tools
for i, (clf_name, clf) in enumerate(classifiers.items()):
    # fit the dataset to the model
    clf.fit(X_train)
    # predict raw anomaly score
    scores_pred = clf.decision_function(X_test)
    # prediction of a datapoint category outlier or inlier
    y_pred = clf.predict(X_test)
    # prediciton error rate
    y_ErrRate = (y_pred != Y_test).sum() / len(Y_test)
    # plot scores_pred
    x = np.arange(100)
    y1 = scores_pred
    fig = plt.figure()
    ax1 = fig.add_subplot(111)
    ax1.plot(x,y1, 'k-', label='Anomaly Score')
    ax1.plot(x[y_pred==1], y1[y_pred==1],'ro', label='Outlier')
    ax1.set_title('PyOD Result: ' +clf_name + ' Error Rate: '+str(round(y_ErrRate,3)))
    ax1.legend()
    plt.show()