前言

我在对地质学某些类型岩石的微量元素数据进行数据收集处理的时候,对异常数据进行筛选使用到了孤立森林,一开始没打算就此写这篇博客,不过就目前来说,我认为写这个博客有利于我后面的参考和记忆,遂以此记录,并且将会尽量将 sklearn 应用方面写更多的博客。

关于本篇的说明:

  • 使用的 Python 版本为 3.10.9(理论上你只要是 v3.0 以上就可以)
  • 在相关机器学习的文章中使用但是不限于如下的基本 Python 包,如果有使用其他包,将会在文章内容中做详细说明:

关于这个机器学习相关博客分类问题,我大概率后续会进行其他方式分类,目前都扔到机器学习分类中有些笼统。

孤立森林是什么?

隔离森林又名孤立森林,是一种从异常点出发,通过指定规则进行划分,根据划分次数进行判断的异常检测方法。 由周志华老师教授等人于2008年在第八届IEEE数据挖掘国际会议上提出。

内容来源:百度百科

孤立森林在有的地方会被翻译成孤点森林,不过孤立森林用的会比较多,简单来说孤立森林是用来对数据做异常检测的,它可以在大数据量的情况下,识别其中的异常数据,这样我们在进行机器学习的时候特征工程的时候就可以使用它来剔除相关异常点。

孤立森林的论文原文:**Liu F T, Ting K M, Zhou Z H. Isolation forest[C]//2008 eighth ieee international conference on data mining. IEEE, 2008: 413-422.**

孤立森林的原理

孤立森林因为是剔除异常点,所以对于“正常”的数据集来说,它们的值总是会在一个范围内波动,在可视化的空间呈现上来说是聚集的。而我们需要剔除的异常点则会是离散的,偏离这个聚集的范围的。

基于这个想法,孤立森林采用“切割数据集”的想法,来分隔数据集,进而根据分隔的大小来构造二叉树,根据值在二叉树的高度,计算每个点的异常值来判断这个点是不是异常值。可以通过如下图示来清楚的理解它的运行思路:

image-20230928171111967

可以在上图中看到,对于异常点来说,我们一次或者很少的次数就可以分隔出来,而聚集的点需要很多次分割才可以将它们分割出来。

孤立森林算法伪代码

该阶段的步骤如下:

  1. 从数据中随机选择个点作为子采样,放入树的根节点。
  2. 随机选择一个特征维度 q,在当前节点的数据中随机产生一个切割点 p(p的值域为当前节点数据中q的最小值和最大值之间)
  3. 以该切割点生成超平面,将当前节点数据空间划分成两个子空间:将在 q 上小于 p 的数据放于当前节点的左子节点,将大于等于 p 的数据放在当前节点的右子节点
  4. 在子节点中递归调用步骤(2)和(3),不断构造新的子节点,直到子节点中只有一个数据或已达到限定高度
  5. 循环(1)到(4),直到生成 t 棵 iTree
image-20230928171412119 image-20230928171434326 image-20230928171503114

孤立森林函数原型

1
2
3
4
5
6
7
8
9
10
sklearn.ensemble.IsolationForest(
*,
n_estimators=100,
max_samples='auto',
contamination='auto',
max_features=1.0,
bootstrap=False,
n_jobs=None,
random_state=None,
verbose=0, warm_start=False)

其中参数说明如下表所示:

参数 说明
n_estimators 指定森林中生成的随机树的数量,默认值为 100
max_samples 构建子树的样本数量,整数为个数,小数为占整个数据集的比例,用来训练随机数的样本数量,即:子采样的大小
如果设置的是auto,则max_samples=min(256, n_samples),n_samples即总样本的数量
contamination 取值范围为(0., 0.5),表示异常数据占给定的数据集的比例,默认为0.1
max_features 构建每个子树的特征数,整数位个数,小数为占全特征的比例,指定从总样本 X 中抽取来训练每棵树 iTree 的属性的数量,默认只使用一个属性
bootstrap 布尔类型,采样是有放回还是无放回,如果为True,则各个树可放回地对训练数据进行采样。如果为False,则执行不放回的采样。默认值为False
n_jobs 在运行fit()和predict()函数时并行运行的作业数量。除了在joblib.parallel_backend上下文的情况下,None表示为1。设置为-1则表示使用所有可用的处理器。默认值为None
random_state 每次训练的随机性。如果设置为int常数,则该random_state参数值是用于随机数生成器的种子。如果设置为RandomState实例,则该random_state就是一个随机数生成器。如果设置为None,该随机数生成器就是使用在np.random中的RandomState实例。默认值为None
verbose 训练中打印日志的详细程度,数值越大越详细。默认值为0
warm_start 当设置为True时,重用上一次调用的结果去fit,添加更多的树到上一次的森林1集合中;否则就fit一整个新的森林。默认值为False

可视化结果

使用plotly包来可视化我们的异常区分结果,代码示例:

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
import pandas as pd
from sklearn.ensemble import IsolationForest
import plotly.express as px

# 读取.xlsx文件
df = pd.read_excel('data.xlsx', sheet_name='我的数据工作簿')

# 获取第二列 La 数据
data = df.iloc[0:,1:]

# 模型训练
iforest = IsolationForest(n_estimators=100, max_samples='auto',
contamination=0.05, max_features=14,
bootstrap=False, n_jobs=-1)

# 异常预测
# tempData = iforest.fit_predict(data)

# fit_predict 函数 训练和预测一起 可以得到模型是否异常的判断,-1为异常,1为正常
df['label'] = iforest.fit_predict(data)

# 预测 decision_function 可以得出 异常评分
df['scores'] = iforest.decision_function(data)

# 输出结果
for index, value in enumerate(df['label']):
if(value == -1):
print(f"异常情况: {value}, 位置: {index + 1}")

# 可视化结果
df['anomaly'] = df['label'].apply(lambda x: 'outlier' if x==-1 else 'inlier')
fig = px.histogram(df,x='scores',color='anomaly')
fig.show()

注:上述代码仅做示例,内容部分如果使用请按照自己的实际情况修改

End

这个文章在一个礼拜前就已经开头了,但是由于一些事情耽搁了,现在终于补完了,不过目前来说,感谢研究生的生活有一些忙,也不会有本科博客的更新力度,不过我还是会尽力去更新。

image-20230928225751168

相关参考文章