吴恩达|机器学习作业8.0.异常检测

8.0.异常检测

1)题目:

在本练习中,您将实现异常检测算法,并将其应用于检测网络中的故障服务器。在第二部分中,您将使用协同过滤来构建电影推荐系统。
在本练习中,您将实现一个异常检测算法来检测服务器计算机中的异常行为。这些特性度量每个服务器的吞吐量(mb/s)和响应的延迟(ms)。在服务器运行时,您收集了m = 307个关于它们行为的样本,因此有一个未标记的数据集{x(1),…,x(m)}。您怀疑这些样本中的绝大多数都是正常运行的服务器的“正常”(非异常)样本,但是也可能有一些服务器在这个数据集中异常运行的样本。
您将使用高斯模型来检测数据集中的异常样本。您将首先从一个二维数据集开始,该数据集可以可视化算法在做什么。在该数据集上,您将拟合高斯分布,然后找到概率非常低的值,考虑为异常。之后,您将把异常检测算法应用于多维的较大数据集。
数据集链接: https://pan.baidu.com/s/1cEgQIvehUcLxZ0WVhxcPuQ 提取码: xejn

2)知识点概括:

  • 异常检测(anomaly detection)用数据集建立概率模型 p ( x ) p(x) ,如果新的测试数据在这个模型上小于某个阈值,则说它极大可能为异常点

  • 高斯分布/正态分布
    密度估计(density estimation)使用联合密度函数作为概率模型 p ( x ) p(x) ,这里其实是用到了每个特征是独立的,但是视频上说实际上不独立效果也差不多
    在这里插入图片描述

  • 划分训练集、验证集和测试集:
    假设有10000个反例和20个正例(y=1)
    选6000个反例作为无标签的训练集
    选2000个反例和10个正例作为训练集
    选2000个反例和10个正例作为测试集

  • 选择阈值 ϵ \epsilon 的方法:
    在验证集上尝试不同的阈值,选择那个能最大化F1值的那个阈值
    F1值是基于查准率 P = T P T P + F P P={TP\over TP+FP} 和查全率 R = T P T P + F N R={TP\over TP+FN} 的调和平均定义的 1 F 1 = 1 2 ( 1 P + 1 R ) {1\over F1}={1\over 2}\cdot({1\over P}+{1\over R}) ,因此 F 1 = 2 × P × R P + R = 2 × T P m + T P T N F1={2\times P\times R\over P+R}={2\times TP\over m+TP-TN} ,其中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)
在这里插入图片描述

圈出异常点,即概率小于阈值的那些点
在这里插入图片描述

多维数据的结果

发布了32 篇原创文章 · 获赞 33 · 访问量 6632

猜你喜欢

转载自blog.csdn.net/weixin_44750583/article/details/89404099