diff --git "a/\345\274\202\345\270\270\346\243\200\346\265\213 task_0.md" "b/\345\274\202\345\270\270\346\243\200\346\265\213 task_0.md" new file mode 100644 index 0000000..2b7c16c --- /dev/null +++ "b/\345\274\202\345\270\270\346\243\200\346\265\213 task_0.md" @@ -0,0 +1,36 @@ +# 异常检测 task_0 +## 1 datawhale论坛与项目介绍 + +论坛:http://datawhale.club/ + +在论坛如何提问:http://datawhale.club/t/topic/728/2 + +项目介绍:http://datawhale.club/t/topic/1425 + +学习任务:https://github.com/datawhalechina/team-learning + +PPT简介:https://datawhale.feishu.cn/docs/doccnY7uZLRKtxWpU5oazEfOq8d + +## 2 打卡环节(微信小程序) +2.1 打卡内容 +打卡,即任选Datawhale论坛、CSDN、简书等平台,将自己的学习体会,输出成【学习分享】后,将分享的链接,填至问卷的 “打卡链接” 中相应的位置。 + +2.2 打卡要求 +打卡形式不限,可撰写学习笔记,包含自己运行代码;可记录重要知识,记录自己总结的学习体会。 +希望能有自己的理解,不要照搬学习文档。 +每位同学需在打卡截止期前打卡,否则后面的打卡无法点亮,未按时打卡将会【被抱出群】。 + +2.3 打卡示范 +https://mp.weixin.qq.com/s/IOlHIEIQhuIaubTeP4o39w +https://mp.weixin.qq.com/s/wxUVHapEiPUV2LSBbEu5-g +https://mp.weixin.qq.com/s/cXSRcMk_0t8RxSaKb0sHww +https://mp.weixin.qq.com/s/fsT6rzpL5cuzh2usNjzzbA + +## 3 Timeline +task_0:熟悉规则 +task_1:异常检测介绍(2021/05/12-02:59截止) +task_2:基于统计学的方法(2021/05/15-02:59截止) +task_3:线性模型(2021/05/18-02:59截止) +task_4:基于相似度的方法(2021/05/21-02:59截止) +task_5:高维异常检测(2021/05/24-02:59截止) + diff --git "a/\345\274\202\345\270\270\346\243\200\346\265\213-task1.md" "b/\345\274\202\345\270\270\346\243\200\346\265\213-task1.md" new file mode 100644 index 0000000..b3c6a44 --- /dev/null +++ "b/\345\274\202\345\270\270\346\243\200\346\265\213-task1.md" @@ -0,0 +1,120 @@ +## 异常检测-task1:异常检测概述与初步实现 + +### 1 异常检测定义与应用 + +#### 1.1 异常检测定义 + +- 定义:**异常检测**(英语:**anomaly detection**)对不符合预期模式或数据集中其他项目的项目、事件或观测值的识别,通常异常项目会转变成银行欺诈、结构缺陷、医疗问题、文本错误等类型的问题。异常也被称为离群值、新奇、噪声、偏差和例外。 +- 有三大类异常检测方法。 在假设数据集中大多数实例都是正常的前提下,**无监督异常检测**方法能通过寻找与其他数据最不匹配的实例来检测出未标记测试数据的异常。**监督式异常检测**方法需要一个已经被标记“正常”与“异常”的数据集,并涉及到训练分类器(与许多其他的统计分类问题的关键区别是异常检测的内在不均衡性)。**半监督式异常检测**方法根据一个给定的*正常*训练数据集创建一个表示正常行为的模型,然后检测由学习模型生成的测试实例的可能性。 +- 类别:点异常(少数个体实例异常)、上下文异常(特定情境下个体实例异常,其他情境下正常)、群体异常(群体集合中的个体实例异常,自身可能不异常) +> ***引用来源:*** [维基百科-异常检测](https://zh.wikipedia.org/wiki/%E5%BC%82%E5%B8%B8%E6%A3%80%E6%B5%8B) + +#### 1.2 异常检测应用 + +异常检测的应用领域有:故障检测、物联网异常检测、欺诈检测、工业异常检测、时间序列异常检测、视频异常检测、日志异常检测、医疗异常检测、网络入侵检测等。 + +### 2 异常检测的实现算法 + +- **统计与概率模型:**先对数据分布进行假设,在假设下定义异常。如:假设数据服从高斯分布,可以设定阈值,将距离均值某一阈值以外的数据当做异常点。还可以通过计算Z分数和四分位距(IQR) +- **线性模型:**典型的有PCA,将数据降到m维之后,计算重建误差,利用正常点的重建误差小这一特点找到异常点,也可以计算样本点到新m维超空间的加权欧式距离,由此找到异常点。 +- **基于相似度衡量的模型:** 异常点因为和正常点的分布不同,因此相似度较低,由此衍生出来的方法有:k近邻(异常点的k近邻距离大)、基于密度的LOF方法(领域密度小的为异常点)、基于簇的DBSCAN算法(异常点不能被归位某一簇) +- **集成方法:**最早的框架为feature bagging,也有用boosting的(较少) + +>***引用来源:***[数据挖掘中常见的异常检测算法有哪些?](https://www.zhihu.com/question/280696035/answer/417091151) + +### 3 利用开源库:PyOD简单实现异常检测 + +#### 3.1 PyOD库的介绍 + +> ***引用来源:*** [用PyOD工具库进行「异常检测」](https://zhuanlan.zhihu.com/p/58313521) +> [Python Outlier Detection (PyOD)](https://github.com/yzhao062/pyod) :是时下最流行的异常检测库,它涵盖了近20种异常检测方法(LOF/LOCI/ABOD/GAN); +> +> 而且**简单易用且一致的API**,只需要几行代码就可以完成异常检测; +> +> 使用JIT和并行化(parallelization)进行优化,加速算法运行及扩展性(scalability),可以处理大量数据; + +PyOD论文:https://www.jmlr.org/papers/volume20/19-011/19-011.pdf 发表于:https://www.jmlr.org/ +文档与API:https://pyod.readthedocs.io/en/latest/ 完整API:https://pyod.readthedocs.io/en/latest/api_cc.html +PyOD下载:https://pypi.org/project/pyod/ +jupyter示例:https://hub-binder.mybinder.ovh/user/yzhao062-pyod-sug237v4/tree + +#### 3.2 API介绍 + +大部分异常检测算法是无监督学习,PyOD的检测器基本上都有统一的API使用,使用方法与sklearn很像,API使用参考:https://pyod.readthedocs.io/en/latest/api_cc.html + +- **fit(X):** 在初始化检测器clf后,用数据X训练/拟合clf,clf被fit后会有两个属性: + 1. **decision_scores:** 对数据X 进行异常打分,分越高,X的异常程度越高 + 2. **labels_:** 数据X的异常标签,返回二分类标签(0为正常点,1为异常点) +- **fit_predict_score(X,y):** 用X训练检测器clf后,预测X的预测值,在真实标签y上评估(并非训练) +- **decision_function(X):** 在检测器clf被fit后,可以通过该函数来预测未知数据的异常程度,返回值为原始分数,并非0和1。返回分数越高,则该数据点的异常程度越高 +- **predict(X):** 在检测器被fit之后,可以用该函数来预测未知数据的异常标签,(0为正常点,1为异常点) +- **predict_proba(X):** 在检测器被fit后,用该函数预测未知标签的异常概率, + +#### 3.3 PyOD API demo: + +- 安装pyod: + +``` +! pip install pyod +``` +- 导入相应的库函数(以KNN为例) +``` +from pyod.models.knn import KNN +from pyod.utils.data import generate_data +from pyod.utils.data import evaluate_print +from pyod.utils.example import visualize +``` +- 生成数据集 +``` +contamination = 0.1 #异常值的比例 +n_train = 200 +n_test = 100 + + +X_train, y_train, X_test, y_test = \ + generate_data(n_train=n_train, + n_test=n_test, + n_features=2, + contamination=contamination, + random_state=42) #n_features = 2时,可以可视化,见后文 +``` +- 训练clf +``` +clf_name = 'KNN' +clf = KNN() +clf.fit(X_train) +``` +- 打印评估结果 +``` +y_train_pred = clf.labels_ # binary labels (0: inliers, 1: outliers) +y_train_scores = clf.decision_scores_ # raw outlier scores +y_test_pred = clf.predict(X_test) # outlier labels (0 or 1) +y_test_scores = clf.decision_function(X_test) # outlier scores + +# evaluate and print the results +print("\nOn Training Data:") +evaluate_print(clf_name, y_train, y_train_scores) +print("\nOn Test Data:") +evaluate_print(clf_name, y_test, y_test_scores) +``` + +knn评估 + +- 可视化 +``` +visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred, + y_test_pred, show_figure=True, save_figure=False) +``` + +可视化 + + +#### 3.4 PyOD学习资源 +权威教程: + +>***引用来源:***[用PyOD工具库进行「异常检测」](https://zhuanlan.zhihu.com/p/58313521) +>Analytics Vidhya: [An Awesome Tutorial to Learn Outlier Detection in Python using PyOD Library](https://www.analyticsvidhya.com/blog/2019/02/outlier-detection-python-pyod/) +>KDnuggets: [Intuitive Visualization of Outlier Detection Methods](https://www.kdnuggets.com/2019/02/outlier-detection-methods-cheat-sheet.html) +>awesome-machine-learning: [General-Purpose Machine Learning](https://github.com/josephmisiti/awesome-machine-learning#python-general-purpose) +>开发团队所整理的:[anomaly-detection-resources](https://github.com/yzhao062/anomaly-detection-resources) + diff --git "a/\345\274\202\345\270\270\346\243\200\346\265\213-task2.md" "b/\345\274\202\345\270\270\346\243\200\346\265\213-task2.md" new file mode 100644 index 0000000..6c585a5 --- /dev/null +++ "b/\345\274\202\345\270\270\346\243\200\346\265\213-task2.md" @@ -0,0 +1,151 @@ +## 基于统计学方法的异常检测 +### 1、概述 + +#### 1.1 基本原理 +首先假设正常数据服从某一分布,对于异常点,并不符合该分布,由此可以利用统计学方法找到异常点。一般思想为:学习一个拟合给定数据集的生成模型,然后识别该模型低概率区域中的对象,把它们作为异常点。 + +#### 1.2 主要类型 +- 参数方法 +假定正常的数据对象被一个以$\Theta$为参数的参数分布产生。该参数分布的概率密度函数$f(x,\Theta)$给出对象$x$在该分布下的概率。该值越小,$x$越可能是异常点。 +- 非参数方法 +并不假定先验分布,而是通过输入数据确定模型,并不是完全无参,只是参数的个数和性质很灵活。 + +### 2、参数方法 +#### 2.1 正态分布下的异常点检测 +对于一维数据集$\{x^{(1)}, x^{(2)}, ..., x^{(m)}\}$,可以假定它们服从一元正态分布:$x^{(i)}\sim N(\mu, \sigma^2)$,对于参数$\mu$和$\sigma$,可以用矩法估计的思想求出来: + +$\mu=\frac 1m\sum_{i=1}^m x^{(i)}$ + +$\sigma^2=\frac 1m\sum_{i=1}^m (x^{(i)}-\mu)^2$ + +得到参数后就意味着找到了正态分布的概率密度函数;接下来可以设定阈值,以此找到异常点(概率小于该阈值的数据)例如:常见的3$\sigma$原则:超出$(\mu-3\sigma, \mu+3\sigma)$的数据可以被认为是异常点;也可以利用箱线图,找到上下四分位数( Q1、Q3),此时,异常点常被定义为小于Q1-1.5IQR或大于Q3+1.5IQR的那些数据。 +利用如下的Python代码可以很容易的画出箱线图 + +```python +import numpy as np +import seaborn as sns +import matplotlib.pyplot as plt + +data = np.random.randn(50000) * 20 + 20 +sns.boxplot(data=data) +``` +结果如下 + + + +#### 2.2 多元数据下的异常点检测 +当数据的维度大于1时,可以将一元异常点的检测方法推广到多元,具体方法为:多元异常点检测任务转换成一元异常点检测问题。例如基于正态分布的一元异常点检测扩充到多元情形时,可以求出每一维度的均值和标准差(利用矩法估计),此时的概率密度函数为: +$p(x)=\prod_{j=1}^n p(x_j;\mu_j,\sigma_j^2)=\prod_{j=1}^n\frac 1{\sqrt{2\pi}\sigma_j}exp(-\frac{(x_j-\mu_j)^2}{2\sigma_j^2})$ +上式适用于各个维度相互独立的情况,在各个维度之间由关联时,需要用到多元高斯分布 + +- 多元高斯分布 +$\mu=\frac{1}{m}\sum^m_{i=1}x^{(i)}$ +$\sum=\frac{1}{m}\sum^m_{i=1}(x^{(i)}-\mu)(x^{(i)}-\mu)^T$ +$p(x)=\frac{1}{(2 \pi)^{\frac{n}{2}}|\Sigma|^{\frac{1}{2}}} \exp \left(-\frac{1}{2}(x-\mu)^{T} \Sigma^{-1}(x-\mu)\right)$ + +### 3 非参数方法 +对数据集进行先验分布假定是一件主观性很强的事,而非参数方法不受参数的拘束,因此在很多情况下都适用。 +- 直方图法 +1.构造直方图。使用输入数据(训练数据)构造一个直方图。该直方图可以是一元的,或者多元的(如果输入数据是多维的)。指定直方图的类型(等宽的或等深的)和其他参数(直方图中的箱数或每个箱的大小等)。与参数方法不同,这些参数并不指定数据分布的类型。 +2.检测异常点。为了确定一个对象是否是异常点,可以对照直方图检查它。在最简单的方法中,如果该对象落入直方图的一个箱中,则该对象被看作正常的,否则被认为是异常点。也可以使用直方图赋予每个对象一个异常点得分。例如令对象的异常点得分为该对象落入的箱的容积的倒数。 + +使用直方图检验异常点的方法也有缺陷:对箱尺的要求严格,尺寸太小,正常点落不到箱中,尺寸太大,部分异常点成为漏网之鱼 + +### 4、HBOS(Histogram-based Outlier Score) +1.为每个数据维度做出数据直方图。对分类数据统计每个值的频数并计算相对频率。对数值数据根据分布的不同采用以下两种方法: + +* 静态宽度直方图:标准的直方图构建方法,在值范围内使用k个等宽箱。样本落入每个桶的频率(相对数量)作为密度(箱子高度)的估计。时间复杂度:$O(n)$ + +* 动态宽度直方图:首先对所有值进行排序,然后固定数量的$\frac{N}{k}$个连续值装进一个箱里,其 中N是总实例数,k是箱个数;直方图中的箱面积表示实例数。因为箱的宽度是由箱中第一个值和最后一个值决定的,所有箱的面积都一样(因为箱子中的数量一样),因此每一个箱的高度都是可计算的。这意味着跨度大的箱的高度低,即密度小,只有一种情况例外,超过k个数相等,此时允许在同一个箱里超过$\frac{N}{k}$值。 + + 时间复杂度:$O(n\times log(n))$ + +2.对每个维度都计算了一个独立的直方图,其中每个箱子的高度表示密度的估计。然后为了使得最大高度为1(确保了每个特征与异常值得分的权重相等),对直方图进行归一化处理。最后,每一个实例的HBOS值由以下公式计算: +$$ +H B O S(p)=\sum_{i=0}^{d} \log \left(\frac{1}{\text {hist}_{i}(p)}\right) +$$ +推导如下: + +假设样本*p*第 *i* 个特征的概率密度为$p_i(p)$ ,则*p*的概率密度可以计算为: +$$ +P(p)=P_{1}(p) P_{2}(p) \cdots P_{d}(p) +$$ +两边取对数: +$$ +\begin{aligned} +\log (P(p)) &=\log \left(P_{1}(p) P_{2}(p) \cdots P_{d}(p)\right) =\sum_{i=1}^{d} \log \left(P_{i}(p)\right) +\end{aligned} +$$ +概率密度越大,异常评分越小,为了方便评分,两边乘以“-1”: +$$ +-\log (P(p))=-1 \sum_{i=1}^{d} \log \left(P_{t}(p)\right)=\sum_{i=1}^{d} \frac{1}{\log \left(P_{i}(p)\right)} +$$ +最后可得: +$$ +H B O S(p)=-\log (P(p))=\sum_{i=1}^{d} \frac{1}{\log \left(P_{i}(p)\right)} +$$ +HBOS在全局异常检测问题上表现良好,但不能检测局部异常值。但是HBOS比标准算法快得多,尤其是在大数据集上。 + +### 4 利用pyod库调用HBOS + +```python +from __future__ import division +from __future__ import print_function + +import os +import sys + +# temporary solution for relative imports in case pyod is not installed +# if pyod is installed, no need to use the following line +sys.path.append( + os.path.abspath(os.path.join(os.path.dirname("__file__"), '..'))) + +from pyod.models.hbos import HBOS +from pyod.utils.data import generate_data +from pyod.utils.data import evaluate_print +from pyod.utils.example import visualize + +if __name__ == "__main__": + contamination = 0.1 # percentage of outliers + n_train = 200 # number of training points + n_test = 100 # number of testing points + + # Generate sample data + X_train, y_train, X_test, y_test = \ + generate_data(n_train=n_train, + n_test=n_test, + n_features=2, + contamination=contamination, + random_state=42) + + # train HBOS detector + clf_name = 'HBOS' + clf = HBOS() + clf.fit(X_train) + + # get the prediction labels and outlier scores of the training data + y_train_pred = clf.labels_ # binary labels (0: inliers, 1: outliers) + y_train_scores = clf.decision_scores_ # raw outlier scores + + # get the prediction on the test data + y_test_pred = clf.predict(X_test) # outlier labels (0 or 1) + y_test_scores = clf.decision_function(X_test) # outlier scores + + # evaluate and print the results + print("\nOn Training Data:") + evaluate_print(clf_name, y_train, y_train_scores) + print("\nOn Test Data:") + evaluate_print(clf_name, y_test, y_test_scores) + + # visualize the results + visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred, + y_test_pred, show_figure=True, save_figure=False) +``` + +结果及可视化如下: + +![roc](E:\datawhale\AnomalyDetection\AnomalyDetection\img\hbos-roc.png) + + + +HBOS算法在训练集上的ROC为0.8,在验证集上的ROC为0.6,效果一般 \ No newline at end of file