ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

典型相关分析(CCA)在故障检测中的原理与Python实现

典型相关分析(CCA)在故障检测中的原理与Python实现 简介CCA.zip是一份基于典型相关分析CCA的MATLAB故障检测程序包面向从事工业过程监控、数据驱动故障诊断的研究人员与工程师。压缩包内共4个m脚本整体大小仅4KBmycanoncorr.m负责求解两组变量间的典型变量CCA.m作为主程序串联数据预处理与完整分析流程getpercent.m用于计算百分比指标以评估故障程度autoscale.m则对多维度数据进行标准化处理。这套精简代码可直接用于trade7kb交易数据集的分析帮助用户提取与故障模式高度相关的组合特征。目前已有250人学习下载适合具备一定MATLAB基础、希望快速上手CCA故障检测方法的初学者参考。通过运行这些脚本读者不仅能获得从数据读入、自动缩放、相关分析到结果解释的完整调用链还能根据自身数据调整参数为设备或交易系统的异常预警提供可复用的计算工具。1. 典型相关分析在故障检测里解决的是哪一类问题一条化工产线上温度、压力、流量、液位、转速、振动这些测点动辄几十上百个。很多团队一开始先用 PCA 做故障检测把高维数据压到几个主成分上看 T² 和 SPE。PCA 的思路是找单变量组里方差最大的方向用它描述“大部分正常波动”。但流程工业里的异常往往不是单个测点超限而是两组变量之间的相关关系被打破了——比如进料流量和塔顶温度原本是强耦合的换热器结垢之后这个耦合关系先于温度超限发生漂移。典型相关分析CCA建模时同时抓取两组变量的线性组合让组合之间的相关性最大化故障检测里就是用这种“相关结构”是否被破坏来判断异常比只看单组方差要早报警也更不容易被负荷变化误触发。这个标题里的“CCA 故障”指的是把 CCA 当作故障检测模型的主干算法“trade7kb”大概率是某个小规模历史数据集的文件名几十 KB 的 CSV折算下来不过几百个采样点。对这类小样本工况CCA 反而比 PCA 有优势它不需要估计高维协方差矩阵的全部结构只关心两组变量之间的交叉关系参数少过拟合风险低。这篇文章把 CCA 故障检测从原理到落地讲透内容包括典型变量的求解逻辑、T² 和 Q 统计量的构造、小样本下的阈值设定以及比 PCA 实用在哪里、坑在哪里。2. CCA 建模原理与故障检测的数学框架2.1 两组变量之间的相关性度量CCA 最早由 Hotelling 在 1936 年提出核心目标是对两组变量 X 和 Y分别找到线性变换 a 和 b使得变换后的典型变量 u Xa 与 v Yb 之间的相关系数最大化。这里的 X 和 Y 可以是同一过程的不同测点集合比如 X 取反应器入口变量Y 取出口变量也可以把同一组测点的时序错开形成两组让 CCA 学习其中的动态相关性。数学上假设 X ∈ R^{N×p}Y ∈ R^{N×q}N 是采样数p 和 q 是两组变量的维度。先对数据和做标准化保证均值为 0、方差为 1。然后计算三块协方差矩阵Σ_xxX 的自协方差矩阵维度 p×pΣ_yyY 的自协方差矩阵维度 q×qΣ_xyX 与 Y 的互协方差矩阵维度 p×qCCA 要找的相关系数等价于求解一个广义特征值问题求 a 使得 (Σ_xy^T Σ_xx^{-1} Σ_xy Σ_yy^{-1}) 这类矩阵的最大特征值对应的特征向量即为典型载荷。实际实现中不需要直接求逆对矩阵 K Σ_xx^{-1/2} Σ_xy Σ_yy^{-1/2} 做奇异值分解SVD分解得到的奇异值就是逐级递减的典型相关系数左右奇异向量经过变换后就得到 a 和 b。奇异值的个数最多是 min(p, q)排在前面的几个典型变量对应两组变量之间最强的线性耦合方向。故障检测建模时通常只保留前 k 个典型变量k 远小于 min(p, q)这样既捕捉了主要相关结构又滤掉了噪声主导的高阶相关性。2.2 故障检测中 CCA 的输出残差与统计量CCA 在故障检测里的关键转化是训练阶段用正常工况数据求出投影方向 a 和 b 之后对任意一个新采样点可以计算它被“已建模的相关结构”解释了多少、剩下多少没有被解释后者就是残差。故障一旦破坏了 X 和 Y 之间的原有耦合残差会明显变大。两个最常用的监测统计量是 T²也叫 Hotelling T²和 Q也叫 SPE平方预测误差。T² 度量的是样本在典型变量子空间内的波动是否超出正常范围适合检测那些不改变相关结构、但改变信号幅值的故障Q 度量的是样本在残差空间中的偏离程度专门抓相关结构被破坏的情况。把 CCA 和 PCA 做一个对比PCA 的 T² 反映的是主成分空间内的幅值变化SPE 反映残差空间的变化但 PCA 没有利用“两个变量组之间的关系”这种先验信息它只会在 X 或 Y 内部方差结构发生显著变化时才报警。而 CCA 把检测目标直接对上了相关结构这在故障早期尤其有价值——很多时候幅值还正常相关性先变了。2.3 CCA 和偏最小二乘PLS在选择上的差异同样是利用两组变量建模CCA 和 PLS 容易被混淆。最本质的区别在目标函数CCA 最大化 Xa 与 Yb 之间的相关系数关注的是相关性强度PLS 最大化 Xa 与 Yb 之间的协方差同时要求 X 的投影能尽可能解释 X 自身的方差。PLS 建模时方差和相关性一起优化预测能力通常更好CCA 则更纯粹地刻画“相关结构”在故障检测里对相关性的变化更敏感。实际选型时有一个经验如果目标是做软测量用 X 预测 Y 的数值优先 PLS如果故障表现为变量间强耦合的弱化或断裂CCA 的检测效果往往好于 PLS。另外 CCA 对 X 和 Y 内部的噪声更敏感因为最大化相关系数容易把噪声方向也放大所以使用前对原始数据做平滑或小波滤波是常见做法这个细节后面排错章节再说。3. 用 Python 在本地复现故障 CCA 的最小实现3.1 数据组织X 组、Y 组和故障段怎么划分复现一个 CCA 故障检测模型第一步是把数据组织成 X 和 Y 两组。以换热器结垢为例取进料流量、进料温度、冷却水流量作为 X 组出口温度、换热器压降作为 Y 组。故障发生前这两组变量之间的相关性稳定结垢后压降上升但流量可能没变X 与 Y 的耦合关系就偏了。样本量上注意一个前提CCA 的求解需要协方差矩阵可逆p q 不能超过样本数 N。工程上一般要求 N 2(pq)否则协方差矩阵奇异模型不稳定。对 trade7kb 这类几 KB 的小数据集几十个测点加一两百个采样点属于典型的“宽数据”后面要考虑正则化。3.2 从零实现 CCA 的核心代码用 NumPy 手写 CCA 并不复杂而且比直接调 sklearn 能更清楚地看到奇异值分解的中间结果。代码如下import numpy as np def cca_fit(X, Y, k): 输入: X, Y 为二维数组行为样本列为变量需已标准化 输出: A, B 为投影矩阵s 为典型相关系数 n X.shape[0] # 计算三块协方差矩阵 Sxx (X.T X) / (n - 1) Syy (Y.T Y) / (n - 1) Sxy (X.T Y) / (n - 1) # 对 Sxx 和 Syy 做 Cholesky 分解完成白化 Lx np.linalg.cholesky(Sxx) Ly np.linalg.cholesky(Syy) Lx_inv np.linalg.inv(Lx) Ly_inv np.linalg.inv(Ly) # 白化后的互协方差矩阵做 SVD K Lx_inv Sxy Ly_inv.T U, s, Vt np.linalg.svd(K) # 还原到原始空间的投影方向 A Lx_inv.T U[:, :k] B Ly_inv.T Vt.T[:, :k] return A, B, s[:k] def cca_project(X, Y, A, B): 计算典型变量 u 和 v以及残差 U X A V Y B return U, V, U - V # 残差矩阵逻辑说明代码先计算 X、Y 各自的自协方差和互协方差用 Cholesky 分解完成白化目的是把两组变量变成“单位方差且互不相关”的空间在这个空间里再对互协方差做 SVD得到的奇异值就是典型相关系数。A 和 B 的列数由参数 k 决定k 取 1 到 min(p, q) 之间的整数。参数说明k 是最关键的自由参数取太大会把噪声方向的伪相关也学进来取太小会漏掉真实的相关结构常见做法是观察奇异值 s 的分布取累计奇异值贡献超过 80% 的个数。矩阵分解方式上如果 Sxx 或 Syy 接近奇异Cholesky 会报错此时可改用 np.linalg.pinv 做伪逆或者给 Sxx 对角线加一个小的正则项。3.3 构造两个监测统计量并画控制图有了投影矩阵之后在训练集上计算每个样本的 T² 和 Q然后对测试集做同样的计算。测试集样本 x 和 y 先执行和训练集相同的标准化处理调用同一组 A、B 算出典型变量 u、v再算出 T² 和 Qdef compute_stats(X, Y, A, B): 计算 T² 和 Q 统计量 U, V, res cca_project(X, Y, A, B) n X.shape[0] k A.shape[1] # 典型变量的协方差理论上应为对角阵 Suu (U.T U) / (n - 1) Suu_inv np.linalg.inv(Suu) # T²典型变量空间内的马氏距离 T2 np.sum((U Suu_inv) * U, axis1) # Q残差平方和 Q np.sum(res ** 2, axis1) return T2, Q逻辑说明T² 本质上是典型变量 U 的马氏距离它衡量的是样本在典型变量子空间中的位置偏离中心的程度适合捕捉幅值变化。Q 则是对残差矩阵逐行求平方和残差越大说明 X 和 Y 之间的实际相关性和训练时学到的相关性偏离越远这是 CCA 故障检测最有价值的输出。参数说明Suu_inv 求逆前建议检查 Suu 的条件数如果条件数大于 1e6说明 k 选得过大典型变量之间有近似的线性相关模型失真。画控制图时如果训练数据来自正常工况可以用训练集 T² 和 Q 的 95% 或 99% 分位数作为控制限也可以用核密度估计拟合分布后取分位数小样本时后者更稳。4. 阈值设定、正则化与小样本场景下的落地调整4.1 控制限选择卡方近似还是经验分位数CCA 故障检测中控制限的设定直接决定误报率和漏报率。两种常见做法其一是理论近似假设 T² 近似服从卡方分布Q 近似服从加权卡方分布用分布分位数作为阈值其二是纯数据驱动直接用训练集 T² 和 Q 的经验 95% 或 99% 分位数当阈值。理论上卡方近似要求数据服从多元正态分布工业数据大概率不满足导致设定偏松或偏紧。实践中的建议是先做正规性检验用 Shapiro-Wilk 或 QQ 图看一眼 T² 和 Q 的分布形态再决定阈值来源。如果训练样本大于 500经验分位数更推荐因为不依赖分布假设如果只有一两百个样本经验分位数本身噪声很大此时用核密度估计拟合分布取高斯核下的 95% 分位数比直接排位更平滑。下面是一段阈值设定的示例代码from scipy.stats import gaussian_kde def threshold_kde(x, alpha0.95): 用核密度估计拟合分布并返回分位数阈值 kde gaussian_kde(x) # 在数据范围内细密采样构造累计分布 grid np.linspace(np.min(x), np.max(x), 1000) cdf np.array([kde.integrate_box_1d(-np.inf, t) for t in grid]) idx np.argmin(np.abs(cdf - alpha)) return grid[idx]逻辑说明KDE 比直接取分位数多一步——用高斯核把离散的点平滑成连续分布再在网格上求累计概率。坏处是计算量比直接分位数大但数据量只有几百上千个点时完全可以接受。选取 grid 的边界要覆盖训练集的极值必要时可以外扩 10% 防止阈值落在分布边缘。参数说明alpha 控制灵敏度95% 对应约 5% 的误报率99% 对应 1%。故障检测场景里一般先 99% 起步现场误报多再下调到 95%如果追求早期预警可以设 90% 并叠加“连续 3 个点超限才报警”的准则。这个准则用代码就是在滚动窗口上检查序列连续超限次数。4.2 协方差奇异与正则化给 CCA 加 Ridge 惩罚小样本场景下最常踩的坑是 Sxx 或 Syy 接近奇异Cholesky 分解报 LinAlgError。原因简单p q 接近甚至超过样本数 N协方差矩阵没有足够的观测来支撑估计。解决方案是在自协方差矩阵的对角线上加一个小的正则项这个做法也叫 Ridge CCA。lam 1e-3 Sxx_reg Sxx lam * np.eye(p) Syy_reg Syy lam * np.eye(q)lam 的取值看数据尺度标准化之后变量方差都是 1lam 从 1e-4 开始尝试每次乘 10直到 Cholesky 分解不再报错。lam 取太大会把相关结构抹平典型相关系数普遍偏小检测灵敏度下降取太小又解不动。实际操作中可以画一条“lam 对典型相关系数总和”的曲线取相关系数总和开始明显下降之前的值。另外注意标准化顺序一定要先标准化再做正则化因为标准化的均值和方差来自训练集测试集也必须沿用训练集保存的均值和标准差不能重新计算。这个细节漏掉测试集的统计量分布会和训练集不一致阈值就失效了。4.3 变量分组选择决定检测效果CCA 模型的表现高度依赖 X、Y 怎么分组这是一个经常被忽视的“参数”。原则是把有明确因果或机理关联的变量放在不同组。比如 X 放上游变量进料、冷却水Y 放下游变量出口温度、压降故障沿着工艺流程传播时相关性变化最明显。如果乱分组比如把两个强相关的同类测点各分一组CCA 学到的只是冗余变量之间的相关性故障检测意义不大。p 和 q 的比例也要注意。一组维度远大于另一组SVD 分解出的多数奇异值会被高维组主导低维组的信息被稀释。经验上让 p 与 q 接近比如 10:10、8:12。如果工艺决定了两组维度天然悬殊可以先在组内做 PCA 降维把每组压到 3 到 5 个主成分后再做 CCA整体检测效果更稳定。4.4 误报警的排查路径在线运行后如果频繁误报按下面顺序排查问题。第一步验证预处理管线确认测试集用了训练集的均值和标准差做标准化否则 T² 和 Q 都会漂移。第二步检查延迟关系很多工业变量之间存在纯滞后X 当前时刻的值和 Y 当前时刻的值没有强相关但 X 滞后若干拍之后和 Y 相关。此时把 X 做时间平移再对齐建立动态 CCA能显著减少误报。第三步检查控制回路状态如果工厂在这段时间切换了控制模式或用不同的控制器参数相关结构本身变了模型需要重训而不是调阈值硬扛。5. 动态 CCA 和贡献图把报警定位到具体变量线性 CCA 在实际现场运行一段时间后暴露的最大局限是静态假设——它认为 X 和 Y 在当前时刻满足同一个相关结构。但流程工业中的因果关系几乎都带惯性进料流量变化之后出口温度要过几秒甚至几分钟才跟上。一个立即可用的改进是把 X 组扩展成包含时滞的增广矩阵取 X 的当前时刻和前 L 个时刻的观测值拼在一起这样每组样本不仅包含当前信息还包含历史信息CCA 学到的相关性就带上了动态特征。L 取多少合适滞后阶数的选择可以看不同 L 下典型相关系数总和的变化总和开始不再增长时的 L 就是合适的值常见范围是 1 到 5过大的 L 会让 X 组维度膨胀协方差矩阵更快逼近奇异。非线性场景下的备选方案是核 CCAKCCA把两组变量映射到高维特征空间后再做 CCA适合强非线性耦合的工况。但 KCCA 的核矩阵是 N×N 维样本量几千时计算和存储都吃力小样本反而有优势。两个方案实际项目里要根据数据量和非线性程度决定如果流程本身机理清楚、滞后明显优先动态 CCA只有真心找不到线性相关结构时再上核方法。报警之后的故障定位可以靠贡献图完成。CCA 的 Q 统计量超限时将残差矩阵 res 回映射到原始变量空间计算每个变量对 Q 的贡献率贡献率显著偏高的变量就是异常来源。原理上Q 是残差平方和逐变量拆开即得贡献不需要额外训练模型。最后一线时需要注明的边界贡献图解决的是“哪个测点指向故障”不是“什么故障”进一步的故障类型识别还要依赖历史故障样本作为标签用分类器或者规则库来完成。故障检测里 CCA 的价值不在“比所有方法都准”而在“比别人早一步看到相关性的变化”。小样本、强耦合、机理清晰的场景是它的主场。评估一个 CCA 模型是否合格最后看三件事正常样本的 T² 和 Q 是否稳定、故障注入样本是否在阈值附近有明显抬升、贡献图给出的变量指向是否符合工艺常识——前两条决定能不能用第三条决定现场敢不敢信。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进