吴恩达机器学习作业8(上)--- Anomaly Detection(异常检测)

代码分析

前言

异常检测模型分为原始模型和多元高斯分布模型

原始模型为多元高斯分布模型的特例

其区别是

  • 原始模型的协方差矩阵为对角矩阵,其特征相互独立
  • 多元高斯分布模型的特征存在相关性

实现高斯分布函数

首先导入类库

import numpy as np
import matplotlib.pyplot as plt
import scipy.io 
import scipy.optimize #Use for fmincg
%matplotlib inline

导入数据,有训练集(无标签),交叉验证集(有标签)

datafile = 'data/ex8data1.mat'
mat = scipy.io.loadmat( datafile )
#训练集,无标签
X = mat['X']
#交叉验证集,有标签
ycv = mat['yval']
Xcv = mat['Xval']

可视化函数

# Visualize the data
def plotData(myX, newFig=False):
    if newFig:
        plt.figure(figsize=(8,6))
    plt.plot(myX[:,0],myX[:,1],'b+')
    plt.xlabel('Latency [ms]',fontsize=16)
    plt.ylabel('Throughput [mb/s]',fontsize=16)
    plt.grid(True)
    
plotData(X)

在这里插入图片描述
下图为多元高斯分布函数
在这里插入图片描述
实现高斯分布函数(兼容单变量和多变量)

#此函数得出p方程,兼容原始模型和多元高斯分布模型
def gaus(myX, mymu, mysig2):
    m = myX.shape[0]#数据集个数
    n = myX.shape[1]#特征数
    #如果sigma是向量,就转化为对角矩阵(协方差矩阵)
    if np.ndim(mysig2) == 1:
        mysig2 = np.diag(mysig2)
    #计算常数项
    norm = 1./(np.power((2*np.pi), n/2)*np.sqrt(np.linalg.det(mysig2)))
    myinv = np.linalg.inv(mysig2)#sigma取逆
    myexp = np.zeros((m,1))
    for irow in range(m):#这里使用for-loop遍历数据集,因为找不到向量化的方法
        xrow = myX[irow]
        myexp[irow] = np.exp(-0.5*((xrow-mymu).T).dot(myinv).dot(xrow-mymu))
    return norm*myexp

估计高斯分布的参数

下图为高斯分布参数的计算公式(x为向量)
在这里插入图片描述
由训练集拟合出参数μ和σ^2

def getGaussianParams(myX,useMultivariate = True):
    m = myX.shape[0]#数据集个数
    mu = np.mean(myX,axis=0)#计算μ
    #计算σ
    if not useMultivariate:
        sigma2 = np.sum(np.square(myX-mu),axis=0)/float(m)
        return mu, sigma2
    else:
        sigma2 = ((myX-mu).T.dot(myX-mu))/float(m)
        return mu, sigma2

好了,我们实现了高斯分布函数gaus,并且实现了可以根据数据集计算高斯分布的参数的函数getGaussianParams

我们可以画出高斯分布模型的等高线图

#打印等高线图
def plotContours(mymu, mysigma2, newFig=False, useMultivariate = True):
    delta = .5
    myx = np.arange(0,30,delta)
    myy = np.arange(0,30,delta)
    meshx, meshy = np.meshgrid(myx, myy)
    
    #将meshx,meshy(60x60)展开为(3600)并转化为list
    coord_list = [ entry.ravel() for entry in (meshx, meshy) ]
    points = np.vstack(coord_list).T#堆叠起来
    
    myz = gaus(points, mymu, mysigma2)
    #if not useMultivariate:
    #    myz = gausOrthog(points, mymu, mysigma2)
    #else: myz = gausMV(points, mymu, mysigma2)
    myz = myz.reshape((myx.shape[0],myx.shape[0]))

    if newFig: 
        plt.figure(figsize=(6,4))#新图像
    
    cont_levels = [10**exp for exp in range(-20,0,3)]
    mycont = plt.contour(meshx, meshy, myz, levels=cont_levels)

    plt.title('Gaussian Contours',fontsize=16)

测试

# 不使用多元高斯分布模型
plotData(X, newFig=True)
useMV = False
plotContours(*getGaussianParams(X, useMV), newFig=False, useMultivariate = useMV)

# 使用多元高斯分布模型
plotData(X, newFig=True)
useMV = True
plotContours(*getGaussianParams(X, useMV), newFig=False, useMultivariate = useMV)

在这里插入图片描述
在这里插入图片描述
可以观察到多元高斯分布模型的等高线稍微倾斜,这是因为特征Latency和特征Throughput具有相关性

选择阈值ε

当然,作为异常检测模型,我们当然需要寻找一个阈值ε,作为判断样本点是否异常的标准

那么,如何找到使异常检测算法准确率最高的阈值ε呢?,由于我们的数据是十分倾斜的,不能使用准确率来衡量算法的好坏,于是我们采用F1-score来衡量算法的好坏

prec为Precision,rec为Recall
在这里插入图片描述
这是计算F1-score的函数

#计算F1-score
def computeF1(predVec, trueVec) 
    P, R = 0., 0.#Precision,Recall
    if float(np.sum(predVec)):
        P = np.sum([int(trueVec[x]) for x in range(predVec.shape[0]) if predVec[x]]) / float(np.sum(predVec))
    if float(np.sum(trueVec)):
        R = np.sum([int(predVec[x]) for x in range(trueVec.shape[0]) if trueVec[x]]) / float(np.sum(trueVec))
        
    return 2*P*R/(P+R) if (P+R) else 0
    

这是选择阈值的函数

def selectThreshold(myycv, mypCVs):
    # 列出可能的epsilon值
    nsteps = 1000#待比较ε个数
    epses = np.linspace(np.min(mypCVs),np.max(mypCVs),nsteps)#可能值
    
    bestF1, bestEps = 0, 0
    
    trueVec = myycv.flatten()
    
    for eps in epses:#遍历所有可能的ε,寻找F1最大的作为最终结果
    	#mypCVs是数据集通过gaus函数计算出的probability值
        predVec = mypCVs < eps#预测是否异常 y=0/y=1
        thisF1 = computeF1(predVec, trueVec)#计算F1
        if thisF1 > bestF1:
            bestF1 = thisF1
            bestEps = eps
            
    print("Best F1 is %f, best eps is %0.4g."%(bestF1,bestEps))
    return bestF1, bestEps
        

测试

#利用gaus函数来计算cv集的probability值
pCVs = gaus(Xcv, mu, sig2)

#You should see a value for epsilon of about 8.99e-05.
#比较出最佳阈值
bestF1, bestEps = selectThreshold(ycv,pCVs)

输出:Best F1 is 0.875000, best eps is 9.075e-05.

标记出异常点

def plotAnomalies(myX, mybestEps, newFig = False, useMultivariate = True):
    #计算gaus分布的概率值
    ps = gaus(myX, *getGaussianParams(myX, useMultivariate))
    #选择出异常点
    anoms = np.array([myX[x] for x in range(myX.shape[0]) if ps[x] < mybestEps])
    if newFig: 
        plt.figure(figsize=(6,4))
    plt.scatter(anoms[:,0],anoms[:,1], s=80, facecolors='none', edgecolors='r')
plotData(X, newFig=True)
plotContours(mu, sig2, newFig=False, useMultivariate=True)
plotAnomalies(X, bestEps, newFig=False, useMultivariate=True)

在这里插入图片描述

高维数据集测试

导入数据

#导入数据
datafile = 'data/ex8data2.mat'
mat = scipy.io.loadmat( datafile )
Xpart2 = mat['X']
ycvpart2 = mat['yval']
Xcvpart2 = mat['Xval']
print('Xpart2 shape is ', Xpart2.shape)

测试

#计算出参数μ和Σ
mu, sig2 = getGaussianParams(Xpart2, useMultivariate=False)
#计算每个数据的gaus值
ps = gaus(Xpart2, mu, sig2)


#计算cv数据集的gaus值
psCV = gaus(Xcvpart2, mu, sig2)
#寻找最好的ε
bestF1, bestEps = selectThreshold(ycvpart2,psCV)


#寻找出异常点
anoms = [Xpart2[x] for x in range(Xpart2.shape[0]) if ps[x] < bestEps]
print('# of anomalies found: ',len(anoms))

输出:Best F1 is 0.615385, best eps is 1.379e-18.
#of anomalies found: 117

数据集

ex8data1.mat
ex8data2.mat
这里偷个懒,数据集可以上kaggle查

猜你喜欢

转载自blog.csdn.net/NP_hard/article/details/114105503