Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3.6. 异常检测实战

本文紧承 3.3. 异常检测(Anomaly Detection)理论,没看过的建议先看理论分析。

3.6.1. 实战前的准备工作

接下来,请你确保你的Python环境中有pandasmatplotlibscikit-learnnumpy这几个包,如果没有,请在终端输入指令以下载和安装:

pip install pandas matplotlib scikit-learn numpy scipy

我把数据放到了GitCode上,可以点击链接去下载和查看。文件一共有3栏:x1, x2和label,x1和x2是输入变量,label是标签,要么是0要么是1。如果是正常点就是1,否则就是0。

下载下来后把这个文件放到你的Python项目文件夹里即可。

3.6.2. 建立异常检测数据模型

Step 1: 读取数据

使用pandas库来读取.csv文件:

# 导入数据  
import pandas as pd  
data = pd.read_csv('error_detection_data.csv')  
  
print(data.head())

输出:

         x1        x2  label
0 -1.630353 -4.839381      1
1  4.995439  2.821713      1
2 -0.942488 -3.756172      1
3 -2.795116  2.975474      1
4  2.624829  1.159119      1

Step 2: 输入数据可视化

我们使用matplotlib来对输入的数据进行可视化:

# 可视化数据  
x1 = data.loc[:, 'x1']  
x2 = data.loc[:, 'x2']  
y = data.loc[:, 'label']  
  
  
import matplotlib.pyplot as plt  
plt.scatter(x1, x2, c=y)  
plt.show()

输出图片:

mat

可以很明显地看到,四角各有一个错误点。

不止如此,我们还可以使用hist方法来画数据的分布情况:

plt.hist(x1, bins=100, color='red')  
plt.hist(x2, bins=100, color='blue')  
plt.show()
  • bins这个参数用于控制生成的图有多少个区间,我填的100就会生成100个区间

输出图片:

hist

  • 红色是x1
  • 蓝色是x2

Step 3: 概率密度函数计算

为了查找异常点,我们得计算正态分布的概率密度函数。正态分布的公式是: $$ p(x) = \frac{1}{\sigma \sqrt{2\pi}} e^{-\frac{(x - \mu)^2}{2\sigma^2}} $$ 其中的参数只有两个:

  • $\mu$(均值,Mean):决定正态分布的中心位置,表示数据的平均值
  • $\sigma$(标准差,Standard Deviation):衡量数据的离散程度,决定正态分布的宽度,值越大,曲线越平缓;值越小,曲线越陡峭

我们得先计算这两个参数。幸运的是Python提供了函数,不需要我们手动写代码:

# 计算数据均值和标准差  
x1_mean = x1.mean()  
x2_mean = x2.mean()  
x1_std = x1.std()  
x2_std = x2.std()

然后使用scipy下的norm模块来计算高斯分布并用matplotlib画出来:

# 画正态分布  
from scipy.stats import norm  
import numpy as np  
x1_range = np.linspace(x1.min(), x1.max(), 100)  
normal1 = norm.pdf(x1_range, x1_mean, x1_std)  
x2_range = np.linspace(x2.min(), x2.max(), 100)  
normal2 = norm.pdf(x2_range, x2_mean, x2_std)  
  
import matplotlib.pyplot as plt  
  
# 绘制正态分布曲线  
plt.figure(figsize=(10, 5))  
  
# 第一条正态分布曲线  
plt.plot(x1_range, normal1, label='x1 Normal Distribution', color='blue')  
  
# 第二条正态分布曲线  
plt.plot(x2_range, normal2, label='x2 Normal Distribution', color='red')  
  
# 添加图例  
plt.legend()  
  
# 设置标题和标签  
plt.title("Gaussian Distribution of x1 and x2")  
plt.xlabel("Value")  
plt.ylabel("Probability Density")  
  
# 显示图像  
plt.show()
  • norm.pdf函数用于计算正态分布的概率密度函数,它的后两个参数就是均值和标准差,第一个参数是数据的x轴。所以我们需要使用np.linspace来创建一个数值序列作为x
  • np.linspace的第一个数据是x的最小值,代表数值序列开始的值;第二个数值是x的最大值,数值序列结束的值;最后一个参数用于控制要生成的数值个数

输出图片:

正态分布

Step 4: 训练异常检测模型

我们把sklearn下异常检测的模型导入进来,然后把数据喂给它:

# 训练异常检测模型  
x = data.drop('label', axis=1)  
from sklearn.covariance import EllipticEnvelope  
model = EllipticEnvelope()  
model.fit(x)

Step 5: 可视化预测出的错误点

# 可视化异常数据  
import matplotlib.pyplot as plt  
plt.scatter(x['x1'], x['x2'], c=model.predict(x))  
plt.show()

输出图片:

predict

Step 6: 计算正确率

EllipticEnvelope.predict 对正常点(inlier)返回 1,对异常点(outlier)返回 -1。评分前需要把 CSV 标签映射到这一约定:

# 计算正确率  
# CSV 标签:1 = 正常,0 = 异常 → sklearn:1 = inlier,-1 = outlier
y = data.loc[:, 'label'].replace({1: 1, 0: -1})
print(model.score(x, y))

若不做映射,把 predict 的结果(1/-1)直接和 CSV 标签(1/0)比较会低估正确率。映射之后,分数才反映预测的正常/异常是否与标签一致。