去年Q3苏州一家做注塑机的工厂找到我们。他们产线上有大约60台注塑机每台设备装了3个振动传感器和2个温度探头采样频率1kHz。老板的要求很简单能不能在这些机器坏之前告诉我但这里有个关键问题——他们过去三年几乎没有记录任何故障数据。不是不记是故障太少了。一年也就三四次而且每次故障类型还不一样有时候是螺杆磨损有时候是加热圈烧了有时候干脆是模具的问题。这就是预测性维护里最典型的场景没有足够的故障样本做监督学习只能上异常检测。过去两年我在不同行业折腾了七八个类似项目把市面上主流的5种异常检测方法都试了一遍今天来聊聊真实的使用体验。方法一3σ统计法——最简单的也是最容易被低估的说实话我刚开始做异常检测时根本看不起3σ法。觉得这也太土了算个均值和标准差就完事了但后来被现实教育了。去年在浙江一家做轴承的工厂我们用3σ法做了一版基线监控。逻辑非常简单取设备正常运行时的振动RMS值假设它服从正态分布超过 μ3σ 就报警。结果上线第一周就逮住了一台润滑不良的磨床——轴承温度缓慢攀升RMS值从正常的0.8g一路涨到1.6g远超3σ上限。import numpy as np import pandas as pd def three_sigma_detector(data, window1000): 滑动窗口3σ异常检测 data: 正常工况下的振动RMS序列训练数据 mu np.mean(data) sigma np.std(data) upper mu 3 * sigma lower mu - 3 * sigma def predict(new_value): if new_value upper or new_value lower: return 1, (upper, lower, mu) return 0, (upper, lower, mu) return predict, upper, lower, mu # 实际使用 train_rms df_normal[vib_rms].values detector, up, low, mu three_sigma_detector(train_rms) is_anomaly, bounds detector(1.6) print(f异常{is_anomaly}, 上限{up:.2f}, 当前值超出{(1.6-up)/up*100:.0f}%)踩坑提醒3σ法对数据分布要求严格。那次在化工厂测泵的振动数据根本不是正态分布——设备在不同工况下振动RMS呈现多峰分布。这时候3σ法就废了得用分位数法或者干脆换方法。适用场景监控对象物理特性稳定、工况单一、数据近似正态分布。优点是计算量几乎为零可以在PLC上直接跑。方法二孤立森林——工程交付的万金油如果说3σ法是青铜那孤立森林就是王者。scikit-learn 1.3.2 里的IsolationForest是我在工业现场用过最省心的异常检测算法。它的原理很有意思——不是去学正常数据长什么样而是通过不断随机切分数据空间把那些容易快速被孤立出来的点标记为异常。说白了异常点少且特征值极端用很少的切割次数就能切出来。今年年初在无锡一家做光伏组件的工厂我们给镀膜机做异常检测。特征是镀膜腔体的真空度、温度曲线梯度、气体流量等12个工艺参数。训练数据只有正常工况下的2万条记录。from sklearn.ensemble import IsolationForest import joblib # 用10%污染率训练这很关键后面说原因 model IsolationForest( n_estimators200, contamination0.1, # 预估异常占比 random_state42, n_jobs-1 # 工业数据量大全核跑 ) # 注意训练数据只包含正常工况 model.fit(X_normal) # 推理时注意返回值-1异常1正常 predictions model.predict(X_test) anomaly_idx np.where(predictions -1)[0]这里有个我交了学费才搞清楚的细节contamination这个参数不是随便设的。很多人上来就填0.011%异常率结果模型过于保守真实故障漏了一大片。我的经验是宁可设高一点0.05-0.1再用人工复核来筛比你漏掉故障强一百倍。另一个争议点很多人觉得孤立森林不需要特征工程。我的观点刚好相反——在工业场景下原始传感器数据直接扔给孤立森林效果很差。必须先做特征提取统计特征、频域特征给模型喂有物理意义的东西这才是正道。方法三单类SVMOne-Class SVM——理论上完美实际上让人头疼One-Class SVM 在学术界被吹得很高。用核函数把正常数据映射到高维空间找一个超球面包住它们落在球外的就是异常。数学上很漂亮。但在工程上有两个让人崩溃的问题第一核函数选型像个玄学。RBF核配不同的gamma值结果能差一个数量级。我去年在调试一个机床主轴监测项目时gamma从0.01调到10F1-score从0.3跳到0.85没有规律可循纯靠穷举。第二大数据量下慢得离谱。2万条数据One-Class SVM训练了将近40分钟对比孤立森林只要8秒。更狠的是预测阶段也很慢——每来一个新样本都要和支持向量算距离对实时性要求高的场景根本不行。from sklearn.svm import OneClassSVM # 踩坑nu参数控制允许多少正常样本被误判为异常 # 设太低→模型太紧→正常工况也报警大量误报 # 设太高→模型太松→真故障漏掉了 model OneClassSVM( kernelrbf, nu0.01, # 别超过0.05否则漏报率飙升 gamma0.1 # 这个最玄学建议用grid search ) model.fit(X_normal)一句话评价如果你的数据量在5000条以内且你对核函数参数调优有耐心One-Class SVM可以考虑。否则别跟自己过不去。方法四LOF局部离群因子——处理多工况的神器LOF的全称是Local Outlier Factor核心思想是一个点的异常程度取决于它周围邻居的密度。如果这个点的局部密度远低于它的邻居它就是异常。你用通俗的话理解你在你们小区月薪5万周围邻居都月薪3-5万你不异常。但如果你在鹤岗周围邻居月薪2000你就成了异常——这就是LOF的局部二字的意义。在工业场景里LOF最大的价值是处理多工况切换。很多设备不是24小时满负荷跑的——白天高速、晚上低速、换产品型号还要停一会。全局方法比如3σ看到低速运转就觉得异常了但LOF只看局部邻域能区分同工况下的异常偏离和不同工况间的正常切换。from sklearn.neighbors import LocalOutlierFactor # LOF训练和预测一步完成和新数据对比要分开做 lof LocalOutlierFactor( n_neighbors20, # 邻居数建议取数据集1%-5% contamination0.1, noveltyTrue # 必须设True否则不能predict新数据 ) lof.fit(X_normal) scores -lof.score_samples(X_test) # 分数越高越异常踩过这个坑的人都懂n_neighbors设小了对局部扰动太敏感误报满天飞设大了又退化成了全局检测方法。20是经验值但一定要在验证集上调。方法五自编码器Autoencoder——深度学习派的最爱但要慎用自编码器做异常检测的思路是训练一个网络压缩-重建正常数据正常样本重建误差小异常样本重建误差大。用 PyTorch 2.1 实现很简单import torch import torch.nn as nn class AnomalyAE(nn.Module): def __init__(self, input_dim12): super().__init__() # 编码器12 → 8 → 4 → 2 self.encoder nn.Sequential( nn.Linear(input_dim, 8), nn.ReLU(), nn.Linear(8, 4), nn.ReLU(), nn.Linear(4, 2) ) # 解码器2 → 4 → 8 → 12 self.decoder nn.Sequential( nn.Linear(2, 4), nn.ReLU(), nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, input_dim) ) def forward(self, x): latent self.encoder(x) reconstructed self.decoder(latent) return reconstructed, latent # 训练时只用正常数据MSE作为损失 # 推理时重建误差超过阈值即为异常但说实话自编码器在工业异常检测里的性价比真不高。瓶颈在瓶颈维度选的2你换256维试试重建误差区分度直线下降——因为模型学成了一个恒等映射异常样本也能重建得很好。更坑的是阈值怎么定。99分位数3σ还是在验证集上找最佳F1每个项目的数据都不一样没有普适答案。我在写这段话之前刚做了一个对比实验同一个数据集孤立森林F10.87自编码器F10.79训练时间是孤立森林的20倍。我以前也觉得深度学习一定比传统方法强现在不这么想了。数据量和特征质量决定上限算法选型决定的是下限。最后说两句这篇文章聊了五种方法但我真正的建议就一条从简单的开始。先用3σ法跑个基线再用孤立森林做主力其他方法什么时候用——当你发现前面两个搞不定的时候。别一上来就用深度学习那不是技术进步那是浪费算力。我在实际项目中用得最多的组合是孤立森林作为主力检测器 3σ法做单特征快速监控 LOF处理多工况场景。自编码器只在数据量超过50万条、特征维度超过50维时才考虑。记住异常检测的终极目标不是检测出所有异常而是在你能承受的误报范围内不放过任何一次真正的故障。这两者之间的平衡靠的不是算法而是你对业务的理解。