计算机系统应用教程网站

网站首页 > 技术文章 正文

孤立森林(Isolation Forest)的异常检测及Python示例

btikc 2024-10-11 11:20:39 技术文章 3 ℃ 0 评论

在最近的一个项目中,我研究了一个手机应用用户的数据聚类问题。目标是根据用户的行为对他们进行分类,有可能使用K-means聚类。然而,在检查数据之后,发现一些用户表现出异常行为——他们是异常值。

许多机器学习算法在不考虑离群值时,其性能会受到影响。为了避免此类问题,例如,您可以将它们从您的示例中删除,在一些合理的点(基于领域知识的基础上)限制值,或者转换数据。然而,在本文中,我想集中精力识别它们。

理想情况下,我希望有一个算法来识别多维空间中的异常值,原则上类似于随机森林。在本文中,我将集中讨论孤立森林,而不详细描述决策树和集合背后的思想,因为已经有大量可用的好资源。

一些理论

与其他流行的异常值检测方法不同的主要思想是,孤立森林明确识别异常而不是分析正常数据点。与任何树集成方法一样,孤立森林建立在决策树的基础之上。在这些树中,通过首先随机选择特征然后在所选特征的最小值和最大值之间选择随机分割值来创建分区。

原则上,异常值不如常规观测值频繁,并且在值方面不同于它们(它们远离特征空间中的常规观测值)。这就是为什么通过使用这样的随机分区,它们应该被识别为更接近树的根(较短的平均路径长度,即观察必须在树中从根到终端节点传递的边数)。

在图1中可以观察到识别正常与异常观察的想法。正常点(左侧)需要识别比异常点(右侧)更多的分区。

与其他离群值检测方法一样,决策需要一个异常值。对于孤立森林,定义为:

其中h(x)为观测x的路径长度,c(n)为二叉搜索树中未成功搜索的平均路径长度,n为外部节点个数。

每个观测结果都有一个异常值,可以根据它做出以下决定:

  • 分数接近1表示异常
  • 得分远小于0.5表示正常观察
  • 如果所有分数接近0.5,则整个样本似乎没有明显不同的异常

Python示例

好的,现在让我们看一个手动的例子。为了简单起见,我将研究一个人工的二维数据集。通过这种方式,我们可以监控绘图中的离群值识别过程。

首先,我需要生成观察结果。我将从观察开始,这些观察将被认为是正常的,并将用于训练模型(在Python的scikit-learn实现中的训练和评分与其他所有机器学习算法类似)。第二组是新的观察,来自于训练的相同分布。最后,生成离群值。

# importing libaries ----

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from pylab import savefig

from sklearn.ensemble import IsolationForest

# Generating data ----

rng = np.random.RandomState(42)

# Generating training data

X_train = 0.2 * rng.randn(1000, 2)

X_train = np.r_[X_train + 3, X_train]

X_train = pd.DataFrame(X_train, columns = ['x1', 'x2'])

# Generating new, 'normal' observation

X_test = 0.2 * rng.randn(200, 2)

X_test = np.r_[X_test + 3, X_test]

X_test = pd.DataFrame(X_test, columns = ['x1', 'x2'])

# Generating outliers

X_outliers = rng.uniform(low=-1, high=5, size=(50, 2))

X_outliers = pd.DataFrame(X_outliers, columns = ['x1', 'x2'])

图2显示了生成的数据集。正如预期的那样,训练和“正常”观察基本上是叠加在一起的,而离群值则分散开来。由于异常值的随机性,有些异常值与训练/正常观测值重叠,但我将稍后对此进行说明。

现在我需要在训练集中训练孤立森林。我在这里使用默认设置。值得注意的一点是contamination参数,它指定了我们认为是异常值的观察百分比(scikit-learn的默认值是0.1)。

# Isolation Forest ----

# training the model

clf = IsolationForest(max_samples=100, random_state=rng)

clf.fit(X_train)

# predictions

y_pred_train = clf.predict(X_train)

y_pred_test = clf.predict(X_test)

y_pred_outliers = clf.predict(X_outliers)

现在我们有了预测。如何评估性能?我们知道,测试集只包含与正常观测相同分布的观测。所以,所有的测试集观察都应该被归类为正常的。让我们来看看精度。

# new, 'normal' observations ----

print("Accuracy:", list(y_pred_test).count(1)/y_pred_test.shape[0])

# Accuracy: 0.93

# outliers ----

print("Accuracy:", list(y_pred_outliers).count(-1)/y_pred_outliers.shape[0])

# Accuracy: 0.96

一开始这看起来很不错,特别是考虑到默认设置,但是还有一个问题需要考虑。由于离群值数据是随机生成的,一些离群值实际上位于正常观测范围内。为了更仔细地检查,我将把正常观测数据集与标记的离群值集一起绘制出来。我们可以看到,在正常观测集中的一些离群值被正确地归类为常规观测,其中一些被错误地归类。我们所能做的是尝试不同的参数规格(contamination, number of estimators、抽取样本的数量等)以获得更好的适应。但就目前而言,这些结果令人满意。

总结:

  • 孤立森林是一种离群检测技术,它识别异常而不是正常的观测。
  • 类似于随机森林,它是建立在一个二元(Isolation)树的集合上
  • 它可以放大以处理大的、高维的数据集

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表