异常检测
我们经常需要识别一些异常行为或者表现,比如 机器是否故障,产品是否合格,这类问题的特点就是 正常数据很多,异常数据很少,甚至根本没有;
解决这种问题的思路就是,把 训练样本中 一小部分数据认为是 异常数据,然后训练一个 非常紧凑的决策边界,把 大部分被认为是正常的样本 框起来,并以此边界作为衡量标准,边界外就是异常;
如下图
这种算法我们称为 单分类算法;
解决单分类问题的算法有很多,如
1. 孤立森林:我的博客
2. 自编码器:我的博客
把 自编码器 用来做 异常检测 真的很奇妙,它的思路是,用正常样本训练 自编码器, 输入和输出一定相差不大,如果新的样本通过自编码器,输入和输出相差很大,就是异常样本;
3. One Class SVM:这种方法类似于 SVM,在理解 SVM 的基础上,这个算法没有什么好讲的,所以不单独写一篇博客了;
由于 SVM 在核函数计算时速度很慢,故不适合海量数据,而 孤立森林 可运行在分布式系统上,自编码器 可用 GPU 进行加速,适合海量数据;
One Class SVM
sklearn 提供了一些机器学习算法,用于 奇异点(Novelty) 或者 异常点(Outlier) 检测;
novelty detection:训练样本中没有离群点,我们用训练好的模型去检测,边界外的就是异常; 【自编码器】
outlier dection:训练样本中存在离群点,训练模型时要匹配密集样本,忽略离群点; 【孤立森林】
One Class SVM 既可以是 novelty,也可以是 Outlier,当然,严格的讲,它应该属于 novelty,但实际上训练样本都会存在噪音,我们需要绕过噪音,得到一个干净的模型,这就是 Outlier;
One Class SVM 是一种无监督算法,它的思想是 寻找一个 超球面,使得 正常样本 在球体内,异常样本在球体外,然后 最小化这个球 的半径或者体积;
其中 o 是球心,r 是半径,V(r) 是球的体积,c 是惩罚系数,ξ 是松弛变量; 【基本上等同于 SVM 我的博客】
SVDD 介绍
解决 One Class SVM 的方法很多, SVDD 就是其中一种,SVDD 的思路仍然类似于上面的公式,但略作简化
s.t.
再来张图把
sklearn API
官网示例
import numpy as np import matplotlib.pyplot as plt import matplotlib.font_manager from sklearn import svm xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500)) # Generate train data X = 0.3 * np.random.randn(100, 2) X_train = np.r_[X + 2, X - 2] # Generate some regular novel observations X = 0.3 * np.random.randn(20, 2) X_test = np.r_[X + 2, X - 2] # Generate some abnormal novel observations X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2)) # fit the model clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1) clf.fit(X_train) y_pred_train = clf.predict(X_train) y_pred_test = clf.predict(X_test) y_pred_outliers = clf.predict(X_outliers) n_error_train = y_pred_train[y_pred_train == -1].size n_error_test = y_pred_test[y_pred_test == -1].size n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size # plot the line, the points, and the nearest vectors to the plane Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) plt.title("Novelty Detection") plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu) #绘制异常样本的区域 a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred') #绘制正常样本和异常样本的边界 plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors='palevioletred') #绘制正常样本的区域 s = 40 b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c='white', s=s, edgecolors='k') b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c='blueviolet', s=s, edgecolors='k') c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c='gold', s=s, edgecolors='k') plt.axis('tight') plt.xlim((-5, 5)) plt.ylim((-5, 5)) plt.legend([a.collections[0], b1, b2, c], ["learned frontier", "training observations", "new regular observations", "new abnormal observations"], loc="upper left", prop=matplotlib.font_manager.FontProperties(size=11)) plt.xlabel( "error train: %d/200 ; errors novel regular: %d/40 ; " "errors novel abnormal: %d/40" % (n_error_train, n_error_test, n_error_outliers)) plt.show()
nu 代表异常样本的占比,nu 越大,R 越小,条件越 苛刻
优化
基于蚁群算法的优化 ,可以参考下
参考资料: