异常检测-基于相似度的方法-datawhale-task4

基于相似度的方法可分为基于距离密度的度量方法

基于距离的度量

基于单元的⽅法

在基于单元格的技术中,数据空间被划分为单元格,单元格的宽度是阈值D和数据维数的函数。具体地说,每个维度被划分成宽度最多为 D 2 d \frac{D}{2\sqrt{d}} 2d D单元格。在给定的单元以及相邻的单元中存在的数据点满⾜某些特性,这些特性可以让数据被更有效的处理。

注:d代表维度,例如如果二维的话就是 D 2 2 \frac{D}{2\sqrt{2}} 22 D
引用助教同学的讲解:
在这里插入图片描述
以上图为例,在二维空间中,假设极端情况下,两个数据点正好在格子的两个对角点上

要让这两个点的距离不大于 D 2 \frac{D}{2} 2D,则格子的边长不能大于 D 2 2 \frac{D}{2\sqrt{2}} 22 D

对于给定单元格, L 1 L_1 L1邻居被定义为通过最多1个单元间的边界可从该单元到达的单元格的集合。在⼀个⻆上接触的两个单元格也是 L 1 L_1 L1邻居。
L 2 L_2 L2邻居是通过跨越2个(或3个)边界而获得的那些单元格。
如下图所示:
在这里插入图片描述
如此设置都是为了引出以下性质:
在这里插入图片描述
定义如下规则,迅速确定异常值:
在这里插入图片描述
余下的点再用 k k k最近邻距离进行计算排查。

基于索引的⽅法

计算复杂度太高,不表。

基于密度的度量(以LOF为主)

基于密度的算法主要有局部离群因⼦(LocalOutlierFactor,LOF),以及LOCI、CLOF等基于LOF的改进算法。下⾯以LOF为例来进⾏详细的介绍和实践。

基于距离的检测适⽤于各个集群的密度较为均匀的情况。

在这里插入图片描述
在上图中,离群点B容易被检出,而若要检测出较为接近集群的离群点A,则可能会将⼀些集群边缘的点当作离群点丢弃。而LOF等基于密度的算法则可以较好地适应密度不同的集群情况。

下文讲的相当详细易懂,建议参考。
异常点/离群点检测算法——LOF

概念引入

  1. d ( p , o ) d(p,o) d(p,o):两点p和o之间的距离

  2. k − d i s t a n c e k-{distance} kdistance:第k距离
    对于点p的第k距离 d k ( p ) d_k(p) dk(p)定义如下: d k ( p ) d_k(p) dk(p)= d ( p , o ) d(p,o) d(p,o),并且满足:
       a) 在集合中至少有不包括p在内的k个点 o ′ ∈ C { x ≠ p } o'∈C\{x≠p\} oC{x=p}, 满足 d ( p , o ′ ) d(p,o') d(p,o) d ( p , o ) d(p,o) d(p,o)
       b) 在集合中最多有不包括p在内的k−1个点 o ′ ∈ C { x ≠ p } o'∈C\{x≠p\} oC{x=p},满足 d ( p , o ′ ) d(p,o') d(p,o)< d ( p , o ) d(p,o) d(p,o)
       白话:p的第k距离,也就是距离p第k远的点的距离,不包括p,如图。
    在这里插入图片描述

  3. k − d i s t a n c e k-{distance} kdistance neighborhood of p:第k距离邻域
      点p的第k距离邻域 N k ( p ) N_k(p) Nk(p),就是p的第k距离即以内的所有点,包括第k距离。
      因此p的第k邻域点的个数 ∣ N k ( p ) ∣ > k |N_k(p)|>k Nk(p)>k

  4. r e a c h − d i s t a n c e reach-{distance} reachdistance:可达距离
     点o到点p的第k可达距离定义为:
      r e a c h − d i s t a n c e k ( p , o ) = m a x { k − d i s t a n c e ( o ) , d ( p , o ) } reach-{distance_k}(p,o)=max\{k-{distance}(o),d(p,o)\} reachdistancek(p,o)=max{kdistance(o),d(p,o)}
     白话:点o到点p的第k可达距离,至少是o的第k距离,或者为o、p间的真实距离。
        这也意味着,离点o最近的k个点,o到它们的可达距离被认为相等,且都等于 d k ( o ) d_k(o) dk(o)
        如图4,o1到p的第5可达距离为d(p,o1),o2到p的第5可达距离为 d 5 ( o 2 ) d_5(o2) d5(o2)
        在这里插入图片描述

  5. local reachability density:局部可达密度
       我们可以将“密度”直观地理解为点的聚集程度,就是说,点与点之间距离越短,则密度越⼤。
    点p的局部可达密度表示为:
         l r d k ( p ) = 1 / ( ∑ o ∈ N k ( p )  reach  − dist ⁡ k ( p , o ) ∣ N k ( p ) ∣ ) l r d_{k}(p)=1 /\left(\frac{\sum_{o \in N_{k}(p)} \text { reach }-\operatorname{dist}_{k}(p, o)}{\left|N_{k}(p)\right|}\right) lrdk(p)=1/(Nk(p)oNk(p) reach distk(p,o))
    表示点p的第k邻域内点到p的平均可达距离的倒数。
       注意,是p的邻域点 N k ( p ) N_k(p) Nk(p)到p的可达距离,不是p到 N k ( p ) N_k(p) Nk(p)的可达距离,一定要弄清楚关系。并且,如果有重复点,那么分母的可达距离之和有可能为0,则会导致lrd变为无限大,下面还会继续提到这一点。
        这个值的含义可以这样理解,首先这代表一个密度,密度越高,我们认为越可能属于同一簇,密度越低,越可能是离群点。如果p和周围邻域点是同一簇,那么可达距离越可能为较小的 dk(o),导致可达距离之和较小,密度值较高;如果p和周围邻居点较远,那么可达距离可能都会取较大值 d(p,o),导致密度较小,越可能是离群点。

  6. local outlier factor:局部离群因子
       点p的局部离群因子表示为:
        L O F k ( p ) = ∑ o ∈ N k ( p ) l r d k ( o ) l r d k ( p ) ∣ N k ( p ) ∣ = ∑ o ∈ N k ( p ) l r d k ( o ) ∣ N k ( p ) ∣ / lr ⁡ d k ( p ) L O F_{k}(p)=\frac{\sum_{o \in N_{k}(p)} \frac{l r d_{k}(o)}{l r d_{k}(p)}}{\left|N_{k}(p)\right|}=\frac{\sum_{o \in N_{k}(p)} l r d_{k}(o)}{\left|N_{k}(p)\right|} / \operatorname{lr} d_{k}(p) LOFk(p)=Nk(p)oNk(p)lrdk(p)lrdk(o)=Nk(p)oNk(p)lrdk(o)/lrdk(p)
       
       表示点p的邻域点 N k ( p ) N_k(p) Nk(p)的局部可达密度与点p的局部可达密度之比的平均数。
       如果这个比值越接近1,说明p的其邻域点密度差不多,p可能和邻域同属一簇;如果这个比值越小于1,说明p的密度高于其邻域点密度,p为密集点;如果这个比值越大于1,说明p的密度小于其邻域点密度,p越可能是异常点。
      现在概念定义已经介绍完了,现在再回过头来看一下lof的思想,主要是通过比较每个点p和其邻域点的密度来判断该点是否为异常点,如果点p的密度越低,越可能被认定是异常点。至于密度,是通过点之间的距离来计算的,点之间距离越远,密度越低,距离越近,密度越高,完全符合我们的理解。而且,因为lof对密度的是通过点的第k邻域来计算,而不是全局计算,因此得名为“局部”异常因子,这样,对于图1的两种数据集C1和C2,lof完全可以正确处理,而不会因为数据密度分散情况不同而错误的将正常点判定为异常点。

练习

#coding:utf-8
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.neighbors import LocalOutlierFactor

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.rcParams["font.sans-serif"]=["KaiTi"]
plt.rcParams["axes.unicode_minus"] = False

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

np.random.seed(61)
# 构造两个数据点集群
X_inliers1 = 0.2 * np.random.randn(100, 2)
X_inliers2 = 0.5 * np.random.randn(100, 2)
X_inliers = np.r_[X_inliers1 + 2, X_inliers2 - 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)
# 打标签,群内点构造离群值为1,离群点构造离群值为-1
ground_truth[-n_outliers:] = -1

plt.title('构造数据集 (LOF)')
plt.scatter(X[:-n_outliers, 0], X[:-n_outliers, 1], color='b', s=5, label='集群点')
plt.scatter(X[-n_outliers:, 0], X[-n_outliers:, 1], color='orange', s=5,
label='离群点')
plt.axis('tight')
plt.xlim((-5, 5))
plt.ylim((-5, 5))
legend = plt.legend(loc='upper left')
legend.legendHandles[0]._sizes = [10]
legend.legendHandles[1]._sizes = [20]
#plt.show()
plt.savefig('构造数据集 (LOF).png',format='png',bbox_inches='tight')

# 训练模型(找出每个数据的实际离群值)
clf = LocalOutlierFactor(n_neighbors=20, contamination=0.1)
# 对单个数据集进监督检测时,以1和-1分别表⽰⾮离群点与离群点
y_pred = clf.fit_predict(X)
# 找出构造离群值与实际离群值不同的点
n_errors = y_pred != ground_truth
X_pred = np.c_[X,n_errors]
X_scores = clf.negative_outlier_factor_
# 实际离群值有正有负,转化为正数并保留其差异性(不是直接取绝对值)
X_scores_nor = (X_scores.max() - X_scores) / (X_scores.max() - X_scores.min())
X_pred = np.c_[X_pred,X_scores_nor]
X_pred = pd.DataFrame(X_pred,columns=['x','y','pred','scores'])
X_pred_same = X_pred[X_pred['pred'] == False]
X_pred_different = X_pred[X_pred['pred'] == True]
# 直观地看看数据
X_pred
plt.title('局部离群因子检测 (LOF)')
plt.scatter(X[:-n_outliers, 0], X[:-n_outliers, 1], color='b', s=5, label='集群点')
plt.scatter(X[-n_outliers:, 0], X[-n_outliers:, 1], color='orange', s=5,
    label='离群点')
# 以标准化之后的局部离群值为半径画圆,以圆的⼤小直观表⽰出每个数据点的离群程度
plt.scatter(X_pred_same.values[:,0], X_pred_same.values[:, 1],
        s=1000 * X_pred_same.values[:, 3], edgecolors='c',
        facecolors='none', label='标签⼀致')
plt.scatter(X_pred_different.values[:, 0], X_pred_different.values[:, 1],
        s=1000 * X_pred_different.values[:, 3], edgecolors='violet',
        facecolors='none', label='标签不同')
plt.axis('tight')
plt.xlim((-5, 5))
plt.ylim((-5, 5))
legend = plt.legend(loc='upper left')
legend.legendHandles[0]._sizes = [10]
legend.legendHandles[1]._sizes = [20]
#plt.show()
plt.savefig('局部离群因子检测 (LOF).png',format='png',bbox_inches='tight')

结果:

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值