异常检测——高维数据异常检测
主要内容包括:
- Feature Bagging
- 孤立森林
1、引言
在实际场景中,很多数据集都是多维度的。随着维度的增加,数据空间的大小(体积)会以指数级别增长,使数据变得稀疏,这便是维度诅咒的难题。维度诅咒不止给异常检测带来了挑战,对距离的计算,聚类都带来了难题。例如基于邻近度的方法是在所有维度使用距离函数来定义局部性,但是,在高维空间中,所有点对的距离几乎都是相等的(距离集中),这使得一些基于距离的方法失效。在高维场景下,一个常用的方法是子空间方法。
集成是子空间思想中常用的方法之一,可以有效提高数据挖掘算法精度。集成方法将多个算法或多个基检测器的输出结合起来。其基本思想是一些算法在某些子集上表现很好,一些算法在其他子集上表现很好,然后集成起来使得输出更加鲁棒。集成方法与基于子空间方法有着天然的相似性,子空间与不同的点集相关,而集成方法使用基检测器来探索不同维度的子集,将这些基学习器集合起来。
下面来介绍两种常见的集成方法:Feature Bagging 和Isolation Forest。
2、Feature Bagging
2.1 Feature Bagging的通用算法
Feature Bagging,基本思想与bagging相似,只是对象是feature。feature bagging属于集成方法的一种,下图是feature bagging的通用算法:
-
给定: S { ( x 1 , y 1 ) , . . . , ( x m , y m ) } S\{(x_1,y_1),...,(x_m,y_m)\} S{(x1,y1),...,(xm,ym)} 特征 x i ∈ X d x_i∈X^d xi∈Xd,标签 y i ∈ Y = { C , N C } y_i∈Y=\{C,NC\} yi∈Y={C,NC}, C C C为异常值, N C NC NC为非异常值。
-
标准化数据集 S S S
-
对于 t = 1 , 2 , 3 , 4 , . . . T t=1,2,3,4,...T t=1,2,3,4,...T
- 从 ⌊ d / 2 ⌋ \lfloor d/2 \rfloor ⌊d/2⌋和 ( d − 1 ) (d-1) (d−1)之间的均匀分布中随机选择特征子集的特征数 N t N_t Nt(至少取一半的特征)
- 无放回的随机选择 N t N_t Nt个特征创建特征子集 F t F_t Ft
- 采用特征子集 F t F_t Ft应用异常检测算法 O t O_t Ot
- 异常检测算法 O t O_t Ot的输出是异常得分向量 A S t AS_t ASt
-
整合异常得分向量 A S t AS_t ASt,并输出最终异常得分向量 A S F I N A L AS_{FINAL} ASFINAL:
A S F I N A L = C O M B I N E ( A S t ) , t = 1 , 2 , . . . , T AS_{FINAL}=COMBINE(AS_t),t=1,2,...,T ASFINAL=COMBINE(ASt),t=1,2,...,T
2.2 Feature Bagging 的设计关键点
1. 选择基检测器
这些基本检测器可以彼此完全不同,或不同的参数设置,或使用不同采样的子数据集。Feature bagging常用LOF算法为基算法。(KNN、ABOD等同样ok)
2. 分数标准化
不同检测器可能会在不同的尺度上产生分数。例如,平均k近邻检测器会输出原始距离分数,而LOF算法会输出归一化值。另外,尽管一般情况是输出较大的异常值分数,但有些检测器会输出较小的异常值分数。因此,需要将来自各种检测器的分数转换成可以有意义的组合的归一化值。
3. 分数组合方法
分数标准化之后,还要选择一个组合函数将不同基本检测器的得分进行组合,最常见的选择包括平均和最大化组合函数。下面是两个feature bagging两个不同的组合分数方法:
广度优先:
本质上:取每条记录的最高的异常值分数
方式:对每条记录每个基检测器预测的异常值分数从高到低一起排序,遍历 I n d t ( i ) Ind_t(i) Indt(i),将每条记录最高的异常值分数存入最终结果表。
- 给定 ( A S t ) , t = 1 , 2 , . . . , T (AS_t),t=1,2,...,T (ASt),t=1,2,...,T, 和 m m m:数据集 S S S和每个向量 A S t AS_t ASt的大小size
- 将所有异常值分数向量 A S t AS_t ASt排序,得到向量 S A S t SAS_t SASt,并返回已排序向量的索引 I n d t Ind_t Indt。比如, S A S t ( 1 ) SAS_t(1) SASt(1)有最高的异常值分数, I n d t ( 1 ) Ind_t(1) Indt(1)为这条有着最高异常值分数的数据记录 S A S t ( 1 ) SAS_t(1) SASt(1)在数据集 S S S中的索引。
- 初始化 A S F I N A L AS_{FINAL} ASFINAL和 I n d F I N A L Ind_{FINAL} IndFINAL为空向量。
- For
i
=
1
i=1
i=1 to
m
m
m (最外层遍历所有数据记录)
- For
t
=
1
t=1
t=1 to
T
T
T (里面一层遍历所有基检测器检测结果)
- 如果索引为
I
n
d
t
(
i
)
Ind_t(i)
Indt(i)的数据记录被第
t
t
t个异常检测算法排在第
i
i
i位,并且异常得分
A
S
t
(
i
)
AS_t(i)
ASt(i)不在向量
I
n
d
F
I
N
A
L
Ind_{FINAL}
IndFINAL中
- 将 I n d t ( i ) Ind_t(i) Indt(i)插入向量 I n d F I N A L Ind_{FINAL} IndFINAL的尾部
- 将 A S t ( i ) AS_t(i) ASt(i)插入向量 A S F I N A L AS_{FINAL} ASFINAL的尾部
- 如果索引为
I
n
d
t
(
i
)
Ind_t(i)
Indt(i)的数据记录被第
t
t
t个异常检测算法排在第
i
i
i位,并且异常得分
A
S
t
(
i
)
AS_t(i)
ASt(i)不在向量
I
n
d
F
I
N
A
L
Ind_{FINAL}
IndFINAL中
- For
t
=
1
t=1
t=1 to
T
T
T (里面一层遍历所有基检测器检测结果)
- 返回
A
S
F
I
N
A
L
AS_{FINAL}
ASFINAL和
I
n
d
F
I
N
A
L
Ind_{FINAL}
IndFINAL
排序取最大值的过程不大好理解,举个栗子:
累计求和:
本质上:取每条记录的平均异常值分数
方式:对每条记录每个基检测器得出的异常值分数求和
-
给定 ( A S t ) , t = 1 , 2 , . . . , T (AS_t),t=1,2,...,T (ASt),t=1,2,...,T, 和 m m m:数据集 S S S和每个向量 A S t AS_t ASt的大小size
-
对异常值分数 A S t AS_t ASt求和:
-
For i = 1 i=1 i=1 to m m m (最外层遍历所有数据记录)
A S F I N A L ( i ) = ∑ t = 1 T A S t ( i ) AS_{FINAL}(i)=\sum_{t=1}^TAS_t(i) ASFINAL(i)=∑t=1TASt(i)
-
返回 A S F I N A L AS_{FINAL} ASFINAL
基探测器的设计及其组合方法都取决于特定集成方法的特定目标。很多时候,我们无法得知数据的原始分布,只能通过部分数据去学习。除此以外,算法本身也可能存在一定问题使得其无法学习到数据完整的信息。这些问题造成的误差通常分为偏差和方差两种。
方差:是指算法输出结果与算法输出期望之间的误差,描述模型的离散程度,数据波动性。
偏差:是指预测值与真实值之间的差距。即使在离群点检测问题中没有可用的基本真值
2.3 Bagging的必要条件
-
基检测器之间尽量独立。
-
基检测器的准确率要大于50%。
用数学来验证下,集成方法比单个基检测器效果更好。基检测器准确率为 x x x,集成模型包含了25个基检测器。
import numpy as np
from scipy.special import comb
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
x = np.linspace(0,1,20)
y = []
for epsilon in np.linspace(0,1,20):
E = np.array([comb(25,i)*(epsilon**i)*((1-epsilon)**(25-i))
for i in range(13,26)]).sum()
y.append(E)
plt.plot(x,y,"o-",label="基检测器不同")
plt.plot(x,x,"--",color="red",label="基检测器相同")
plt.xlabel("单个基检测器准确率")
plt.ylabel("25个基检测器集成后的准确率")
plt.legend()
plt.show()
由图可见:
(1)当基检测器的准确率大于0.5时,集成的效果是比基检测器要好的。相反,当基检测器的准确率小于0.5,袋装的集成算法就失效了。
(2)当基检测器之间无太大差别时,集成的效果与基检测器无差别。
3、Isolation Forests
孤立森林(Isolation Forest)算法是周志华教授等人于2008年提出的异常检测算法,受随机森林的思想启发。是机器学习中少见的专门针对异常检测设计的算法之一,方法因为该算法时间效率高,能有效处理高维数据和海量数据,无须标注样本,在工业界应用广泛。
iForest 适用于连续数据(Continuous numerical data)的异常检测,将异常定义为“容易被孤立的离群点 (more likely to be separated)”——可以理解为分布稀疏且离密度高的群体较远的点。
用统计学来解释,在数据空间里面,分布稀疏的区域表示数据发生在此区域的概率很低,因而可以认为落在这些区域里的数据是异常的。
解决的问题
Swamping:异常数据点和正常数据点离得很近
Masking:异常数据点聚集,伪装成正常数据点。
3.1 Isolation Forest算法原理
1. Isolation
先思考一个小问题,如果把上面这张图,随机选择一条方向的直线进行切分,直到图中的每个点都在一个单独的区域?
这个算法呢,理解起来不是太难,这个孤立森林,其实都是一堆二叉树~
先从iTree讲起。
2. Isolation Trees
首先,iTree是一棵真二叉树(proper binary tree),及每个节点都有0个或2个子节点。
构建一棵iTree的过程:
- 从训练数据 X X X中随机选择 n n n个样本作为子样本,放入树的根节点,样本属性集为 A A A。
- iTree会在 A A A中随机挑一个属性 a a a。
- 这组数据在属性 a a a上的最大值为 m a x max max,最小值为 m i n min min,iTree会再次随机在 m i n min min到 m a x max max中间随机选一个值 v v v。(随机了两次,好随便的iTree)
- 接下来,对这组数据属性 a a a的值与 v v v做比较, a a a< v v v 则进入左子树, a a a> v v v则进入右子树,
- 然后呢,对左子树和右子树重复进行1-4,直到停止条件的发生。
so 停止条件是?
当当当当~ 来啦~
停止条件1:子树中仅有一个元素,或子树不再可分(数据均相同)。
停止条件2:达到了树高度的阈值
c
e
i
l
(
l
o
g
2
n
ceil(log_2^n
ceil(log2n)。
3. 异常得分的计算
每条待测数据的异常分数(Anomaly Score),其计算公式为:
s ( x , n ) = 2 − ( E ( h ( x ) ) c ( n ) ) s(x,n) = 2^-(\frac{E(h(x))}{c(n)}) s(x,n)=2−(c(n)E(h(x)))
c
(
n
)
=
2
H
(
n
−
1
)
−
2
(
n
−
1
)
n
c(n) = 2H(n-1)-\frac{2(n-1)}{n}
c(n)=2H(n−1)−n2(n−1)
其中,
H
(
k
)
=
l
n
(
k
)
+
ξ
H(k) = ln(k)+\xi
H(k)=ln(k)+ξ,
ξ
\xi
ξ为欧拉常数
h
(
x
)
h(x)
h(x):数据x在iTree树上沿对应的条件分支往下走,直到达到叶子节点,并记录这过程中经过的路径长度。
E
(
h
(
x
)
)
E(h(x))
E(h(x)):数据x在一组iTree树的平均路径长度。
c
(
n
)
c(n)
c(n):二叉搜索树的平均路径长度,用来对结果进行归一化处理(iTree与二叉查找树有着相同的结构,故借用二叉查找树对搜索不成功路径的平均长度的分析)
ξ
\xi
ξ:是欧拉常数,其值为0.577215664
• when
E
(
h
(
x
)
)
E(h(x))
E(h(x)) →
c
(
n
)
c(n)
c(n),
s
s
s → 0.5;
• when
E
(
h
(
x
)
)
E(h(x))
E(h(x))→0,
s
s
s→1;
• and when
E
(
h
(
x
)
)
E(h(x))
E(h(x))→
n
−
1
n−1
n−1,
s
s
s→0.
异常分数,具有以下性质:
-
如果分数越接近1,其是异常点的可能性越高;
-
如果分数都比0.5要小,那么基本可以确定为正常数据;
-
如果所有分数都在0.5附近,那么数据不包含明显的异常样本。
E ( h ( x ) ) E(h(x)) E(h(x))与 s s s的关系,单调递减
4. 模型训练与评估
经过对原始训练数据多次不放回抽样,构建了一堆iTree后,就组成了iForest。
3.2 iTree如何解决swamping和masking的问题
通过sub-sampling 无放回的随机采样,解决正常样本与异常点分界不清,交织在一起的问题。
(a) Original sample (4096 instances)
(b) Sub-sample (128 instances)
3.3 iForest总结
特点
- Non-parametric(两个参数,还是已经给了优秀的默认值的)
- unsupervised
- iForest仅对Global Anomaly敏感,即全局稀疏点敏感,不擅长处理局部的相对稀疏点(Local Anomaly)。
优点
- 计算成本相比基于距离或基于密度的算法更小
- 线性的时间复杂度
- 对内存需求极低
- 处理大数据集上有优势
适用的数据:
- 连续数据
- 异常数据远少于正常数据
- 异常数据与正常数据的差异较大
- 非超高维数据(高维需要降维)
4、练习
1. 调用feature bagging和Isolation Forest
PyOD库中的FeatureBagging算法的默认基检测器为LOF,但也可以通过estimator_params自行指定。(但是还不清楚怎么写)
estimator_params : dict, optional (default=None)
The list of attributes to use as parameters
when instantiating a new base estimator. If none are given,
default parameters are used.
1.1 使用PyOD库生成toy example并调用feature bagging
调用方式1:单个LOF基检测器
clf_name = 'LOF'
clf = LOF(n_neighbors=35)
clf.fit(X_train)
调用方式2:多个LOF的FeatureBagging
对比图可见:多个LOF基检测器的FeatureBagging效果好于单个LOF检测器
clf_name = 'FeatureBagging'
clf = FeatureBagging(check_estimator=False)
# clf = FeatureBagging(LOF(n_neighbors=35))
clf.fit(X_train)
调用方式3:多个HBOS的FeatureBagging
对比图可见:基检测器为HBOS时识别准确率比LOF差
clf_name = 'FeatureBagging'
clf = FeatureBagging(HBOS())
clf.fit(X_train)
1.2 采用信用卡欺诈数据调用feature bagging和isolation forest
Task5-FeatureBagging&IForest(信用卡欺诈数据).ipynb
基于LOF基检测器的Feature Bagging:
On Training Data:
Feature Bagging ROC:0.8564, precision @ rank n:0.0457
On Test Data:
Feature Bagging ROC:0.876, precision @ rank n:0.0352
基于HBOS基检测器的Feature Bagging:
On Training Data:
Feature Bagging ROC:0.9475, precision @ rank n:0.3029
On Test Data:
Feature Bagging ROC:0.9533, precision @ rank n:0.338
单个HBOS:
On Training Data:
HBOS ROC:0.947, precision @ rank n:0.3771
On Test Data:
HBOS ROC:0.9659, precision @ rank n:0.3239
iforest:
On Training Data:
IForest ROC:0.9474, precision @ rank n:0.22
On Test Data:
IForest ROC:0.9433, precision @ rank n:0.2746
总结:截止目前,在信用卡欺诈数据上单个检测器准确率最高的是HBOS,但是准确率依然不足50%,故基于HBOS的FeatureBagging准确率还不如单个HBOS。
2. (思考题:feature bagging为什么可以降低方差?)
假设有n个独立同分布的模型,每个模型的方差均为 σ 2 σ^2 σ2,基于方差的性质可得:
V a r ( 1 n ∑ i = 1 n X i ) = 1 n 2 V a r ( ∑ i = 1 n X i ) = σ 2 n Var(\frac1n∑_{i=1}^nX_i)=\frac1{n^2}Var(∑_{i=1}^nX_i)=\frac{σ^2}n Var(n1∑i=1nXi)=n21Var(∑i=1nXi)=nσ2
这样模型均值的方差仅为单模型方差的 1 n \frac1n n1。然而在只有一个数据集的情况下只能训练出一个模型,也就没法求平均。所以为了缓解这个问题,可以采用有放回抽样来模拟生成多个数据集,将每个数据集训练得到的模型平均来降低方差,即是Bagging的基本思想。
参考链接:https://www.cnblogs.com/massquantity/p/9029611.html
3. (思考题:feature bagging存在哪些缺陷,有什么可以优化的idea?)
- Feature Bagging由于存在多个基检测器,训练及预测的耗时较高,可考虑并行化处理
- Feature Bagging抽取 ⌊ d / 2 ⌋ \lfloor d/2 \rfloor ⌊d/2⌋和 ( d − 1 ) (d-1) (d−1)个特征来生成子样本数据,但特征之间有可能相关性极高,导致该步骤失效。在进行模型训练之前,要对数据要充分的认知分析与数据处理。
5、参考文献
[1]Goldstein, M. and Dengel, A., 2012. Histogram-based outlier score (hbos):A fast unsupervised anomaly detection algorithm . InKI-2012: Poster and Demo Track, pp.59-63.
[2]https://cs.nju.edu.cn/zhouzh/zhouzh.files/publication/icdm08b.pdf
[3]《Outlier Analysis》——Charu C. Aggarwal
[4] https://www.cnblogs.com/massquantity/p/9029611.html