一、算法概述
异常检测的应用场景很多,但是大部分时候,都是用在无法很好的获取黑样本的情况下,无法获取黑样本,一般有三种情况:
黑样本出现的概率很低,比如火灾、核泄漏、火山爆发等,百年难遇。
无法分辨黑白样本,比如大量的行为日志、冷启动业务,根本不知道作案模式。
还有一种情况,黑样本很好获取,但是成本很高,比如系统故障、设备故障、光伏发电机的异常检测等,如果要获取黑样本,直接弄坏几个设备测试下就行了......
对于第三种情况,我们能够明确的知道:到目前为止,没有出现过异常,只有正常数据,是白样本,也就是没有问题的数据。面对这种问题,单分类异常检测,就是很好的选择,One Class Learning 比较经典的算法是One-Class-SVM,这个算法的思路非常简单,就是寻找一个超平面将样本中的正例圈出来,预测就是用这个超平面做决策,在圈内的样本就认为是正样本。
在研究OneClassSVM之前,我们看看什么是奇异值检测和异常值检测:
Novelty Detection(奇异值检测):当训练数据中没有离群点,只含有positive(正常)的数据,我们的目标是用训练好的模型去检测另外新发现的样本,通过算法学习其模式,之后用于检测未曾看到过新数据是否属于这个模式,如果属于,该新数据是正常,否则异常,即奇异值。
Outlier Detection(异常值检测):当训练数据中包含离群点,通过相关算法找到训练数据的中心模式,忽略偏差观测值,从而检测出异常值。
严格地讲,我们今天要讲的OneClassSVM不是一种outlier detection方法,而是一种novelty detection方法,它的训练集不应该掺杂异常点,因为模型可能会去匹配学习这些异常点,可能就检测不出来了。但在数据维度很高,或者对相关数据分布没有任何假设的情况下,OneClassSVM也可以作为一种很好的outlier detection方法,学习到的模型,基本上也是忽略了异常值之后的模型。其实在分类任务中,当两类样本非常不平衡时,也可以将个数比例极小的那部分当做异常点来处理,从另外一种角度来完成分类任务,仅用正样本进行训练,非正样本就是另一类!欺诈检测、入侵检测、恶性肿瘤检测、产品质量检测等。
有个小案例,可以帮助我们对奇异值检测的理解,有一个小和尚,他从小就在寺庙长大,只见过男性,没见过女生,那么遇到一个男性,他能很快地基于这个男性与他之前接触的男性有类似的特征,给出这个人是男性的结论。但如果遇到的是一个女性,他会发现,这个人与他之前所认知的男性的特征差异很大,进而会得出她不是男性的判断,但是并不会得出是女性的判断。
但是由于svm的核函数计算比较耗时,在海量数据的场景用的并不多,但是思路值得借鉴,因此这个文章我也不会写的太细,其实文章写了一年多了,去年我在测试的时候,发现20多w的数据跑着都很费劲。真是。。。。,所以就放弃了,如果大家的场景有强需求,或者计算资源比较充足,那还是可以深入研究下的。
二、算法原理
OneClass SVM的一般工作流程如下:
数据映射:将正常数据映射到高维特征空间中,使得正常数据点能够被一个超平面所包围。这个超平面被称为决策边界。
寻找超平面:通过最大化超平面与正常数据之间的间隔,寻找一个最优的分割超平面,使得异常点尽可能远离该超平面。这意味着决策边界要尽可能远离正常数据点。
异常检测:对于新的数据点,通过计算其与超平面的距离,来判断该数据点是否为异常,距离较大的数据点更有可能是异常点。
OneClass SVM的关键在于如何选择最优的超平面,以使得正常数据被尽可能包围,而异常数据则被远离。这是通过优化一个目标函数来实现的,其中包括最小化超平面到最近正常数据点的距离和最大化超平面与正常数据之间的间隔,常用的实现的方法有下面两个。
1、OCSVM
一种实现方法是 One-Class SVM (OCSVM),首次是在论文《Support Vector Method for Novelty Detection》中(奇异值检测的支持向量方法),由 Bernhard Schölkopf 等人在 2000 年提出, 其与 SVM 的原理类似,更像是将零点作为负样本点,其他数据作为正样本点,来训练支持向量机,策略是将数据映射到与内核相对应的特征空间,在数据与原点间构建超平面,该超平面与原点呈最大距离。
现在假设该超平面为:
目标就是在分类正确的基础上最大化超平面与原点的距离:
2、SVDD
另一种方法则是 SVDD,是在其同名论文《Support Vector Data Description》中由 DAVID M.J. TAX 等人提出。相比于 OCSVM,SVDD 定义了一个模型,该模型给出了一个包围全部数据的封闭边界:超球体。球体的特征是中心 𝑎 和半径 R2>0。我们通过最小化 R2来最小化球体的体积,并要求球体包含所有训练样本 xi。这与Schólkopf、Burges和Vapnik(1995)中用于估计分类器的VC维数的方法(由包围数据的最小球体的直径限定)相同。并且文章中证明了该方法与 OCSVM 求解的超平面相似,其最优化目标如下:
3、优缺点
1)算法优点
不需要异常数据进行训练,只需要正常数据即可。
对于高维数据和复杂的数据分布具有较好的适应性。
可以通过调整模型参数来控制异常点的检测灵敏度。
2)算法缺点
在处理高维数据和大规模数据时,计算复杂度较高,时间比较久
对于数据分布不均匀或存在噪声的情况,效果可能不理想。
需要谨慎选择模型参数,以避免过拟合或欠拟合的情况。
三、算法实现
1、基本用法
官方链接:http://scikit-learn.org/stable/modules/generated/sklearn.svm.OneClassSVM.html
sklearn.svm.OneClassSVM(*, kernel='rbf', degree=3,
gamma='scale', coef0=0.0,
tol=0.001, nu=0.5,
shrinking=True,
cache_size=200,
verbose=False, max_iter=-1
)
*星号:这是PEP-3102和Python3.0引入的一种新的函数参数规范语法,它指示KNeighborsClassifier类的构造函数在n_neighbors之后不接受任何其他位置参数,其余所有参数都是仅关键字的。仅关键字参数与名称和值一起提供,而位置参数则不必提供。在这种情况下,您可以合法地使用以下语法(为n_neighbors提供值)
2、参数解释
kernel:核函数(一般使用高斯核){‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’}, 默认=’rbf’
指定算法中使用的内核类型。它必须是“linear”,“poly”,“rbf”,“sigmoid”,“precomputed”或者“callable”中的一个。如果没有给出,将默认使用“rbf”。如果给定了一个可调用函数,则用它来预先计算核矩阵。
nu:浮点数,默认=0.5
边界误差分数的上限和支持向量分数的下限。区间限定在(0,1)内。默认情况下取0.5。
degree:整数型,默认=3
多项式核函数的次数(' poly '),将会被其他内核忽略。
gamma:浮点数或者{‘scale’, ‘auto’} , 默认=’scale’
核系数包含‘rbf’, ‘poly’ 和‘sigmoid’
如果gamma='scale'(默认),则它使用1 / (n_features * X.var())作为gamma的值,
如果是auto,则使用1 / n_features。
在0.22版本有改动:默认的gamma从“auto”改为“scale”
coef0:浮点数,默认=0.0
核函数中的独立项。它只在' poly '和' sigmoid '中有意义。
tol:浮点数,默认=1e-3
残差收敛条件。
shrinking:布尔值,默认=True
是否使用缩小启发式,参见使用指南
cache_size:浮点数,默认=200
指定内核缓存的大小(以MB为单位)。
verbose:布尔值,默认=False
是否启用详细输出。
请注意,此参数针对liblinear中运行每个进程时设置,如果启用,则可能无法在多线程上下文中正常工作。
max_iter:整数型,默认=-1
对求解器内的迭代进行硬性限制,或者为-1(无限制时)。
3、属性解释
support_:形如(n_SV,)的数组。支持向量的指标。
support_vectors_:形如(n_SV, n_features)的数组。支持向量
dual_coef_:形如(n_class-1, n_SV)的数组。决策函数中支持向量的系数。
coef_:形如(n_class * (n_class-1) / 2, n_features)的数组。分配给特征的权重(原始问题的系数),仅在线性内核的情况下可用。coef_是一个继承自raw_coef_的只读属性,它遵循liblinear的内部存储器布局。
intercept_:形如(n_class * (n_class-1) / 2,)的数组。决策函数中的常量。
offset_:浮点型。用于从原始分数定义决策函数的偏移量。我们有这样的关系:decision_function = score_samples - offset_。偏移量与intercept_相反,是为了与其他离群点检测算法保持一致而提供的。
此部分新增在版本0.20。
fit_status_:整数型。如果拟合无误,则为0;如果算法未收敛,则为1。
4、方法介绍
fit(X):训练,根据训练样本和上面两个参数探测边界。(注意是无监督)
predict(X):返回预测值,+1就是正常样本,-1就是异常样本。
decision_function(X):返回各样本点到超平面的函数距离(signed distance),正的维正常样本,负的为异常样本。
set_params(**params):设置这个评估器的参数,该方法适用于简单估计器以及嵌套对象(例如管道),而后者具有表单<component>_<parameter>的参数,,因此可以更新嵌套对象的每个组件。
get_params([deep]):获取这个评估器的参数。
fit_predict(X[, y]):在X上执行拟合并返回X的标签,对于异常值,返回 -1 ,对于内点,返回1。
5、算法示例
用官网的数据,举个小例子,大家知道下这个算法的大概用法,后面加个案例在实战数据中的用法和效果。
from sklearn.svm import OneClassSVM
X = [[0], [0.44], [0.45], [0.46], [1]]
clf = OneClassSVM(gamma='auto').fit(X)
clf.predict(X)
array([-1, 1, 1, 1, -1])
clf.score_samples(X)
array([1.7798..., 2.0547..., 2.0556..., 2.0561..., 1.7332...])
四、案例分析
之前的信用卡数据,我发现我的单机跑不动....。后面想想办法在写,下面是之前的异常检测的文章和数据。
基于深度学习Autoencoder的信用卡欺诈异常检测,效果非常牛逼
异常检测算法之(HBOS)-Histogram-based Outlier Score
异常检测算法之(KNN)-K Nearest Neighbors
往期精彩:
SynchroTrap-基于松散行为相似度的欺诈账户检测算法