LoF(Local outlier Factor)について勉強したので紹介します。
LoFとは(概要)
LoF は外れ値を検知するための手法の一つです。密度ベースの手法で、以下の図のように近傍のデータの密度等を用いて比較することで、外れ値かどうかを判定します。
「密度等」と書きましたが、実際には各データのLoF値という値を計算して、その値によって外れ値とする手法です。
LoF値は以下のような式で求めます。
lrdは後で説明しますが、密度を表します。
式の分子を見てもらうとわかると思いますが、
データAのlrd(密度)でデータAのk近傍のデータ群のlrdを割っています。
この部分から、
- 近傍のデータ群の密度とデータAの密度が同じぐらいなら LoF は1に近く
- 近傍のデータ群の密度よりデータAが高密度なら LoF は1より小さく
- 近傍のデータ群の密度よりデータAが低密度なら LoF は1より大きく
なることがわかります。
LoF値の導出
この式がどこから出てきたかを順番に見ていこうと思います。
まず、到達可能性距離rd(reachability distance)という値を定義します。
\begin{aligned}
rd(A, B) = \max(d(A,B), kd(B))
\end{aligned}
\( d(A,B) \) はデータA,データBとの距離(例:ユークリッド距離等)、kd(B)(k-distance(B))はBのk近傍の中で一番遠いデータとの距離を表します。
次にデータAとその近傍のデータ群 \( N_k(A) \) との距離の平均を分母とした局所到達可能性密度lrd(local reachability density)を定義します。
\begin{aligned}
lrd_k(A)=1/\frac{\sum^{k}_{c \in N_k(A)}rd(A,C)}{| N_k(A)|}
\end{aligned}
各データとの距離の平均の逆数なので、名前にある通り密度を表します。
ここまで来たら、最後にLoF値の式を見てみます。
\begin{aligned}
LOF_{k}(A)=\frac{\sum_{c \in N_k(A)}\dfrac{lrd_{k}(c)}{lrd_{k}(A)}}{|N_k(A)|}
\end{aligned}
分子の式を見てわかるとおり、データAのlrdでデータAのk近傍のデータ群のlrdを割っています。
なので、先程も述べましたが、このLoF値は、
- 近傍のデータ群の密度とデータAの密度が同じぐらいなら LoF は1に近く
- 近傍のデータ群の密度よりデータAが高密度なら LoF は1より小さく
- 近傍のデータ群の密度よりデータAが低密度なら LoF は1より大きく
なります。
LoFを使ってみる(scikit-learn)
scikit-learnを使ってLoF試してみます。
まず、必要なモジュールをimportします。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from sklearn import datasets
from sklearn.neighbors import LocalOutlierFactor
次に、簡単なデータセットを用意します。
X, Y = datasets.make_blobs(n_samples=200, centers=2, n_features=2, cluster_std=0.4, random_state=0)
plt.scatter(X[:, 0], X[:, 1], c="blue")
ではLoFで外れ値を見つけてみます。
labels = LocalOutlierFactor(n_neighbors=5).fit_predict(X)
これだけです。ではプロットしてみます。
unique_labels = np.unique(labels)
for label in unique_labels:
x = X[np.where(labels==label)]
plt.scatter(x[:, 0], x[:, 1],label=label)
plt.legend()
青(-1)が外れ値です。うまく外れ値を見つけることができているように思います。
終わりに
今回は簡単にLoFについて書きました。
もしなにか間違いがあれば教えていただければと思います。
コメント