8.0.异常检测
1)题目:
在本练习中,您将实现异常检测算法,并将其应用于检测网络中的故障服务器。在第二部分中,您将使用协同过滤来构建电影推荐系统。
在本练习中,您将实现一个异常检测算法来检测服务器计算机中的异常行为。这些特性度量每个服务器的吞吐量(mb/s)和响应的延迟(ms)。在服务器运行时,您收集了m = 307个关于它们行为的样本,因此有一个未标记的数据集{x(1),…,x(m)}。您怀疑这些样本中的绝大多数都是正常运行的服务器的“正常”(非异常)样本,但是也可能有一些服务器在这个数据集中异常运行的样本。
您将使用高斯模型来检测数据集中的异常样本。您将首先从一个二维数据集开始,该数据集可以可视化算法在做什么。在该数据集上,您将拟合高斯分布,然后找到概率非常低的值,考虑为异常。之后,您将把异常检测算法应用于多维的较大数据集。
数据集链接: https://pan.baidu.com/s/1cEgQIvehUcLxZ0WVhxcPuQ 提取码: xejn
2)知识点概括:
-
异常检测(anomaly detection)用数据集建立概率模型 ,如果新的测试数据在这个模型上小于某个阈值,则说它极大可能为异常点
-
高斯分布/正态分布
密度估计(density estimation)使用联合密度函数作为概率模型 ,这里其实是用到了每个特征是独立的,但是视频上说实际上不独立效果也差不多
-
划分训练集、验证集和测试集:
假设有10000个反例和20个正例(y=1)
选6000个反例作为无标签的训练集
选2000个反例和10个正例作为训练集
选2000个反例和10个正例作为测试集 -
选择阈值 的方法:
在验证集上尝试不同的阈值,选择那个能最大化F1值的那个阈值
F1值是基于查准率 和查全率 的调和平均定义的 ,因此 ,其中TP、FP、TN和FN分别表示真正例、假正例、真反例和假反例的例数,m表示样例总数。 -
什么时候选择异常检验/监督学习:
1.选择异常检验
反例数量远远大于正例数量时(正例数量过少)
异常的情况有多种不同的可能性时
2.选择监督学习
正反例数量相当时(正例数量足够)
未来的反例和训练集中的很类似 -
如果数据的直方图看起来不是高斯分布,可以进行一些变换,使得数据尽量服从高斯分布,再进行异常检验
-
对于特征相关的情况下使用多元高斯分布可以解决
-
多元高斯与一元高斯乘积之间的比较:
多元高斯可以自动捕捉特征之间的协方差,当你在使用一元高斯的乘积,想通过异常的组合值来捕捉异常样本时,必须产生一些新特征来告诉模型怎么识别异常。但是多元高斯模型计算花销大很多。而且多元高斯必须要求样本数量大于特征数量(一般来说远大于的情况使用比较合理),否则协方差矩阵不可逆,而一元高斯的乘积在这种情况下也可以做。
3)大致步骤:
-
数据导入及可视化。
-
估计高斯分布的参数,然后得到联合密度,再可视化这个联合密度的等概率曲线。注意在写联合密度时,如果sigma2为矩阵,即协方差矩阵,则直接用多元高斯分布的公式即可,若是一维向量,则转化成对角矩阵的协方差阵,再带入多元高斯分布的公式,因为当协方差阵为对角阵时相当于变量独立,此时联合密度等于单个密度函数相乘。然后再用等高线contour函数画出等概率曲线。
-
发现异常点。使用验证集,得到一个最好的阈值,这里最好的评价标准为F1值,即得到F1值最高的那个阈值。得到阈值为8.99e-05,F1值为0.875。然后再用这个阈值找出异常点,在图上把这些点圈出来。
-
多维数据的异常检验。执行一样的操作,也用验证集找阈值,得到117个异常值。
4)关于Python:
-
np.ndim( )函数可以返回矩阵或向量的维数。
-
np.linalg.det( )函数可以求矩阵的行列式。
-
np.linalg.inv( )函数可以求矩阵的逆。
5)代码与结果:
import numpy as np
import matplotlib.pyplot as plt
import scipy.io as scio
'''============================part1 数据导入及可视化========================='''
data = scio.loadmat('ex8data1.mat')
x = data['X']
xval = data['Xval']
yval = data['yval']
plt.scatter(x[:,0], x[:,1], marker='x', c='b', s=10)
plt.xlim((0,30))
plt.ylim((0,30))
plt.xlabel('Latency (ms)')
plt.ylabel('Throughput (mb/s)')
'''============================part2 模型估计===================================='''
'''估计高斯分布的参数'''
def estimateGaussian(x):
mu = x.mean(axis=0) #求每列的均值
sigma2 = x.var(axis=0) #求每列的方差,这里自由度为m
return mu, sigma2
mu, sigma2 = estimateGaussian(x)
'''联合密度'''
def multivariateGaussian(x, mu, sigma2):
p = np.zeros((x.shape[0],1))
n = len(mu)
if np.ndim(sigma2) == 1:
sigma2 = np.diag(sigma2) #对角阵
for i in range(x.shape[0]):
p[i] = (2*np.pi)**(-n/2) * np.linalg.det(sigma2)**(-1/2) * np.exp(-0.5*(x[i,:]-mu).T@np.linalg.inv(sigma2)@(x[i,:]-mu))
return p
p = multivariateGaussian(x, mu, sigma2) #第一项为6.47082850e-02
'''等概率曲线'''
def visualizeFit(x, mu, sigma2):
a = np.linspace(0, 30, 100)
b = np.linspace(0, 30, 100)
aa, bb = np.meshgrid(a, b)
z = multivariateGaussian(np.c_[aa.flatten(), bb.flatten()], mu, sigma2)
z = z.reshape(aa.shape)
levels = [10**h for h in range(-20,0,3)]
plt.contour(a, b, z, levels, linewidths=1)
plt.scatter(x[:,0], x[:,1], marker='x', c='b', s=10)
plt.xlabel('Latency (ms)')
plt.ylabel('Throughput (mb/s)')
visualizeFit(x, mu, sigma2)
'''============================part3 发现异常点========================='''
#验证集的概率向量
pval = multivariateGaussian(xval, mu, sigma2)
'''寻找最优(F1最大的)的阈值'''
def selectThreshold(yval, pval):
bestF1 = 0
bestEpsilon = 0
for epsilon in np.linspace(min(pval), max(pval), 1001):
y_predict = np.zeros(yval.shape)
y_predict[pval<epsilon] = 1 #把小于阈值的设为1
tp = np.sum(y_predict[yval==1]) #真正例
precision = tp/np.sum(y_predict) #查准率
recall = tp/np.sum(yval) #查全率
F1 = (2 * precision * recall) / (precision + recall)
if F1 > bestF1:
bestF1 = F1
bestEpsilon = epsilon
return bestEpsilon, bestF1
epsilon, F1 = selectThreshold(yval, pval) #(8.990852779269495e-05, 0.8750000000000001)
#找出异常点
outliers = np.array([x[i] for i in range(len(x)) if p[i] < epsilon]) #概率小于阈值记为异常点
#把异常点圈出来
plt.figure()
plt.scatter(outliers[:,0], outliers[:,1], s=100, marker='o', facecolors='none', edgecolors='r', linewidths=2)
visualizeFit(x, mu, sigma2)
'''============================part4 多维数据的异常检验========================='''
#导入数据
data = scio.loadmat('ex8data2.mat')
x = data['X'] #(1000, 11)
xval = data['Xval'] #(100, 11)
yval = data['yval']
#估计高斯分布的参数
mu, sigma2 = estimateGaussian(x)
#得到概率向量
p = multivariateGaussian(x, mu, sigma2)
#验证集的概率向量
pval = multivariateGaussian(xval, mu, sigma2)
#寻找最优阈值
epsilon, F1 = selectThreshold(yval, pval) #(1.377228890761358e-18, 0.6153846153846154)
#找出异常点
outliers = np.array([x[i] for i in range(len(x)) if p[i] < epsilon]) #概率小于阈值记为异常点
#输出结果
print('Best epsilon found using cross-validation: %e\n' %epsilon)
print('Best F1 on Cross Validation Set: %f\n' %F1)
print('# Outliers found: %d\n\n' %len(outliers))
样本集可视化结果
等概率曲线,这里给出了概率等高线的取值为10**h for h in range(-20,0,3)
圈出异常点,即概率小于阈值的那些点
多维数据的结果