えんじにあのじゆうちょう

勉強したことを中心にアウトプットしていきます。

【異常検知】最近傍法を使った方法

はじめに

異常検知シリーズ第2段、ということで最近傍法を使った異常検知にチャレンジします。
例のごとく、Albert社のブログを大きく参考にさせていただいています。
www.albert2005.co.jp

解説

概要

ある意味では前よりも単純で、ある時点のデータとそれまでのデータ点の中で、最も近い点との距離をみて、その距離が一定の閾値を超えたら異常と判断する方法です。
簡単そうですね。
早速実装していきましょう。

実装

まずデータを用意しますが、これは前回と変わらないのでコードはそちらを参考にしてください。
https://t.marufeuille.dev/entory/hotelings-theoryt.marufeuille.dev

ここでは生成後のデータをグラフ化したもののみ掲載します。

f:id:marufeuillex:20191214205628p:plain

では、これについて異常検知を行ってみます。

# thresholdは3としてみる。
thresh = 3

# 異常検知
anomaly_idxs = []
for idx in range(len(series)):
    s= series[idx]
    p = [np.array([i, s[i]]) for i in range(s.shape[0])]
    a= []
    for i in range(s.shape[0]):
        min_val = np.inf

        for j in range(s.shape[0]):
            if i == j:
                continue
            diff = np.linalg.norm(p[i] - p[j])
            if diff < min_val:
                min_val = diff

        if min_val > thresh:
            a.append(i)
    anomaly_idxs.append(a)

# 可視化
fig, ax = plt.subplots(3, 2, figsize=(15, 10))
for i in range(len(series)):
    anomaly_idx = np.array(anomaly_idxs[i])
    s = series[i]
    anomaly_data = np.array(s)[anomaly_idxs[i]]
    ax[i //2, i % 2].plot(np.arange(N), series[i])
    ax[i //2, i % 2].scatter(anomaly_idx, anomaly_data, color="red", marker="x")

f:id:marufeuillex:20191214213444p:plain

前回の最近傍法のものと見比べていただきたいですが、前回検知できなかった2, 3についても最も近い点との距離と置くことで正しく検知できています。
ただ、結局4のようなケースでたまに続いて出てくるようなパターンがあるときは、どうしても異常という扱いになってしまい、正常とすることは閾値のとり方次第では難しいです。

まとめ

今回は最近傍法を用いた異常検知についてまとめました。
最近傍法は分類アルゴリズムとして使われるものだとばかり思っていましたが、そうでない利用の仕方もあるということで奥深いですね。

次回はlof法についてまとめてみようと思います。