常用异常检测算法总结与代码实现[统计学方法/K近邻/孤立森林/DBSCAN/LOF/混合高斯GMM/自编码器AutoEncoder等]

这篇博文主要是延续前文系列的总结记录,这里主要是总结汇总日常主流的异常检测算法相关知识内容。

 (1)基于统计方法的异常值检测

基于统计方法的异常值检测是一种常用的异常检测算法,它基于样本数据的统计特性来识别与其他样本显著不同的观测值。下面将详细介绍其算法原理,并分析其优点和缺点。
算法原理:
基于概率分布的方法:假设样本数据服从某个概率分布,例如正态分布。通过计算每个样本的概率密度或累积分布函数(CDF),可以确定样本的异常程度。根据阈值或比例判断异常样本。
基于距离的方法:通过计算每个样本与其他样本之间的距离或相似性指标,如欧氏距离、马哈拉诺比斯距离等。根据阈值或百分位数判断异常样本,距离较远的样本被认为是异常值。
基于箱线图的方法:使用统计学中的箱线图来识别异常值。通过计算样本的四分位数和内限后,将超出内限的样本视为异常值。
优点:
简单直观:基于统计方法的异常值检测算法通常易于理解和实现,不需要过多的复杂计算。
泛化能力强:该方法适用于多种数据类型和分布,可以用于不同领域的异常检测问题。
不依赖标签:相比于监督学习的异常检测方法,统计方法无需依赖已知的正常样本标签,因此更适用于无监督或半监督场景。
缺点:
假设数据服从某个特定概率分布:基于概率分布的方法假设数据服从某个概率分布,但实际数据可能并不完全符合这种假设。如果数据的实际分布与假设的分布不一致,可能会导致误判异常值的情况。
对噪声敏感:统计方法在处理包含大量噪声的数据时,可能会将噪声误判为异常值,从而影响准确性。
依赖参数选择:统计方法通常需要设置阈值或其他参数来判断异常值,选择合适的参数对算法的性能影响较大,需要经验或试验来确定。
总结:
基于统计方法的异常值检测是一种简单直观、适用广泛且不依赖标签的异常检测算法。它通过利用样本数据的统计特性来识别异常值。然而,该方法的缺点在于对数据分布的假设、对噪声的敏感性以及参数选择的依赖。在实际应用中,需要根据具体问题和数据特点来选择合适的统计方法,并进行参数调优和结果验证,以提高异常检测的准确性和鲁棒性。

Demo代码实现如下所示:

import numpy as np
import pandas as pd


"""
在下述代码中,我们定义了三个函数分别实现了基于概率分布的方法(Z-score),基于距离的方法(密度离群因子 - DFF)和基于箱线图的方法。

detect_outliers_zscore 函数使用 Z 分数(Z-score)来度量每个数据点与均值之间的偏离程度,超过阈值的数据点被判定为异常值。
detect_outliers_distance 函数使用密度离群因子(DFF)来度量每个数据点与中位数之间的距离,超过阈值的数据点被判定为异常值。
detect_outliers_boxplot 函数使用箱线图的方法来判断异常值,根据四分位距离(IQR)和乘法因子,将超过上下界的数据点判定为异常值。
在示例中,数据为 [1, 2, 3, 10, 20, 30, 100],将使用每种方法进行异常值检测,并输出对应的异常值索引。你可以根据自己的输入数据和需求来调用相应的函数进行测试。
"""


# 基于概率分布的方法 (Z-score)
def detect_outliers_zscore(data, threshold=3):
    mean = np.mean(data)
    std = np.std(data)
    z_scores = np.abs((data - mean) / std)
    outliers = np.where(z_scores > threshold)[0]
    return outliers

# 基于距离的方法 (密度离群因子 - DFF)
def detect_outliers_distance(data, threshold=1.5):
    median = np.median(data)
    mad = np.median(np.abs(data - median))
    dff = np.abs(0.6745 * (data - median) / mad)
    outliers = np.where(dff > threshold)[0]
    return outliers

# 基于箱线图的方法
def detect_outliers_boxplot(data, multiplier=1.5):
    q1 = np.percentile(data, 25)
    q3 = np.percentile(data, 75)
    iqr = q3 - q1
    lower_bound = q1 - multiplier * iqr
    upper_bound = q3 + multiplier * iqr
    outliers = np.where((data < lower_bound) | (data > upper_bound))[0]
    return outliers

# 示例用法
data = np.array([1, 2, 3, 10, 20, 30, 100])

# 基于概率分布的方法 (Z-score)
outliers_zscore = detect_outliers_zscore(data)
print("基于概率分布的方法 (Z-score) 异常值索引:", outliers_zscore)

# 基于距离的方法 (密度离群因子 - DFF)
outliers_distance = detect_outliers_distance(data)
print("基于距离的方法 (DFF) 异常值索引:", outliers_distance)

# 基于箱线图的方法
outliers_boxplot = detect_outliers_boxplot(data)
print("基于箱线图的方法 异常值索引:", outliers_boxplot)

(2)基于k最近邻算法的异常检测

基于k最近邻算法的异常检测是一种常用的无监督学习方法,它通过计算样本与其最近邻之间的距离或相似度来识别异常值。下面将详细介绍其算法原理,并分析其优点和缺点。
算法原理:
计算距离或相似度:对于每个样本,计算它与其他样本之间的距离或相似度,通常使用欧氏距离、曼哈顿距离或余弦相似度等作为度量标准。
选择k个最近邻:根据预设的参数k,选择与当前样本距离或相似度最近的k个样本作为其最近邻。
决策阈值判定:对于每个样本,根据其最近邻的距离或相似度,设置一个阈值。如果样本与其最近邻的距离或相似度超过阈值,则将其视为异常值。
优点:
简单易实现:基于k最近邻算法的异常检测较为简单,容易实现和理解。
适应数据分布变化:该方法不依赖数据的分布假设,能够适应不同类型的数据。
不依赖训练数据:无需训练阶段,直接使用样本数据进行异常检测。
缺点:
效率低下:计算每个样本与其他所有样本的距离或相似度可能会导致计算复杂度较高,特别是在大规模数据集上。
参数选择:选择合适的k值和阈值对算法的性能影响很大,需要通过经验或试验来确定。选择不恰当的参数可能导致误判异常值或漏判异常值。
处理高维数据困难:在高维空间中,距离计算可能受到维度灾难的影响,使得结果不准确。
总结:
基于k最近邻算法的异常检测方法是一种简单直观、不依赖训练数据的异常检测方法。它通过计算样本与其最近邻之间的距离或相似度来识别异常值。然而,该方法的缺点在于效率低下、参数选择的依赖以及在处理高维数据时的困难。在实际应用中,需要根据具体问题和数据特点来选择合适的k值和阈值,并考虑使用降维等技术来解决高维数据的问题,以提高算法的性能和可靠性。
Demo代码实现如下所示:

import numpy as np
from sklearn.neighbors import NearestNeighbors

# 生成随机实验数据
np.random.seed(42)
data = np.concatenate([np.random.normal(0, 1, 100), np.random.normal(10, 1, 20)])

"""
使用 numpy 库生成了一个实验数据集。该数据集包含了两个正态分布的样本,其中一个分布的均值为 0,标准差为 1,样本数量为 100;另一个分布的均值为 10,标准差为 1,样本数量为 20。这样生成的数据集中,后面 20 个样本点就是异常值。

然后使用 detect_outliers_knn 函数进行基于 k 最近邻算法的异常值检测。在示例中使用默认的参数,k=5 和阈值为 1.5。输出结果为后面 20 个样本点的索引列表,即 [100, 101, ..., 119],表示这些样本点被判定为异常值。
"""

def detect_outliers_knn(data, k=5, threshold=1.5):
    """
    使用基于 k 最近邻算法的异常值检测
    参数:
        - data: 输入数据,可以是一维数组或二维数组
        - k: 进行 k 最近邻计算时的邻居数,默认为5
        - threshold: 判断异常值的阈值,默认为1.5
    返回值:
        - outliers: 异常值的索引列表
    """
    if len(data.shape) == 1:
        # 对于一维数组
        data = data.reshape(-1, 1)
    
    knn = NearestNeighbors(n_neighbors=k)
    knn.fit(data)
    distances, _ = knn.kneighbors()
    avg_distances = np.mean(distances, axis=1)
    max_distance = np.max(avg_distances)
    
    outliers = np.where(avg_distances > threshold * max_distance)[0]
    return outliers

# 示例用法
outliers = detect_outliers_knn(data)
print("异常值的索引:", outliers)

(3)基于孤立森林(Isolation Forest)的异常检测算法

基于孤立森林(Isolation Forest)的异常检测是一种基于树结构的无监督学习方法,它通过构建随机划分的二叉树来识别异常值。下面将详细介绍其算法原理,并分析其优点和缺点。
算法原理:
构建孤立树:对于给定的数据集,随机选择一个特征和一个切分点,将数据集分成两个子集。递归地在每个子集上重复这个过程,直到达到停止条件(如树的高度达到预设值或子集中只有一个样本)。
计算异常分值:通过计算从根节点到每个样本所经过的路径长度来定义异常分值。路径越短,则样本越容易被划分为异常值。
决策阈值判定:根据预设的阈值,如果样本的异常分值超过阈值,则将其视为异常值。
优点:
高效性:相比于其他基于距离的方法,孤立森林具有较高的计算效率,因为它使用随机化的切分方式进行树的构建。
不受数据分布影响:该方法不假设数据的分布情况,适用于不同类型的数据,包括多维数据和混合数据。
可扩展性:孤立森林可以通过集成多个孤立树来提高异常检测的准确性和鲁棒性。
缺点:
对于高维稀疏数据不敏感:孤立森林算法在处理高维稀疏数据时可能会出现偏差,因为随机切分方式在这种情况下效果较差。
参数选择:需要选择合适的树高度和异常分值阈值来进行异常检测。参数选择对算法的性能影响很大,需要通过经验或试验来确定。
总结:
基于孤立森林的异常检测方法是一种高效、具有普适性的无监督学习方法。它通过构建随机划分的二叉树来识别异常值,并利用路径长度作为异常分值进行判断。然而,该方法在处理高维稀疏数据时可能存在偏差,并且需要选择合适的参数来进行异常检测。 在实际应用中,需要根据具体问题和数据特点来选择合适的树高度和异常分值阈值,并结合其他技术(如降维)来提高算法的性能和可靠性。

Demo代码实现如下所示:

import numpy as np
from sklearn.datasets import make_blobs
from sklearn.ensemble import IsolationForest

# 生成实验数据
data, _ = make_blobs(n_samples=100, centers=1, random_state=42)  # 正常数据
outliers, _ = make_blobs(n_samples=20, centers=1, random_state=42)  # 异常值

"""
使用 sklearn.datasets.make_blobs 函数生成了一个实验数据集。该数据集包含了一个正态分布的样本集作为正常数据,以及一个与之不同的正态分布样本集作为异常值。
然后使用 detect_outliers_isolation_forest 函数进行基于孤立森林算法的异常值检测。使用默认的参数,即异常值比例为 0.1(10%)。输出结果为异常值的索引列表,表示这些样本点被判定为异常值。
"""

# 合并正常数据和异常值
data = np.concatenate([data, outliers])

def detect_outliers_isolation_forest(data, contamination=0.1):
    """
    使用基于孤立森林算法的异常值检测
    参数:
        - data: 输入数据,可以是一维数组或二维数组
        - contamination: 指定异常值的比例,默认为0.1
    返回值:
        - outliers: 异常值的索引列表
    """
    if len(data.shape) == 1:
        # 对于一维数组
        data = data.reshape(-1, 1)
    
    clf = IsolationForest(contamination=contamination)
    clf.fit(data)
    outliers = np.where(clf.predict(data) == -1)[0]
    return outliers

# 示例用法
outliers = detect_outliers_isolation_forest(data)
print("异常值的索引:", outliers)

(4)基于DBSCAN的异常检测算法

基于DBSCAN(Density-Based Spatial Clustering of Applications with Noise)的异常检测是一种基于密度的无监督学习方法,它通过将数据点分为核心点、边界点和噪声点来识别异常值。下面将详细介绍其算法原理,并分析其优点和缺点。
算法原理:
密度可达:对于给定的数据集和邻域半径ε,如果一个样本的邻域内至少包含MinPts个样本,则该样本被认为是核心点。如果一个样本在某个核心点的邻域内,但自身不是核心点,则被认为是边界点。否则,该样本被视为噪声点。
扩展聚类:从任意未访问的核心点开始,通过对邻域内的样本进行递归扩展,将与该核心点密度可达的样本划分到同一个簇中。重复这个过程直到所有核心点都被访问并且没有新的样本可以加入到已有簇中。
异常点判定:根据未被划分到任何簇的样本被认为是异常点。
优点:
不受数据分布影响:DBSCAN算法不依赖数据的分布假设,能够发现任意形状的簇,并且对于密度变化较大的数据集也能有效处理。
自动确定簇的数量:相比于其他聚类算法,DBSCAN不需要事先指定簇的数量,而是根据数据的密度来自动确定簇的个数。
鲁棒性强:该方法对于噪声和异常值具有一定的容忍度,能够较好地处理包含噪声的数据集。
缺点:
参数选择:DBSCAN算法需要设置邻域半径ε和最小样本数MinPts这两个参数来进行聚类和异常检测,合理的参数选择对算法结果影响较大,需要通过经验或试验来确定。
对于高维数据效果较差:由于维度灾难的问题,DBSCAN算法在处理高维数据时可能会遇到困难,容易导致稀疏邻域,因此在高维数据上的表现可能不佳。
总结:
基于DBSCAN的异常检测算法是一种无监督学习方法,通过将样本分为核心点、边界点和噪声点来识别异常值。它具有不受数据分布影响、自动确定簇的数量和鲁棒性强等优点。然而,该方法需要合适的参数选择,并且在处理高维数据时可能存在困难。在实际应用中,需要根据具体问题和数据特点来选择合适的参数,并结合其他技术(如降维)来提高算法的性能和可靠性。

Demo代码实现如下所示:

import numpy as np
from sklearn.cluster import DBSCAN

# 生成实验数据
data, _ = make_blobs(n_samples=100, centers=1, random_state=42)  # 正常数据
outliers, _ = make_blobs(n_samples=20, centers=1, random_state=42)  # 异常值

# 合并正常数据和异常值
data = np.concatenate([data, outliers])

"""
使用 sklearn.datasets.make_blobs 函数生成了一个实验数据集。该数据集包含了一个正态分布的样本集作为正常数据,以及一个与之不同的正态分布样本集作为异常值。
然后使用 detect_outliers_dbscan 函数进行基于 DBSCAN 算法的异常值检测。使用默认的参数,即领域半径 eps 为 0.5,最小样本数 min_samples 为 5。输出结果为异常值的索引列表,表示这些样本点被判定为异常值。
"""


def detect_outliers_dbscan(data, eps=0.5, min_samples=5):
    """
    使用基于 DBSCAN 算法的异常值检测
    参数:
        - data: 输入数据,可以是一维数组或二维数组
        - eps: 指定 DBSCAN 的领域半径,默认为0.5
        - min_samples: 指定 DBSCAN 的最小样本数,默认为5
    返回值:
        - outliers: 异常值的索引列表
    """
    if len(data.shape) == 1:
        # 对于一维数组
        data = data.reshape(-1, 1)
    
    dbscan = DBSCAN(eps=eps, min_samples=min_samples)
    dbscan.fit(data)
    
    # 认为标签为-1的点为异常值
    outliers = np.where(dbscan.labels_ == -1)[0]
    return outliers

# 示例用法
outliers = detect_outliers_dbscan(data)
print("异常值的索引:", outliers)

(5)基于LOF的异常检测算法

基于LOF(Local Outlier Factor)的异常检测是一种基于密度的无监督学习方法,它通过计算每个样本的局部离群因子来识别异常值。下面将详细介绍其算法原理,并分析其优点和缺点。
算法原理:
计算局部可达密度:对于每个样本,计算它与其k个最近邻之间的距离,然后计算这些距离的倒数,得到局部可达密度(Local Reachability Density,LRD)。LRD越大,表示样本周围的密度越大。
计算局部离群因子:对于每个样本,计算它与其k个最近邻中的样本的LRD比值,并取平均值,得到局部离群因子(Local Outlier Factor,LOF)。LOF越大,表示样本相对于其邻域更有可能是异常值。
判断异常点:根据预设的阈值,如果样本的LOF值超过阈值,则将其视为异常值。
优点:
不受数据分布影响:LOF算法不假设数据的分布情况,能够有效地发现任意形状的簇和异常值。
考虑局部上下文信息:LOF算法通过考虑样本与其邻域之间的密度关系,能够更好地捕获局部上下文信息,从而提高异常检测的准确性。
可用于聚类分析:LOF算法不仅可以用于异常检测,还可以用于聚类分析,帮助发现数据中的簇结构。
缺点:
参数选择:LOF算法需要选择合适的k值和阈值来进行异常检测。参数选择对算法的性能影响较大,需要通过经验或试验来确定。
计算复杂度高:计算每个样本与其k个最近邻的距离和LRD值可能会导致计算复杂度较高,尤其在大规模数据集上。
对于高维数据效果较差:由于维度灾难的问题,LOF算法在处理高维数据时可能会遇到困难,容易受到“维度诅咒”的影响。
总结:
基于LOF的异常检测算法是一种无监督学习方法,通过计算每个样本的局部离群因子来识别异常值。它具有不受数据分布影响、考虑局部上下文信息和可用于聚类分析等优点。然而,该方法需要合适的参数选择,并且在计算复杂度和处理高维数据时可能存在困难。在实际应用中,需要根据具体问题和数据特点来选择合适的参数,并结合其他技术(如降维)来提高算法的性能和可靠性。

Demo代码实现如下所示:

import numpy as np
from sklearn.datasets import make_blobs
from sklearn.neighbors import LocalOutlierFactor

# 生成实验数据
data, _ = make_blobs(n_samples=100, centers=1, random_state=42)  # 正常数据
outliers, _ = make_blobs(n_samples=20, centers=1, random_state=42)  # 异常值

# 合并正常数据和异常值
data = np.concatenate([data, outliers])


"""
使用 sklearn.datasets.make_blobs 函数生成了一个实验数据集。该数据集包含了一个正态分布的样本集作为正常数据,以及一个与之不同的正态分布样本集作为异常值。
然后使用 detect_outliers_lof 函数进行基于 LOF 算法的异常值检测,使用默认的参数,即异常值比例为 0.1(10%)。输出结果为异常值的索引列表,表示这些样本点被判定为异常值。
"""

def detect_outliers_lof(data, contamination=0.1):
    """
    使用基于 LOF 算法的异常值检测
    参数:
        - data: 输入数据,可以是一维数组或二维数组
        - contamination: 指定异常值比例,默认为0.1
    返回值:
        - outliers: 异常值的索引列表
    """
    if len(data.shape) == 1:
        # 对于一维数组
        data = data.reshape(-1, 1)
    
    lof = LocalOutlierFactor(contamination=contamination)
    lof.fit_predict(data)
    scores = -lof.negative_outlier_factor_
    
    # 根据分数判断异常值
    threshold = np.percentile(scores, (1 - contamination) * 100)
    outliers = np.where(scores > threshold)[0]
    return outliers

# 示例用法
outliers = detect_outliers_lof(data)
print("异常值的索引:", outliers)

(6)基于高斯混合模型GMM的异常检测算法

基于高斯混合模型(Gaussian Mixture Model, GMM)的异常检测算法是一种基于概率统计的无监督学习方法,它通过拟合数据集为多个高斯分布的混合模型,并根据样本在这些分布中的概率来判断异常值。下面将详细介绍其算法原理,并分析其优点和缺点。
算法原理:
模型拟合:首先,通过最大似然估计或期望最大化算法,将数据集拟合为一个具有多个高斯分布组成的混合模型。
计算概率密度:对于每个样本,计算其在各个高斯分布中的概率密度值,并加权求和,得到该样本的总概率密度值。
异常判定:根据预设的阈值,如果样本的概率密度值低于阈值,则将其视为异常值。
优点:
能够建模复杂分布:GMM能够灵活地建模复杂的数据分布,因为它是由多个高斯分布混合而成的模型,能够捕捉数据集中的不同模式和聚类结构。
提供概率估计:GMM对每个样本提供了在各个高斯分布中的概率密度估计,因此可以根据样本在不同分布中的概率来判断异常值的程度。
可扩展性:GMM可以通过增加高斯分布的数量来提高模型的复杂度和灵活性,适应更复杂的数据分布。
缺点:
高计算复杂度:GMM的拟合过程需要进行迭代优化,计算复杂度较高,尤其在大规模数据集上可能会受到限制。
对于维度灾难敏感:由于高斯分布的参数数量与数据维度相关,当处理高维数据时,GMM可能遇到维度灾难的问题,需要对数据进行降维等预处理。
参数选择:GMM需要选择合适的高斯分布数量、初始化策略和优化算法等参数,这些参数的选择对模型的性能和结果影响较大,需要经验或试验来确定。
总结:
基于高斯混合模型的异常检测算法是一种灵活且有概率估计的无监督学习方法。它能够建模复杂的数据分布,并根据样本在高斯分布中的概率来判断异常值。然而,该方法的计算复杂度较高,对于高维数据和参数选择要求较高。在实际应用中,需要根据具体问题和数据特点来选择合适的参数,并结合其他技术(如降维)来提高算法的性能和可靠性。

Demo代码实现如下所示:

import numpy as np
from sklearn.datasets import make_blobs
from sklearn.mixture import GaussianMixture

# 生成实验数据
data, _ = make_blobs(n_samples=100, centers=1, random_state=42)  # 正常数据
outliers, _ = make_blobs(n_samples=20, centers=1, random_state=42)  # 异常值

# 合并正常数据和异常值
data = np.concatenate([data, outliers])


"""
使用 sklearn.datasets.make_blobs 函数生成了一个实验数据集。该数据集包含了一个正态分布的样本集作为正常数据,以及一个与之不同的正态分布样本集作为异常值。
然后使用 detect_outliers_gmm 函数进行基于高斯混合模型 (GMM) 算法的异常值检测。使用默认的参数,即分量数 n_components 为 2,异常值比例 contamination 为 0.1(10%)。输出结果为异常值的索引列表,表示这些样本点被判定为异常值。
"""


def detect_outliers_gmm(data, n_components=2, contamination=0.1):
    """
    使用基于高斯混合模型 (Gaussian Mixture Model, GMM) 的异常值检测
    参数:
        - data: 输入数据,可以是一维数组或二维数组
        - n_components: 指定 GMM 中的分量数,默认为2
        - contamination: 指定异常值比例,默认为0.1
    返回值:
        - outliers: 异常值的索引列表
    """
    if len(data.shape) == 1:
        # 对于一维数组
        data = data.reshape(-1, 1)
    
    gmm = GaussianMixture(n_components=n_components, covariance_type='full', 
                          max_iter=100, random_state=42)
    gmm.fit(data)
    scores = -gmm.score_samples(data)
    
    # 根据分数判断异常值
    threshold = np.percentile(scores, (1 - contamination) * 100)
    outliers = np.where(scores > threshold)[0]
    return outliers

# 示例用法
outliers = detect_outliers_gmm(data)
print("异常值的索引:", outliers)

(7)基于自编码器(Autoencoder)的异常检测算法

基于自编码器(Autoencoder)的异常检测算法是一种无监督学习方法,它通过训练一个能够重构输入数据的神经网络模型,并利用重构误差来判断异常值。下面将详细介绍其算法原理,并分析其优点和缺点。
算法原理:
自编码器结构:自编码器通常由两部分组成,编码器和解码器。编码器将输入数据映射到低维的潜在表示空间,然后解码器将潜在表示映射回重构的输入空间。
训练过程:通过最小化输入与重构输出之间的重构误差,自编码器模型被训练出来。正常样本能够被较好地重构,而异常样本则会产生较大的重构误差。
异常判定:根据预设的阈值,如果样本的重构误差超过阈值,则将其视为异常值。
优点:
无监督学习:自编码器是一种无监督学习方法,不需要标注的异常样本进行训练,因此对于没有或数量有限的异常样本的场景也可以使用。
强大的非线性建模能力:自编码器具有非线性建模的能力,可以有效地捕捉数据中的复杂模式和特征,尤其在处理高维数据时表现良好。
泛化能力:自编码器可以学习到数据的潜在表示,具有一定的泛化能力,当面对与训练数据分布不同但相似的数据时,也能有效检测异常。
缺点:
参数选择:自编码器需要选择合适的网络结构、损失函数和正则化方法等参数。不同的参数选择可能会导致模型性能和异常检测结果的差异,需要经验或试验来确定。
难以区分不同类型的异常:自编码器通常是通过重构误差来判断异常值,因此难以区分不同类型的异常,可能会将罕见但正常的样本误分类为异常。
计算复杂度较高:自编码器模型的训练需要大量的计算资源和时间,尤其在大规模数据集上可能会受到限制。
总结:
基于自编码器的异常检测算法是一种无监督学习方法,通过训练一个能够重构输入数据的神经网络模型,并利用重构误差来判断异常值。它具有无监督学习、非线性建模能力和泛化能力等优点。然而,该方法需要合适的参数选择,并且难以区分不同类型的异常。此外,自编码器模型的训练过程计算复杂度较高。在实际应用中,需要根据具体问题和数据特点来选择合适的参数,并结合其他技术(如特征选择)来提高算法的性能和可靠性。

Demo代码实现如下所示:

import numpy as np
from sklearn.datasets import make_blobs
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model

# 生成实验数据
data, _ = make_blobs(n_samples=100, centers=1, random_state=42)  # 正常数据
outliers, _ = make_blobs(n_samples=20, centers=1, random_state=42)  # 异常值

# 合并正常数据和异常值
data = np.concatenate([data, outliers])

# 数据归一化
scaler = MinMaxScaler()
data = scaler.fit_transform(data)


"""
使用 sklearn.datasets.make_blobs 函数生成了一个实验数据集。该数据集包含了一个正态分布的样本集作为正常数据,以及一个与之不同的正态分布样本集作为异常值。
然后使用 build_autoencoder 函数构建了一个自编码器模型,并使用 detect_outliers_autoencoder 函数进行基于自编码器(Autoencoder)算法的异常值检测。使用默认的参数,即训练轮数 epochs 为 100,批次大小 batch_size 为 32。输出结果为异常值的索引列表,表示这些样本点被判定为异常值。
"""


def build_autoencoder(input_dim):
    """
    构建自编码器模型
    参数:
        - input_dim: 输入维度
    返回值:
        - autoencoder: 自编码器模型
        - encoder: 编码器模型
    """
    input_layer = Input(shape=(input_dim,))
    
    # 编码器部分
    encoded = Dense(10, activation='relu')(input_layer)
    encoded = Dense(5, activation='relu')(encoded)
    
    # 解码器部分
    decoded = Dense(10, activation='relu')(encoded)
    decoded = Dense(input_dim, activation='sigmoid')(decoded)
    
    # 构建自编码器模型
    autoencoder = Model(input_layer, decoded)
    
    # 构建编码器模型,用于提取特征
    encoder = Model(input_layer, encoded)
    
    return autoencoder, encoder

def detect_outliers_autoencoder(data, epochs=100, batch_size=32):
    """
    使用基于自编码器(Autoencoder)算法的异常值检测
    参数:
        - data: 输入数据,可以是一维数组或二维数组
        - epochs: 训练轮数,默认为100
        - batch_size: 批次大小,默认为32
    返回值:
        - outliers: 异常值的索引列表
    """
    if len(data.shape) == 1:
        # 对于一维数组
        data = data.reshape(-1, 1)
    
    input_dim = data.shape[1]
    autoencoder, encoder = build_autoencoder(input_dim)
    autoencoder.compile(optimizer='adam', loss='mse')
    
    # 训练自编码器模型
    autoencoder.fit(data, data, epochs=epochs, batch_size=batch_size, verbose=0)
    
    # 重构样本
    reconstructed_data = autoencoder.predict(data)
    
    # 计算重构误差
    errors = np.mean(np.square(data - reconstructed_data), axis=1)
    
    # 根据重构误差判断异常值
    threshold = np.percentile(errors, 95)  # 假设异常值的阈值为95%分位点
    outliers = np.where(errors > threshold)[0]
    
    return outliers

# 示例用法
outliers = detect_outliers_autoencoder(data)
print("异常值的索引:", outliers)

猜你喜欢

转载自blog.csdn.net/Together_CZ/article/details/131631291