首页 > 其他 > 详细

异常检测(3)——基于概率统计的异常检测(2)

时间:2019-09-03 18:55:18      阅读:99      评论:0      收藏:0      [点我收藏+]

  书接上文,继续讨论基于多元正态分布的异常检测算法。

  

  现在有一个包含了m个数据的训练集,其中的每个样本都是一个n维数据:

技术分享图片

  可以通过下面的函数判断一个样本是否是异常的:

技术分享图片

  我们的目的是设法根据训练集求得μσ,以得到一个确定的多元分正态布模型。具体来说,通过最大似然估计量可以得出下面的结论:

技术分享图片

  其中Σ是协方差对角矩阵,最终求得的多元正态分布模型可以写成:

技术分享图片

  关于最大似然估计量、协方差矩阵和多元正态分布最大似然估计的具体推导过程,可参考:

  概率笔记12——多维正态分布的最大似然估计

  概率笔记10——矩估计和最大似然

 

 

  代码:

  1 import numpy as np
  2 import matplotlib.pyplot as plt
  3 from mpl_toolkits.mplot3d import Axes3D
  4
  5 def create_data(model=train, count=200):
  6     ‘‘‘
  7     构造2维训练集
  8     :param model: train:训练集,  test:测试集
  9     :param count: 样本数量
 10     :return: X1:第1纬度的列, X2:第2维度的列表
 11     ‘‘‘
 12     np.random.seed(21)  # 设置seed使每次生成的随机数都相等
 13     X1 = np.random.normal(1.7, 0.036, count)  # 生成200个符合正态分布的身高数据
 14     low, high = -0.01, 0.01
 15     if model == test:
 16         low, high = -0.05, 0.05
 17     # 设置身高对应的鞋码,正常鞋码=身高/7±0.01
 18     X2 = X1 / 7 + np.random.uniform(low=low, high=high, size=len(X1))
 19     return X1, X2
 20
 21 def plot_train(X1, X2):
 22     ‘‘‘
 23     可视化训练集
 24     :param X1: 训练集的第1维度
 25     :param X2: 训练集的第2维度
 26     ‘‘‘
 27     fig = plt.figure(figsize=(10, 4))
 28     plt.subplots_adjust(hspace=0.5)  # 调整子图之间的上下边距
 29     # 数据的散点图
 30     fig.add_subplot(2, 1, 1)
 31     plt.scatter(X1, X2, color=k, s=3., label=训练数据)
 32     plt.legend(loc=upper left)
 33     plt.xlabel(身高)
 34     plt.ylabel(脚长)
 35     plt.title(数据分布)
 36     # 身高维度的直方图
 37     fig.add_subplot(2, 2, 3)
 38     plt.hist(X1, bins=40)
 39     plt.xlabel(身高)
 40     plt.ylabel(频度)
 41     plt.title(身高直方图)
 42     # 脚长维度的直方图
 43     fig.add_subplot(2, 2, 4)
 44     plt.hist(X2, bins=40)
 45     plt.xlabel(脚长)
 46     plt.ylabel(频度)
 47     plt.title(脚长直方图)
 48
 49     plt.rcParams[font.sans-serif] = [SimHei]  # 用来正常显示中文标签
 50     plt.rcParams[axes.unicode_minus] = False  # 解决中文下的坐标轴负号显示问题
 51     plt.show()
 52
 53 def fit(X_train):
 54     ‘‘‘
 55     拟合数据,训练模型
 56     :param X_train: 训练集
 57     :return:  mu:均值, sigma:方差
 58     ‘‘‘
 59     global mu, sigma
 60     X = np.mat(X_train.T)
 61     m, n = X.shape
 62     mu = np.mean(X, axis=1)  # 计算均值μ,axis=1表示对每一个子数组计算均值
 63     sigma = np.mat(np.cov(X)) # 计算Σ,等同于(X - mu) * (X - mu).T / len(X_train)
 64
 65 def gaussian(X_test):
 66     ‘‘‘
 67     计算正态分布
 68     :param X_test: 测试集
 69     :return: 数据集的密度值
 70     ‘‘‘
 71     global mu, sigma
 72     m, n = np.shape(X_test)
 73     sig_det = np.linalg.det(sigma)  # 计算det(Σ)
 74     sig_inv = np.linalg.inv(sigma)  # Σ的逆矩阵
 75     r = []
 76     for x in X_test:
 77         x = np.mat(x).T - mu
 78         g = np.exp(-x.T * sig_inv * x / 2) *  ((2 * np.pi) ** (-n / 2) * (sig_det ** (-0.5)))
 79         r.append(g[0, 0])
 80     return r
 81
 82 def sel_epsilon(X_train):
 83     ‘‘‘
 84     选择合适的ε
 85     :param X_train:
 86     :return: ε
 87     ‘‘‘
 88     g_val = gaussian(X_train)
 89     return np.min(g_val) + 0.0001
 90
 91 def predict(X):
 92     ‘‘‘
 93     检测训练集中的数据是否是正常数据
 94     :param X: 待预测的数据
 95     :return: P1:数据的密度值, P2:数据的异常检测结果,True正常,False异常
 96     ‘‘‘
 97     P1 = gaussian(X) # 数据的密度值
 98     P2 = [p > epsilon for p in P1] # 数据的异常检测结果,True正常,False异常
 99     return P1, P2
100
101 def plot_predict(X):
102     ‘‘‘可视化异常检测结果 ‘‘‘
103     P1, P2 = predict(X)
104     normals_idx = [i for i, t in enumerate(P2) if t == True]  # 正常数据的索引
105     outliers_idx = [i for i, t in enumerate(P2) if t == False]  # 异常数据的索引
106     normals_x = np.array([X[i] for i in normals_idx])  # 正常数据
107     outliers_x =  np.array([X[i] for i in outliers_idx])  # 异常数据
108
109     fig1 = plt.figure(num=fig1) # 散点图
110     ax = Axes3D(fig1)
111     ax.scatter(normals_x[:,0], normals_x[:,1],
112                [P1[i] for i in normals_idx], label=正常数据)
113     ax.scatter(outliers_x[:,0], outliers_x[:,1],
114                [P1[i] for i in outliers_idx], c=r, marker=^, label=异常数据)
115     ax.set_title(共有{}个异常数据.format(len(outliers_idx)))
116     ax.axis(tight)  # 让坐标轴的比例尺适应数据量
117     ax.set_xlabel(身高)
118     ax.set_ylabel(脚长)
119     ax.set_zlabel(p(x))
120     ax.legend(loc=upper left)
121
122     n = 100
123     xs, ys = np.meshgrid(np.linspace(min(X1_train), max(X1_train), n),
124                          np.linspace(min(X2_train), max(X2_train), n))
125     zs = [gaussian(np.c_[xs[i], ys[i]]) for i in range(n)]
126
127     fig2 = plt.figure(num=fig2)
128     ax = Axes3D(fig2)
129     # 3维空间的拟合曲面
130     ax.plot_surface(xs, ys, zs, alpha=0.5, cmap=plt.get_cmap(rainbow))
131     ax.scatter(normals_x[:, 0], normals_x[:, 1],
132                [P1[i] for i in normals_idx], label=正常数据)
133     ax.scatter(outliers_x[:, 0], outliers_x[:, 1],
134                [P1[i] for i in outliers_idx], c=r, marker=^, label=异常数据)
135     ax.axis(tight)  # 让坐标轴的比例尺适应数据量
136     ax.set_xlabel(身高)
137     ax.set_ylabel(脚长)
138     ax.set_zlabel(p(x))
139     ax.legend(loc=upper left)
140
141     fig3 = plt.figure(num=fig3)
142     plt.scatter(normals_x[:, 0], normals_x[:, 1], s=30., c=k, label=正常数据)
143     plt.scatter(outliers_x[:, 0], outliers_x[:, 1], c=r, marker=^, s=30., label=异常数据)
144     plt.contour(xs, ys, zs, 80, alpha=0.5) # 等高线
145     plt.axis(tight)  # 让坐标轴的比例尺适应数据量
146     plt.xlabel(身高)
147     plt.ylabel(脚长)
148     plt.legend(loc=upper left)
149
150     plt.rcParams[font.sans-serif] = [SimHei]  # 用来正常显示中文标签
151     plt.rcParams[axes.unicode_minus] = False  # 解决中文下的坐标轴负号显示问题
152     plt.show()
153
154 if __name__ == __main__:
155     X1_train, X2_train = create_data()
156     plot_train(X1_train, X2_train)
157
158     X_train = np.c_[X1_train, X2_train]
159     mu, sigma = np.mat([]), np.mat([])
160     fit(X_train)
161     epsilon = sel_epsilon(X_train)
162
163     X_test = np.c_[create_data(model=test, count=20)]
164     X = np.r_[X_train, X_test]
165     plot_predict(X)

  为了简单起见,我们认为X_train 中的数据全部是正常数据。fit(X_train)计算多元正态分布的模型参数,gaussian(X_test)根据目标函数计算样本的多元正态分布密度值。在知道了算法原理的请看下,fit(X_train)和gaussian(X_test)都毫无神秘性可言。

  predict(X)将对X中的所有样本进行检测,并返回X对应的检测结果列表,列表中的元素是一个二元组,第一个元素记录x(i)是否是正常数据,第二个元素记录p(x(i);μ,Σ)。由于已经假设了X_train中全部是正常数据,因此这里选择X_train中最小的密度值作为ε。

  X_test中的20个测试数据是可能的异常样本。plot_predict(X)展示了空间样本点、空间拟合曲面和等高线:

技术分享图片

  

技术分享图片

  

技术分享图片


  作者:我是8位的

  出处:http://www.cnblogs.com/bigmonkey

  本文以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,非商业用途! 

  扫描二维码关注公作者众号“我是8位的”

技术分享图片

异常检测(3)——基于概率统计的异常检测(2)

原文:https://www.cnblogs.com/bigmonkey/p/11454586.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!