【机器学习 | 异常检测】孤立森林(isolation Forest)iForest 算法理论讲解及 Python 实战

04-26 1649阅读

文章目录

  • 一、原理
  • 二、具体流程
    • 2.1 训练森林
    • 2.2 首先要明确几个相关概念
    • 2.3 异常分数
    • 2.4 检测过程
    • 三、优缺点
      • 3.1 优点
      • 3.2 缺点
      • 四、代码实战
        • 4.1 准备数据
        • 4.2 模型
        • 4.3 可视化边缘

          一、原理

          孤立森林(Isolation Forest,简称 iForest)是一种无监督学习算法,用于识别异常值。

          其基本原理可以概括为一句话:异常数据由于数量较少且与正常数据差异较大,因此在被隔离时需要较少的步骤。

          有两个假设:

          • 异常的值是非常少的(如果异常值很多,可能被识别为正常的)
          • 异常值与其他值的差异较大(这点也可以引出主要是全局上都为异常的异常,局部小异常可能发现不了,因为差异并不大)

            二、具体流程

            2.1 训练森林

            1. 子采样: 首先从整个数据集中随机抽取一定数量的样本来为构建树做准备。这些抽样的子集大小通常远小于原始数据集的大小,这样可以限制树的大小,并且减少计算复杂度。
            2. 构建孤立树 (iTrees): 对于每个子采样集,算法构建一棵孤立树。构建孤立树的过程是递归的。在每个节点,算法随机选择一个特征,并在该特征的最大值和最小值之间随机选择一个分割值。然后,数据根据这个分割值将样本分到左子树或右子树(这里其实就是简单的将样本中特征小于这个分割点的样本分到左边,其次分到右边)。这个过程的结束条件:树达到限定的高度, 节点中的样本数量到一定的数目,或者所有样本的所选特征值都是同一个值。
            3. 森林构建: 重复1-2构建完特定数量的孤立树,集合为孤立森林。

            2.2 首先要明确几个相关概念

            1. 路径长度( h ( x ) h(x) h(x)): 指样本通过该孤立树构建阶段的特征选择方式,从树的根节点到达该样本被孤立的节点(被孤立就是意味着这个样本最终到达的树的叶子节点)所需要的边数。
            2. 平均路径长度 E ( h ( x ) ) E(h(x)) E(h(x)): 该样本在森林中所有树的路径长度的平均值。
            3. 树的平均路径长度:

              c ( n ) = 2 H ( n − 1 ) − 2 ( n − 1 ) n c(n)=2H(n-1)-\frac{2(n-1)}{n} c(n)=2H(n−1)−n2(n−1)​

              H ( i ) H(i) H(i) 是调和数,可以近似为 l n ( i ) + 0.5772156649 ln(i) + 0.5772156649 ln(i)+0.5772156649,其中 n n n 为样本个数,对于给定的数据集大小 n n n,平均路径长度的期望是一个常数,该公式提供了一个标准化的基准,用于将路径长度标准化。

            4. 异常分数:对于每个样本 x x x,其异常分数 s ( x , n ) s(x, n) s(x,n) 的计算公式如下:

              s ( x , n ) = 2 − E ( h ( x ) ) c ( n ) s(x, n) = 2^{-\frac{E(h(x))}{c(n)}} s(x,n)=2−c(n)E(h(x))​

              其中, E ( h ( x ) ) E(h(x)) E(h(x)) 是数据点 x x x 在所有树中路径长度的平均值, n n n 是训练数据的样本量, c ( n ) c(n) c(n) 是树的平均路径长度,用于标准化。

            2.3 异常分数

            score的范围为[0, 1]。

            1. E ( h ( x ) ) E(h(x)) E(h(x)) 约等于 c ( n ) c(n) c(n), 样本点的路径长度和平均路径长度没啥差别,看不出是否有异常;
            2. E ( h ( x ) ) E(h(x)) E(h(x)) 越靠近 0, score 越接近1, 说明样本很容易被孤立,更可能是异常的;
            3. E ( h ( x ) ) E(h(x)) E(h(x)) 的极端情况就是为样本的 n − 1 n - 1 n−1, 这时候 score 很小,不容易被孤立,也看不出是否为异常。

            2.4 检测过程

            1. 路径长度计算: 对于新的测试样本计算它们在每棵孤立树中的路径长度, 并算平均路径长度。
            2. 计算异常分数: 利用上述计算,孤立森林会计算每个数据点的异常分数。
            3. 判定异常: 根据计算出的异常分数,可以设置一个阈值来判定哪些数据点是异常的。

            三、优缺点

            3.1 优点

            1. 高效性: 孤立森林算法特别适合处理大数据集。它具有线性的时间复杂度,并且由于使用了子采样,使得在计算上更加高效。
            2. 易于并行化: 和随机森林一样,构建孤立树是独立的过程,构建森林可以并行化。

            3.2 缺点

            1. 异常值比例敏感性: 如果数据集中异常值的比例相对较高,孤立森林的效果可能就会下降,因为它是基于异常值“少而不同”的假设。
            2. 对局部异常检测不敏感:因为 少而不同的 前提条件决定主要解决全局异常的特点,对在局部区域表现出轻微异常特征的点检测不是很敏感。
            3. 不适用于多维特征情况:iforest不会因为特征的多少而降低算法的效率,但也正因为每次只随机用其中一个特征作为分割的特征,如果特征维度很高,就会有很多特征没有用到。

            四、代码实战

            4.1 准备数据

            import numpy as np
            import matplotlib.pyplot as plt
            from sklearn.model_selection import train_test_split
            n_samples, n_outliers = 120, 10
            rng = np.random.RandomState(0)
            cluster_1 = 0.4 * rng.randn(n_samples, 2) + np.array([2, 2])
            cluster_2 = 0.3 * rng.randn(n_samples, 2) + np.array([-2, -2])
            outliers = rng.uniform(low=-4, high=4, size=(n_outliers, 2))
            X = np.concatenate([cluster_1, cluster_2, outliers])
            y = np.concatenate(
                [np.ones((2 * n_samples), dtype=int), -np.ones(n_outliers, dtype=int)]
            )
            scatter = plt.scatter(X[:, 0], X[:, 1], c=y, s=20, edgecolor="k")
            handles, labels = scatter.legend_elements()
            plt.axis("square")
            plt.legend(handles=handles, labels=["outliers", "inliers"], )
            plt.title("data distribution")
            plt.show()
            

            【机器学习 | 异常检测】孤立森林(isolation Forest)iForest 算法理论讲解及 Python 实战

            4.2 模型

            # 通过y的比例进行均匀拆分
            X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)
            from sklearn.ensemble import IsolationForest
            clf = IsolationForest(max_samples=100, random_state=0)
            clf.fit(X_train)
            # 得到score,Negative scores represent outliers, positive scores represent inliers
            y_pre_score_test = clf.decision_function(cluster_1)
            print(y_pre_score_test)
            # -1为异常, 1为正常, 可以看下这个函数内部,就是score
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]