多元时序异常检测的可解释之路:模态转换与双模态SHAP实战

📅 发布时间:2026/9/1 4:09:34
多元时序异常检测的可解释之路:模态转换与双模态SHAP实战
平时做系统监控告警的同学应该都有同感单个指标阈值告警太简单经常误报多维指标一起看又很难设计通用规则。尤其是把 LSTM、Transformer 这类模型放到线上之后模型能力是强了但每次告警大家只能对着重构误差曲线猜原因。最近看到 TKDE 2026 上收录的 MOON 方法思路很有意思它不追求把网络越做越深而是通过模态转换把多元时序数据映射成多个视图再用双模态 SHAP 把“为什么异常”这件事变得可解释。这篇文章围绕 MOON 思路中两个最具普适性的技术点——模态转换与双模态 SHAP做一次工程化解读并用一组可运行的 Python 实验把整个流程完整跑通帮助你快速迁移到自己的监控场景中。如果你正好面对“多指标监控、无标签样本居多、告警后难以定位根因”这几类问题这篇文章会比较适合你。阅读过程中不需要复杂的深度学习背景只要会 Python 和基础机器学习即可。读完你会掌握多元时序异常检测的基本挑战、模态转换常见方法、双模态 SHAP 的解释思路以及一套从数据构造、特征提取、模型训练到异常解释的完整代码。1. 多元时序异常检测背景与挑战1.1 多元时序异常检测是什么多元时序异常检测指的是对多个时间上同步采集的指标序列进行联合监控当某一时刻的组合表现偏离正常模式时系统给出异常告警或异常分数。它的典型场景包括数据中心监控中的 CPU、内存、网络延迟、磁盘 IO工业生产中的温度、压力、振动频率以及金融风控中的交易金额、频次、渠道变化等。与单变量异常检测不同多元时序异常检测的核心特征是信息既存在于单个指标的时间变化中也隐藏在多个指标之间的联动关系里。一个指标单独看可能完全正常但多个指标的组合模式一旦被打破往往意味着故障已经发生或者正在形成。比如 CPU 升高本身不算异常但如果 CPU 升高、磁盘 IO 持续下降、网络吞吐异常波动同时出现就很可能说明某个服务进程正在发生故障。从异常形态来看多元时序异常大致可以分成三类点异常某个时刻单个或多个指标出现突变上下文异常指标值在某个局部时间段内不符合该时间段的周期性规律集体异常一组数据点联合起来形成不符合全局模式的行为比如一段时间内的持续漂移。传统监控告警大多使用固定阈值规则维护成本高跨业务复用性差。因此基于统计模型和机器学习模型的异常检测方法逐渐成为主流MOON 这类融合多模态思路的方法也正是在这个背景下被提出的。1.2 单模态建模的局限目前常见的异常检测基线可以大致分为四类统计方法3σ、EWMA、MAD适合单指标、分布稳定的场景传统机器学习Isolation Forest、OneClassSVM、PCA 重构误差特征工程依赖较强深度序列模型LSTM-AE、Transformer-AE、TimesNet、Anomaly Transformer能捕捉复杂时序依赖多模态/多视图方法将时序转换到频域、图像或图结构后联合建模代表性思路就是 MOON。这些方法中的大多数本质上都在“时域”这一单一模态上建模。时域窗口的优点是直观、实现简单但在实际数据上会遇到几个明显问题强周期信号在时域看起来非常复杂但频率域能量往往集中在少数频率分量上只观察时域波形会忽略周期结构的变化低频趋势和高频噪声叠加在一起单一模态很难区分“趋势漂移”和“噪声增大”这两种不同的异常原因某些异常在时域表现很弱但在频域非常清晰。例如机械故障早期振动信号在某个啮合频率附近的能量会突然增强而时域幅值可能几乎没有变化。单模态建模的另一个问题是信息冗余。一个长度为 20 的滑窗如果有 30 个传感器原始输入维度就是 600。大量维度来自平稳噪声模型不仅计算开销大还容易把正常抖动学进表征。通过模态转换先做一次信息压缩通常能提高精度和训练效率。1.3 可解释性为什么越来越重要异常检测模型输出“第 1300 个时刻异常”对运维人员来说只是排障的开始。真正落地时大家更关心的是哪一个传感器或哪一个指标组触发异常指标是均值漂移、方差增大还是周期模式被破坏在频域上哪个频段的能量发生了异常变化如果模型是一个黑盒检测完还要人工翻看十几个维度的原始曲线效率会非常低。尤其是告警量大、值班人数少的场景逐条人工排查根本不可行。因此可解释性从“加分项”变成了“必需项”。SHAPSHapley Additive exPlanations是目前最常用的模型解释方法之一它基于博弈论中的 Shapley 值可以计算每个输入特征对预测结果的贡献。MOON 将 SHAP 扩展为“双模态 SHAP”即把特征按时域和频域分组分别聚合贡献值从而回答一个更高层的诊断问题这个异常主要是时域特征导致的还是频域特征导致的这比单纯看单个特征重要性更符合工业排障习惯。2. MOON 方法核心思路模态转换与双模态 SHAP2.1 模态转换给时序数据换个视角MOON 的基本做法并不复杂不再只用原始滑动窗口作为唯一输入而是把窗口数据通过模态变换得到第二种甚至第三种视图。所谓模态转换本质是使用不同的数学表达形式描述同一段信号让被时域掩盖的规律显式地暴露给模型。工程上常用的时序模态转换手段包括傅里叶变换 / 短时傅里叶变换把窗口从时域变到频域得到频谱或频谱图小波变换同时保留时间和频率分辨率适合非平稳信号格拉姆角场GAF把一维时序编码成二维图像保留局部相关性马尔可夫转移场MTF刻画时间点之间的状态转移概率递归图Recurrence Plot反映相空间轨迹的重复模式。MOON 使用模态转换的目的可以从三个角度看。第一是放大异常特征比如频域能量集中、周期性突变容易被捕获第二是压缩无效信息FFT 后通常只有前几个频率分量携带主要能量模型可以集中关注有效频段第三是提供互补信息当一个模态中异常不明显时另一个模态可能已经出现显著变化。需要注意模态转换不是“为了变而变”而是要把数据中原本被淹没的关键信息显式地交给模型。如果一段信号本身没有周期性强行做频域变换反而会引入噪声。因此在实际应用中要先做简单的数据分析再决定采用哪一种转换方式。2.2 双模态特征融合的检测框架将 MOON 的检测流程简化后可以拆成四个步骤滑动窗口切分原始多元时序对每个窗口分别提取时域特征和频域特征得到双模态特征把双模态特征输入融合检测模型计算异常分数对异常分数较高的样本使用双模态 SHAP 做根因解释。双模态融合方式通常有两种。一种是特征级融合也叫早融合把时域特征和频域特征拼接成同一向量输入一个模型简单且在多数场景下效果稳定。另一种是决策级融合也叫晚融合两个模态各训练一个模型得到两个异常分数再用加权或者投票方式进行融合适合两种模态差异较大的场景。MOON 之所以强调“兼顾精度、效率与可解释性”核心在于三者的平衡精度来自多模态信息互补单一模态容易漏报的异常另一模态可以兜底效率来自特征压缩和轻量模型选择而不是盲目堆叠深度网络可解释性来自双模态 SHAP把“模型为什么认为异常”分解到时域和频域两个维度。在实际落地时特征级融合实现成本最低也是本文实验中选择的方式。2.3 双模态 SHAP解释异常从何而来SHAP 基于博弈论中的 Shapley 值为每个特征分配一个对预测值的贡献值。对某个样本模型的预测值可以分解为f(x) E[f(X)] Σ_j shap_value_j(x)其中E[f(X)]是训练集的平均预测值基线每个特征的shap_value_j表示该特征对当前预测的边际贡献。所有特征贡献相加之后等于模型输出因此 SHAP 具备可加性和局部一致性。所谓双模态 SHAP并不是一种新的 SHAP 数学算法而是一套使用思路把输入特征按模态分成两组一组是时域特征一组是频域特征。模型预测完成后分别聚合两组特征的 SHAP 值就可以回答“这个异常主要是时域贡献大还是频域贡献大”。双模态 SHAP 的聚合方式常见有两种绝对值求和反映模态整体贡献强度适合回答“哪些变化导致预测偏离正常”按正负分别求和反映模态是推高还是拉低预测分数适合回答“异常的方向”。在异常检测场景中通常推荐先看绝对值求和因为它更稳定不容易出现正负抵消导致误判。如果进一步需要定位具体传感器和特征可以继续绘制单个特征的 SHAP 图定位到具体指标。3. 实验设计与环境准备3.1 实验目标与整体流程本文实验将实现一个“MOON 思路最小可行版本”包含以下环节构造一个 3 传感器的多元时序数据注入三类典型异常突跳、方差增大、趋势漂移使用滑动窗口提取双模态特征时域模态均值、标准差、最小值、最大值、一阶差分均值、一阶差分标准差频域模态FFT 幅度谱前 6 个频段能量、频谱熵、主频位置对每个传感器独立训练随机森林回归器用“下一时刻预测误差”作为异常分数用训练集误差分布确定阈值对检测到的异常样本使用 TreeExplainer 计算双模态 SHAP并做聚合可视化。整体流程可以用下面的纯文本链路表示原始多元时序 - 滑窗切分 - 时域特征 / 频域特征 - 回归模型预测 - 预测误差 - 阈值判定异常 - 双模态 SHAP 根因解释这套流程虽然不能覆盖 MOON 论文中的全部网络结构细节但它完整保留了多模态特征输入和双模态解释两个核心思想而且代码可以独立运行适合作为项目原型的起点。3.2 环境依赖与版本说明运行本文代码需要以下 Python 库numpy数值计算scipyFFT 变换pandas数据整理本文主要用 numpypandas 可选scikit-learn随机森林回归模型与评估指标shapSHAP 解释matplotlib可视化。安装命令如下pip install numpy scipy pandas scikit-learn shap matplotlib版本方面建议使用当前各库的最新稳定版本。注意shap库的TreeExplainer接口在 0.40 版本之后基本稳定如果遇到接口不兼容的问题可以执行升级pip install --upgrade shap scikit-learn由于不同版本对随机森林多输出模型的 SHAP 支持程度不同本文实验将训练三个独立的回归模型每个模型只预测一个传感器既方便 SHAP 解释也便于理解模型行为。3.3 模拟多元时序数据构造为了演示完整的异常检测过程我们自行构造 2000 个时间点的三元时序数据。三个传感器的设计如下sensor1正弦波叠加高次谐波和少量白噪声表现明显的周期性sensor2余弦波叠加三倍频谐波和白噪声与 sensor1 存在相位差异sensor3低频组合信号加噪声整体波形更平缓。异常注入位置和类型如下A 段第 700-719 点sensor1 叠加 2.0 偏置模拟传感器跳变或外部冲击B 段第 1200-1229 点sensor2 叠加方差显著增大的随机噪声模拟接线不良或传感器抖动C 段第 1600-1649 点sensor3 叠加线性漂移模拟机械磨损或环境缓慢变化。这些异常分别对应点异常、方差类异常和趋势类异常可以比较充分地检验模型在不同异常形态下的检测能力。4. 完整实战模态特征 回归模型 双模态 SHAP4.1 数据生成与异常注入先编写数据生成函数。为了便于读者复现我固定随机种子并返回原始数据data以及真实标签labels。import numpy as np np.random.seed(42) def build_data(n2000): t np.linspace(0, 50, n) s1 np.sin(t) 0.2 * np.sin(5 * t) np.random.normal(0, 0.05, n) s2 np.cos(t) 0.1 * np.sin(3 * t) np.random.normal(0, 0.05, n) s3 0.5 * np.sin(2 * t) 0.3 * np.cos(t) np.random.normal(0, 0.05, n) # 注入异常 s1[700:720] 2.0 s2[1200:1230] np.random.normal(0, 0.5, 30) s3[1600:1650] 0.02 * np.arange(50) data np.vstack([s1, s2, s3]).T # shape: (n, 3) labels np.zeros(n, dtypeint) labels[700:720] 1 labels[1200:1230] 1 labels[1600:1650] 1 return data, labels data, labels build_data() print(data shape:, data.shape) print(异常样本数量:, labels.sum())运行输出大致为data shape: (2000, 3) 异常样本数量: 80这里说明一下真实异常检测场景中通常没有标签构造标签仅用于后续评估检测效果。阈值设定不依赖异常标签而是从训练集的正常误差分布中计算这一点更贴近无监督场景。4.2 时域模态特征提取时域模态特征提取的目标是捕捉窗口内每个传感器的统计形态。对于一个长度为window_size的窗口我们对每个传感器提取 6 个统计量均值反映整体水平标准差反映波动幅度最小值与最大值反映极端值一阶差分均值反映平均变化方向一阶差分标准差反映变化剧烈程度。这些统计量虽然简单但已经能够覆盖大多数时域异常形态且计算开销非常低。3 个传感器合计得到 18 个时域特征。4.3 频域模态特征提取频域特征提取使用 FFT 幅度谱。考虑到窗口长度只有 20FFT 后能量集中在前几个频率桶因此我们保留去直流分量后的前 6 个频段归一化幅度再额外提取频谱熵和主频位置。频谱熵反映了频谱能量分布的