一. PyOD概览

1. 简介

PyOD 是一个全面的、可扩展的 Python 工具包,用于检测多变量数据中的异常对象,是当下最流行的Python异常检测工具库。

这一检测过程通常被称为离群点检测或异常检测

PyOD 库包含了超过 30 种异常检测算法,具体常用算法如下:

分类 缩写 全称
线性模式 PCA Principal Component Analysis
线性模型 MCD Minimum Covariance Determinant
线性模型 OCSVM One-Class Support Vector Machines
基于近邻 LOF Local Outlier Factor
基于近邻 kNN k Nearest Neighbors
基于近邻 HBOS Histogram-based Outlier Score
基于概率 ABOD Angle-Based Outlier Detection
异常集成 IForest Isolation Forest
异常集成 Feature Bagging

2. API与属性

以下函数均属于包 pyod.models.base.BaseDetector

  • fit(X): 用数据 X 来“训练/拟合”检测器 clf。( 在非监督学习中,不需要 y 值)

  • decision_function(X):可以通过该函数来预测未知数据的异常程度,返回值为原始分数,分数越高,异常程度越高。

  • predict(X): 可以通过该函数来预测未知数据的异常标签,返X回值为二分类标签(0为正常点,1为异常点)

  • predict_proba():在检测器clf被fit后,预测未知数据的异常概率,返回该点是异常点概率

  • fit_predict(X): 训练模型并且预测一个特殊的样本是否是异常值

  • fit_predict_score():训练检测器,预测位置数据的异常标签,并且根据预定义的度量标准评估模型的分数

  • decision_scores_:训练集的异常分数,分数越高表示异常程度越高.

  • labels_:0 表示正常值,1 表示异常值

二、具体算法

1. PCA

image-20200924092132102

简介

PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。PCA 的主要思想是将 n 维特征映射到 k 维上,这 k 维是全新的正交特征也被称为主成分,是在原有 n 维特征的基础上重新构造出来的 k 维特征。PCA 的工作就是从原始的空间中顺序地找一组相互正交的坐标轴,新的坐标轴的选择与数据本身是密切相关的。

其中,第一个新坐标轴选择是原始数据中方差最大的方向,第二个新坐标轴选取是与第一个坐标轴正交的平面中使得方差最大的,第三个轴是与第 1, 2 个轴正交的平面中方差最大的。依次类推,可以得到n个这样的坐标轴。通过这种方式获得的新的坐标轴,我们发现,大部分方差都包含在前面 k 个坐标轴中,后面的坐标轴所含的方差几乎为 0。于是,我们可以忽略余下的坐标轴,只保留前面 k 个含有绝大部分方差的坐标轴。事实上,这相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为 0 的特征维度,实现对数据特征的降维处理。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pyod.models.pca import PCA
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == "__main__":
contamination = 0.1 # 异常值占比
n_train = 200 # 训练集大小
n_test = 100 # 测试集大小

# 生产样本数据
X_train, X_test, y_train, y_test = \
generate_data(n_train=n_train,
n_test=n_test,
n_features=20,
contamination=contamination,
random_state=42,
behaviour="new")

# 训练 PCA 检测器
clf_name = 'PCA'
clf = PCA(n_components=3)
clf.fit(X_train)

# 获得训练集的预测标签和异常分数
y_train_pred = clf.labels_ # (0: 正常, 1: 异常)
y_train_scores = clf.decision_scores_

# 获得测试集的预测结果
y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# 评估并且打印结果
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

# 结果可视化
# 注意,为了实现可视化,原始维度必须是 2 维
# visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
# y_test_pred, show_figure=True, save_figure=False)

运行结果

image-20200924100919300

2. MCD

image-20200924101935248

简介

一种鲁棒性很强的位置和分布估计算法,并且可以通过FAST-MCD方法高效计算。

具体原理可参考:异常检测算法之-MCD(Minimum Covariance Determinant)

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pyod.models.mcd import MCD
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == "__main__":
contamination = 0.1 # 异常值占比
n_train = 200 # 训练集大小
n_test = 100 # 测试集大小

# 生产样本数据
X_train, X_test, y_train, y_test = \
generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42,
behaviour="new")

# 训练 MCD 检测器
clf_name = 'MCD'
clf = MCD()
clf.fit(X_train)

# 获得训练集的预测标签和异常分数
y_train_pred = clf.labels_ # (0: 正常, 1: 异常)
y_train_scores = clf.decision_scores_

# 获得测试集的预测结果
y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# 评估并且打印结果
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

# 结果可视化
visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=False)

运行结果

image-20200924102617552 image-20200924102750477

3. OCSVM

image-20200924102911438

简介

是对 sk-learn 中 one-class SVM 类的封装

详情可参考:Python机器学习笔记:One Class SVM

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pyod.models.ocsvm import OCSVM
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == "__main__":
contamination = 0.1 # 异常值占比
n_train = 200 # 训练集大小
n_test = 100 # 测试集大小


# 生产样本数据
X_train, X_test, y_train, y_test = \
generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42,
behaviour="new")

# 训练 OCSVM 检测器
clf_name = 'OCSVM'
clf = OCSVM()
clf.fit(X_train)

# 获得训练集的预测标签和异常分数
y_train_pred = clf.labels_ # (0: 正常, 1: 异常)
y_train_scores = clf.decision_scores_

# 获得测试集的预测结果
y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# 评估并且打印结果
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

# 结果可视化
visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=False)

运行结果

image-20200924164659935 image-20200924164726149

4. LOF

image-20200926113655703

简介

LOF(Local Outlier Factor),即局部异常因子算法,同样是对 sk-learn 中 LOF 类的封装

LOF 通过计算一个数值 score 来反映一个样本的异常程度。这个数值的大致意思是:一个样本点周围的样本点所处位置的平均密度比上该样本点所在位置的密度。比值比 1 越大,则该点所在位置的密度比其周围样本所在位置的密度越小,这个点就越有可能是异常点。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pyod.models.lof import LOF
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == "__main__":
contamination = 0.1 # 异常值占比
n_train = 200 # 训练集大小
n_test = 100 # 测试集大小


# 生产样本数据
X_train, X_test, y_train, y_test = \
generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42,
behaviour="new")

# 训练 LOF 检测器
clf_name = 'LOF'
clf = LOF()
clf.fit(X_train)

# 获得训练集的预测标签和异常分数
y_train_pred = clf.labels_ # (0: 正常, 1: 异常)
y_train_scores = clf.decision_scores_

# 获得测试集的预测结果
y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# 评估并且打印结果
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

# 结果可视化
visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=False)

运行结果

image-20200926115949002 image-20200926120007794

5. kNN

image-20200927081652658

简介

kNN(K-NearestNeighbor),即 K 近邻算法,是一种基本的有监督式分类和回归算法

K 近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分类到这个类中。

image-20200927082708545

如图,要将绿色原点归类:

  1. K <= 3 :红色三角形
  2. K > 3:蓝色方块

在实际使用中,K 值的选取既不能过大,也不能过小

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pyod.models.knn import KNN
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == '__main__':
contamination = 0.1
n_train = 200
n_test = 100

X_train, y_train, X_test, y_test = generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42)

clf_name = 'KNN'
clf = KNN()
clf.fit(X_train)

y_train_pred = clf.labels_
y_train_scores = clf.decision_scores_

y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# evaluate and print the results
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=True)

运行结果

image-20200927083506477 image-20200927083444614

6. HBOS

image-20200927091752222

简介

HBOS(Histogram-based outlier score),即基于直方图的异常检测算法。

它假设每个维度独立并在每个维度上划分 n 个区间,每个区间所对应的异常值取决于密度。密度越高,异常值越低,因此也可以看成是一种假设维度独立的密度检测。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pyod.models.hbos import HBOS
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == '__main__':
contamination = 0.1
n_train = 200
n_test = 100

X_train, y_train, X_test, y_test = generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42)

clf_name = 'HBOS'
clf = HBOS()
clf.fit(X_train)

y_train_pred = clf.labels_
y_train_scores = clf.decision_scores_

y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# evaluate and print the results
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=True)

运行结果

image-20200927092426760 image-20200927092459169

7. ABOD

image-20200927093058529

简介

ABOD(Angle-base Outlier Detection),在该算法中,对于一个样本,它的加权余弦分数对所有邻居的方差可以作为离群分数。

高维空间中,角度比距离更具有可参考性(维度灾难):

  • O 点为离群点,则其他点在 O 点的同一方向
  • O 点不是离群点,则其他点在 O 点的各个方向
image-20200927093752466

给定一点 P,它与全体样本中的任意两点 x、y 所成角度的构成下图:

image-20200927094853516

可知所成角度的绝对值越小则该点越有可能为离群点,也就是说图像中红点数据代表离群点而蓝点数据代表正常点

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pyod.models.abod import ABOD
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == '__main__':
contamination = 0.1
n_train = 200
n_test = 100

X_train, y_train, X_test, y_test = generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42)

clf_name = 'ABOD'
clf = ABOD()
clf.fit(X_train)

y_train_pred = clf.labels_
y_train_scores = clf.decision_scores_

y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# evaluate and print the results
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=True)

运行结果

image-20200927095418659 image-20200927095516422

8. IForest

image-20200927095714193

简介

pyod.models.iforest.IForest 是对 sk-learn 中 Isolation Forest 的封装。

类似于RandomForest,IsolationForest 通过随机选择一个特征,然后在所选特征的最大值和最小值之间随机选择一个分割值来隔离观察结果。

由于递归分区可以用树结构来表示,因此分离一个样本所需的分裂次数等于从根节点到终止节点的路径长度。这条路径的长度,在这些随机树的森林上的平均值,是一种正态性的度量,也是我们的决策函数。随机分区为异常的值生成明显更短的路径

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pyod.models.iforest import IForest
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == '__main__':
contamination = 0.1
n_train = 200
n_test = 100

X_train, y_train, X_test, y_test = generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42)

clf_name = 'IForest'
clf = IForest()
clf.fit(X_train)

y_train_pred = clf.labels_
y_train_scores = clf.decision_scores_

y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# evaluate and print the results
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=True)

运行结果

image-20200927101132163 image-20200927101156937

9. feature_bagging

image-20200927105513335

简介

Feature bagging 检测器是一种 元估计器(meta estimator),它在数据集的各个子样本上匹配大量的基础检测器(base detectors),并使用平均或其他组合方法来提高预测精度和控制过拟合。子样本的大小始终与原始输入样本的大小相同,但特征是从一半的特征随机抽样到全部特征。默认情况下,LOF用作基础估计器。但是,任何估计器都可以用作基础估计器,如 kNN 和 ABOD。

Feature bagging 首先通过随机选择特征子集来构造 n 个子样本,这会引起基本估计量的多样性。 最后,通过平均/取所有基本检测器的最大值来生成预测分数。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from pyod.models.feature_bagging import FeatureBagging
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

if __name__ == '__main__':
contamination = 0.1
n_train = 200
n_test = 100

X_train, y_train, X_test, y_test = generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42)

clf_name = 'FeatureBagging'
clf = FeatureBagging(check_estimator=False)
clf.fit(X_train)

y_train_pred = clf.labels_
y_train_scores = clf.decision_scores_

y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

# evaluate and print the results
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=True)

运行结果

image-20200927110718875 image-20200927110700780

参考