LSTM自编码器与KMeans聚类:时间序列异常检测新思路

探索LSTM自编码器与KMeans聚类在时间序列异常检测中的应用,无需标注数据,适用于工业监控、金融风控等领域。

原文标题:基于LSTM自编码器与KMeans聚类的时间序列无监督异常检测方法

原文作者:数据派THU

冷月清谈:

本文介绍了一种基于LSTM自编码器和KMeans聚类的时间序列异常检测方法。该方法首先利用LSTM自编码器学习序列数据的潜在表示,然后在潜在空间中应用KMeans聚类实现异常模式的自动识别。文章基于Numenta异常基准(NAB)数据集进行实验验证,该数据集是时间序列异常检测领域的标准评估基准,包含多种真实场景的时间序列数据。实验结果表明,该方法能够有效检测时间序列数据中的异常模式,且无需依赖标注的异常样本进行监督学习。本文提出的方法具有完全无监督、能够自适应地学习复杂的时间序列模式和潜在空间分析等优势,在工业监控系统、金融风险管理、网络安全监测等领域具有广阔的应用前景。

怜星夜思:

1、文章提到LSTM自编码器在正常数据上训练后,对异常数据的重构质量会下降。那么,重构误差的阈值应该如何确定,才能在实际应用中更准确地识别异常?有什么自适应确定阈值的方法吗?
2、文章中KMeans聚类是在LSTM自编码器提取的潜在空间中进行的。考虑到KMeans对初始聚类中心敏感,且需要预先指定聚类数量,这在实际应用中可能会带来问题。有没有其他聚类算法或者改进方法可以应用在这个场景中?
3、文章提到该方法是无监督的,但在实际应用中,即使没有完全标注的异常数据,往往也会有一些先验知识,比如某些时间段内系统维护导致的数据异常。如何将这些先验知识融入到无监督异常检测模型中,以提高检测的准确性和可靠性?

原文内容

来源:DeepHub IMBA
本文约2600字,建议阅读7分钟
本文提出的基于LSTM自编码器和KMeans聚类的组合方法。


时间序列异常检测是金融监控、网络安全防护、工业制造控制以及物联网系统监测等领域的核心技术问题。本文研究了一种结合深度学习LSTM自编码器与KMeans聚类算法的无监督异常检测方法,该方法首先利用LSTM自编码器学习序列数据的潜在表示,然后在潜在空间中应用KMeans聚类实现异常模式的自动识别。

本文基于Numenta异常基准(NAB)数据集进行实验验证,该数据集是时间序列异常检测领域的标准评估基准,包含多种真实场景的时间序列数据。

数据集介绍


Numenta异常基准(NAB)是一个综合性的时间序列异常检测评估框架,涵盖了工业测量传感器数据、真实网络流量监控数据、在线广告交换系统数据以及合成生成的模拟数据等多个应用领域的时间序列样本。

本文选用NAB数据集中的artificialWithAnomaly子集作为实验数据。该子集包含人工合成的时间序列数据,其中注入了预定义的异常模式,为无监督异常检测算法的有效性验证提供了理想的测试环境。数据集的每条记录由时间戳和对应的数值组成,模拟了实际应用场景中的监测指标变化。

在深入分析核心算法之前,需要明确序列数据的基本概念以及LSTM自编码器在异常检测中的应用原理。

序列数据的特征与挑战


序列数据,也称为时间序列数据,是指按照时间顺序采集和记录的数据序列。这类数据的显著特征在于观测值之间存在时间依赖关系,当前时刻的数值往往与历史时刻的观测值密切相关,因此时间维度的信息对于数据分析具有关键意义。序列数据广泛存在于物联网传感器监测、金融市场价格波动、信息系统日志记录等应用场景中。由于序列数据包含复杂的时间演化模式,传统的机器学习方法在处理此类数据时存在明显局限性。相比之下,具备时间动态建模能力的深度学习模型是长短期记忆网络(LSTM),能够有效捕获和利用时间序列中的长期依赖关系。

LSTM自编码器的异常检测机制


LSTM自编码器与用于序列预测或分类的标准LSTM网络在架构设计上存在本质差异。LSTM自编码器的核心目标是学习输入序列的重构映射,其架构由编码器和解码器两个主要组件构成。编码器LSTM网络负责将输入的时间序列压缩为低维的潜在表示向量,该向量捕获了序列数据的核心特征信息。解码器LSTM网络则从这个压缩的潜在编码中重构原始的输入序列。

异常检测的基本假设是,模型在正常数据上训练后,能够准确重构符合正常模式的序列,而对于偏离正常行为的异常序列,其重构质量会显著下降。通过分析重构误差的分布特征或潜在空间中的结构模式,可以有效识别时间序列中的异常行为。

当LSTM自编码器将输入序列映射为潜在向量后,这些向量构成了一个新的特征空间,其中包含了原始数据的时间模式信息。在这个潜在空间中,正常序列和异常序列可能表现出更明显的分离特征。本方法不仅依赖重构误差进行异常判断,还在潜在空间中应用KMeans聚类算法对相似的潜在表示进行分组。该策略基于以下假设:正常序列的潜在表示会聚集形成主要的聚类簇,而异常序列则表现为离群点或形成规模较小的独立聚类。这种方法能够检测出那些可能不会产生显著重构误差,但在潜在空间中展现出不同时间动态特征的细微异常模式。

现在让我们深入分析具体的实现过程。

数据探索与可视化


首先对数据进行可视化分析,了解时间序列的基本分布特征:

 import matplotlib.pyplot as plt  
 import seaborn as sns  
 %matplotlib inline  
   
 plt.figure(figsize=(12,6))  
 sns.lineplot(x=df.index, y=df['value'])  
 plt.show()


 sns.histplot(df['value'], bins=100, kde=True)

数据预处理与序列构造


在确认数据格式的正确性后,使用MinMaxScaler对时间序列进行标准化处理,并构造固定长度的滑动窗口序列作为LSTM网络的输入。该预处理步骤对于深度学习模型的训练稳定性和收敛性具有重要意义。

 scaler = MinMaxScaler()  
scaled_data = scaler.fit_transform(df[['value']])  

def create_sequences(data, seq_length):  
    X = []  
    for i in range(len(data) - seq_length):  
        X.append(data[i:i + seq_length])  
    return np.array(X)  

SEQ_LENGTH = 50  
 X = create_sequences(scaled_data, SEQ_LENGTH)


LSTM自编码器模型构建


构建LSTM自编码器的网络架构,其中编码器将输入序列压缩为64维的潜在向量,解码器则尝试从该潜在表示重构原始序列:

 input_dim = X.shape[2]  
timesteps = X.shape[1]  

inputs = Input(shape=(timesteps, input_dim))  
encoded = LSTM(64, activation='relu', return_sequences=False, name="encoder")(inputs)  
decoded = RepeatVector(timesteps)(encoded)  
decoded = LSTM(64, activation='relu', return_sequences=True)(decoded)  

autoencoder = Model(inputs, decoded)  
autoencoder.compile(optimizer='adam', loss='mse')  
 autoencoder.fit(X, X, epochs=50, batch_size=64, validation_split=0.1, shuffle=True)


为了提取序列的潜在表示,定义独立的编码器模型:

 encoder_model = Model(inputs, encoded)  
 latent_vectors = encoder_model.predict(X, verbose=1, batch_size=32)  # shape = (num_samples, 64)


潜在空间聚类分析


区别于传统的重构误差阈值方法,本文在压缩后的潜在向量空间中应用KMeans聚类算法进行异常检测:

 from sklearn.cluster import KMeans  

kmeans = KMeans(n_clusters=2, random_state=42)  
labels = kmeans.fit_predict(latent_vectors)  

# 假设样本数量较多的聚类为正常模式  
normal_cluster = np.bincount(labels).argmax()  
 anomaly_mask = labels != normal_cluster


通过主成分分析(PCA)将高维潜在空间投影到二维平面进行可视化:

 from sklearn.decomposition import PCA  

pca = PCA(n_components=2)  
latent_pca = pca.fit_transform(latent_vectors)  

plt.figure(figsize=(10, 6))  
sns.scatterplot(x=latent_pca[:, 0], y=latent_pca[:, 1], hue=labels, palette='Set1', s=50, alpha=0.7)  
plt.title("Kmeans cluster in latent space (PCA 2D)")  
plt.xlabel("principal component 1")  
plt.ylabel("principal component 2")  
plt.grid(True)  
 plt.show()

异常检测结果可视化


将检测到的异常点在原始时间序列上进行标注,直观展示异常检测的效果:

 timestamps = balancer.index[SEQ_LENGTH:]  

plt.figure(figsize=(15, 5))  
plt.plot(timestamps, df['value'][SEQ_LENGTH:], label='Value')  
plt.scatter(timestamps[anomaly_mask], df['value'][SEQ_LENGTH:][anomaly_mask], color='red', label='Detected Anomalies')  
plt.legend()  
plt.title("Anomalies Detected via KMeans on LSTM Latent Space")  
 plt.show()

总结


本文提出的基于LSTM自编码器和KMeans聚类的组合方法,通过整合深度学习的序列建模能力与无监督聚类的模式分组优势,实现了对时间序列数据中异常模式的有效检测,且无需依赖标注的异常样本进行监督学习。

该方法具有以下技术优势:首先,完全基于无监督学习范式,无需人工标注的训练数据,适用于缺乏先验异常知识的实际应用场景;其次,能够自适应地学习复杂的时间序列模式,包括长期依赖关系和非线性时间动态;最后,通过潜在空间的分析为异常检测提供了新的视角,支持对数据内在结构的深入探索和可视化分析。

这种方法在工业监控系统、金融风险管理、网络安全监测等对异常检测准确性和实时性要求较高的应用领域具有广阔的应用前景。

作者:Falonne KPAMEGAN

编辑:黄继彦



关于我们

数据派THU作为数据科学类公众号,背靠清华大学大数据研究中心,分享前沿数据科学与大数据技术创新研究动态、持续传播数据科学知识,努力建设数据人才聚集平台、打造中国大数据最强集团军




新浪微博:@数据派THU

微信视频号:数据派THU

今日头条:数据派THU

KMeans确实有其局限性,对初始化敏感,且需要指定聚类数量。可以考虑使用层次聚类,它不需要预先指定聚类数量,可以通过设定不同的距离阈值来获得不同粒度的聚类结果。另外,DBSCAN也是一个不错的选择,它能自动发现具有任意形状的聚类,并且对噪声具有一定的鲁棒性,但是DBSCAN的参数选择也比较tricky。

其实可以把先验知识当成权重来用。比如已知某段时间异常概率高,那这段时间就算模型判断正常,也稍微提高一点它的异常分数。反之,如果某段时间肯定正常,那就可以降低异常分数。不过这个权重怎么设置需要好好琢磨一下,不然容易适得其反。

我觉得可以将先验知识用于数据预处理阶段,例如,对于已知的异常时间段,可以采取一些平滑处理或者直接删除这些数据。此外,还可以使用数据增强的方法,根据先验知识生成一些模拟的异常数据,用于模型的训练。这样可以提高模型对异常数据的敏感性,从而提高检测的准确率。

阈值设定确实是个难点,纯统计的方法可能不够鲁棒,容易受到数据波动的影响。我建议结合领域知识,例如,在工业监控中,某些物理量超过特定范围本身就代表异常,可以将这些先验知识融入阈值设定中。此外,还可以考虑使用集成方法,例如结合多种异常检测算法,通过投票或加权平均的方式来提高检测的准确率。

确定重构误差阈值是个关键问题。我认为可以考虑使用统计方法,比如计算训练集重构误差的均值和标准差,然后设置阈值为均值加上若干倍的标准差。更高级的方法可以尝试使用分位数,例如选择95%或99%分位数作为阈值。自适应的阈值方法可能需要根据实时数据流动态调整,例如使用滑动窗口计算误差统计量,并根据窗口内的数据更新阈值。

除了更换聚类算法,还可以尝试改进KMeans本身。例如,可以使用K-Means++初始化方法来选择更合理的初始聚类中心,从而提高聚类的稳定性和准确性。此外,还可以结合轮廓系数等指标来评估聚类效果,并选择最佳的聚类数量。如果对于聚类结果的可解释性要求较高,可以考虑使用一些基于模型的聚类方法,例如高斯混合模型(GMM)。

我觉得可以借鉴机器学习中的模型评估方法。可以将数据集分成训练集、验证集和测试集。在训练集上训练LSTM自编码器,然后在验证集上寻找最佳的重构误差阈值,最后在测试集上评估模型的性能。可以使用ROC曲线、AUC等指标来评估不同阈值下的检测效果,并选择最优的阈值。这种方式的好处是可以避免过拟合,并确保模型在未知数据上具有良好的泛化能力。

我有个有点野的思路,既然聚类是为了区分正常和异常,那是不是可以用OneClassSVM?把大部分数据当成正常样本训练一个边界,落到边界之外的就算异常。不过这个方法对参数也很敏感,需要好好调。

将先验知识融入无监督模型是个很有意思的问题。可以考虑使用半监督学习的方法,将已知的异常数据作为弱监督信号,来指导模型的训练。例如,可以在损失函数中加入一个正则项,使得模型对已知的异常数据具有更高的重构误差。另一种方法是使用集成学习,将无监督模型和基于规则的异常检测器结合起来,规则可以根据先验知识来设定,从而提高检测的准确率。