在介绍 LOF 算法前先引用几个重要的概念 。
第k 距离
定义:设dk(O) 为数O 的第k 距离
dk(O)=d(O,P)
即:点P 是距离点O 最近的第k 个点。
k 距离邻域
定义:设Nk(O) 为点O 的第k 距离邻域,满足条件
Nk(O)={P′∈D\{O}∣d(O,P′)≤dk(O)}
即:D\{O} 中所有到点O 距离不大于dk(O) 的点集合。
可达距离
定义:以点O 为中心,点P 到点O 的第k 可达距离定义为
dk(P,O)=max{dk(O),d(P,O)}
即:点P 到点O 的第k 可达距离至少为dk(O),距离O 最近的k 个点到O 的可达距离被认为是相等的为等于dk(O)。
局部密度可达
定义:局部密度可达为
ρk(P)=∑O∈Nk(P)dk(P,O)/∣Nk(P)∣1=∑O∈Nk(P)dk(P,O)∣Nk(P)∣
即:点P 的第k 邻域内所有点到P 的平均可达距离。如果P 和周围邻域点是同一簇,那么可达距离越可能为较小的dk(O) ,导致可达距离之和越小,局部可达密度越大。如果O 和周围邻域点较远,那么可达距离可能会取较大值d(P,O),导致可达距离之和越大,局部可达密度越小。
📢 注意:关于局部可达密度的定义其实暗含假设,即:不存在大于等于k 个重复的点,这些重复点的平均可达距离为零,局部可达密度就变为无穷大。解决方法是可以将可达距离加上非常小的值。
根据以上定义,LOF 计算公式如下
LOFk(P)=∣Nk(P)∣∑O∈Nk(P)ρk(P)ρk(O)
即:点P 的邻域Nk(P) 内其他点的局部可达密度与点P 的局部可达密度之比的平均数。如果这个比值越接近 1,说明O 的邻域点密度差不多,O 可能和邻域同属一簇;如果这个比值小于1,说明O 的密度高于其邻域点密度为密集点;如果这个比值大于 1,说明O 的密度小于其邻域点密度可能是异常点。
LOF 算法需要计算数据点对间的距离,整个算法时间复杂度为O(n2) 。为了提高算法效率,FastLOF 算法对其进行改进。主要思路先将数据集划分为多个子集,再分别计算 LOF 分数,剔除异常分数小于 1 的再进行计算,详情可以参考原文。
Python 实践
为了方便此处直接采用 Scikit-learn 中提供的包测试算法效果。
采用人工生成的离群点数据测试,代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| X_inliers = 0.3 * np.random.randn(100, 2) X_inliers = np.r_[X_inliers + 2, X_inliers - 2]
X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2)) X = np.r_[X_inliers, X_outliers]
n_outliers = len(X_outliers) ground_truth = np.ones(len(X), dtype=int) ground_truth[-n_outliers:] = -1
clf = LocalOutlierFactor(n_neighbors=20, contamination=0.1)
y_pred = clf.fit_predict(X) n_errors = (y_pred != ground_truth).sum() X_scores = clf.negative_outlier_factor_
plt.title("Local Outlier Factor (LOF)") plt.scatter(X[:, 0], X[:, 1], color="k", s=3.0, label="Data points")
radius = (X_scores.max() - X_scores) / (X_scores.max() - X_scores.min()) plt.scatter( X[:, 0], X[:, 1], s=1000 * radius, edgecolors="r", facecolors="none", label="Outlier scores" ) plt.axis("tight") plt.xlim((-5, 5)) plt.ylim((-5, 5)) plt.xlabel("prediction errors: %d" % (n_errors)) legend = plt.legend(loc="upper left") legend.legendHandles[0]._sizes = [10] legend.legendHandles[1]._sizes = [20] plt.show()
|
对应的实验结果如下:
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 梦家博客! 打赏
wechat
alipay