1 环境配置
我是安装的anaconda,python 3.7。
自带sklearn==0.21.2。
pip安装pyod,选择清华源一键安装
pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple
安装的pyod版本是0.8.5。
2 异常检测
2.1 异常检测的概念
异常检测(Outlier Detection),顾名思义,是识别与正常数据不同的数据,与预期⾏为差异⼤的数据。
识别如信⽤卡欺诈,⼯业⽣产异常,⽹络流⾥的异常(⽹络侵⼊)等问题,针对的是少数的事件。
2.2 异常的类别
**点异常:**指的是少数个体实例是异常的,⼤多数个体实例是正常的,例如正常⼈与病⼈的健康指标;
**上下⽂异常:**⼜称上下⽂异常,指的是在特定情境下个体实例是异常的,在其他情境下都是正常的,例如在特定时间下的温度突然上升或下降,在特定场景中的快速信⽤卡交易;
**群体异常:**指的是在群体集合中的个体实例出现异常的情况,而该个体实例⾃⾝可能不是异常,例如社交⽹络中虚假账号形成的集合作为群体异常⼦集,但⼦集中的个体节点可能与真实账号⼀样正常。
2.3 异常检测任务分类
有监督:训练集的正例和反例均有标签
⽆监督:训练集⽆标签
弱监督:在训练集中只有单⼀类别(正常实例)的实例,没有异常实例参与训练。参考资料里这里给的是半监督,我个人认为这个场景不符合半监督的一般含义,更加符合Negative and Unlabeled Learning (NU学习) 的场景。
3 异常检测常用方法
参考资料给出了3个类别的方法。
我简单的归纳一下,大概可以分为这样3类。
3.1 基于度量准则的单分类器分类方法
i 统计学方法
对数据的正常性做出假定。它们假定正常的数据对象由⼀个统计模型产⽣,而不遵守该模型的数据是异常点。统计学⽅法的有效性⾼度依赖于对给定数据所做的统计模型假定是否成立。
异常检测的统计学⽅法的⼀般思想是:学习⼀个拟合给定数据集的⽣成模型,然后识别该模型低概率区域中的对象,把它们作为异常点。
然而,这一概率测度本身也是一种度量准则。
ii 基于相似度的方法
- 基于集群(簇)的检测,如DBSCAN等聚类算法。
- 基于距离的度量,如k近邻算法。
- 基于密度的度量,如LOF(局部离群因⼦)算法。
3.2 基于多个分类器的集成学习方法
集成学习方法的基本思路是多个分类器的投票。
我个人不是很喜欢集成,因为我自己的研究领域中,集成方法总是容易错的更离谱,可能是因为我研究的带有标签噪声的学习问题。
3.3 基于树模型的学习方法
在有标签的情况下,可以使⽤树模型(gbdt,xgboost等)进⾏分类,缺点是异常检测场景下数据标签是不均衡的,但是利⽤机器学习算法的好处是可以构造不同特征。
据说工业界,树模型是一类常用的方法,具有很好的性质。但是也不是我的主要研究领域。
4 相关库的使用探索
参考链接:
https://zhuanlan.zhihu.com/p/58313521
https://pyod.readthedocs.io/en/latest/ (Pyod库官⽹)
PyOD中 API介绍与实例(API References & Examples)
特别需要注意的是,异常检测算法基本都是无监督学习,所以只需要X(输入数据),而不需要y(标签)。PyOD的使用方法和Sklearn中聚类分析很像,它的检测器(detector)均有统一的API。所有的PyOD检测器clf均有统一的API以便使用,完整的API使用参考可以查阅(API CheatSheet - pyod 0.6.8 documentation):
-
fit(X): 用数据X来“训练/拟合”检测器clf。即在初始化检测器clf后,用X来“训练”它。
-
fit_predict_score(X, y): 用数据X来训练检测器clf,并预测X的预测值,并在真实标签y上进行评估。此处的y只是用于评估,而非训练
-
decision_function(X): 在检测器clf被fit后,可以通过该函数来预测未知数据的异常程度,返回值为原始分数,并非0和1。返回分数越高,则该数据点的异常程度越高
-
predict(X): 在检测器clf被fit后,可以通过该函数来预测未知数据的异常标签,返回值为二分类标签(0为正常点,1为异常点)
-
predict_proba(X): 在检测器clf被fit后,预测未知数据的异常概率,返回该点是异常点概率当检测器clf被初始化且fit(X)函数被执行后,clf就会生成两个重要的属性:
-
decision_scores: 数据X上的异常打分,分数越高,则该数据点的异常程度越高
-
labels_: 数据X上的异常标签,返回值为二分类标签(0为正常点,1为异常点)
不难看出,当我们初始化一个检测器clf后,可以直接用数据X来“训练”clf,之后我们便可以得到X的异常分值 (clf.decision_scores) 以及异常标签 (clf.labels_) 。当clf被训练后(当fit函数被执行后),我们可以使用 decision_function() 和 predict() 函数来对未知数据进行训练。
示例:
from pyod.models.knn import KNN # imprt kNN分类器
import sklearn
import pyod
import numpy as np
# 训练一个kNN检测器
clf_name = 'kNN'
clf = KNN() # 初始化检测器clf
# 通过np创建一个toy数据
X1 = np.random.randn(100, 20)
X2 = np.random.rand(10,20)*4
X_train = np.r_[X1,X2]
clf.fit(X_train) # 使用X_train训练检测器clf
# 返回训练数据X_train上的异常标签和异常分值
y_train_pred = clf.labels_ # 返回训练数据上的分类标签 (0: 正常值, 1: 异常值)
y_train_scores = clf.decision_scores_ # 返回训练数据上的异常值 (分值越大越异常)
y_train_pred
# array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
基本上算是能检测出来吧。但是要是把rand的倍数调小就不行了。完犊子。