滚刀状态识别机器学习实战:数据对齐、五类模型选型与避坑指南

发布时间:2026/10/12 14:16:54
滚刀状态识别机器学习实战:数据对齐、五类模型选型与避坑指南 简介基于机器学习的滚刀状态识别项目面向机械加工与智能制造领域的技术人员提供以走刀数据为基础的刀具磨损状态初期、正常、急剧分类方案。项目综合应用一维卷积神经网络1DCNN、LSTM、GRU、SVM、随机森林等主流模型并给出训练集与测试集划分及对应样本数量可用于时间序列分类、特征工程和模型对比学习。压缩包共15个文件以8个Python脚本涵盖数据合并、特征提取、模型训练与测试和4个CSV数据文件为主体另有README文档与示意图整体仅2.54MB结构紧凑易上手。目前已有280人学习/下载。读者可获得完整可运行的模型源码、数据预处理与特征生成思路以及不同算法在同一任务上的效果对比适合作为毕业设计、课程项目或工业状态识别入门参考。1. 滚刀状态识别靠机器学习这本来就是成本倒逼出来的事隧道掘进机刀盘上的滚刀埋在掌子面后方正常磨损之外还有偏磨、崩刃、断裂一旦没提前发现换刀开舱一次就可能让工地停工一两天。滚刀状态识别这个方向要解决的就是把“看不见的磨损”变成“能从传感器信号里算出来的数字”。基于Python的机器学习方案用CNN、LSTM、GRU、SVM、随机森林等模型对振动、推力、扭矩、贯入度这类可测数据建模提前预判滚刀状态减少非计划停机。这篇文章按真实做项目的思路来写数据集怎么整理、五类模型怎么选、参数怎么调、哪些坑会让你反复返工。2. 滚刀状态数据处理把换刀记录与传感器日志对齐成训练样本很多人拿到“源码数据集”之后第一件事就是打开模型文件跑train.py我劝你先忍住。滚刀状态识别数据集里真正难的往往不是模型而是把传感器日志、掘进参数报表、换刀台账三份时间线不一致的数据对齐成一张表。这里先按数据处理流程走一遍每个步骤都直接给出可复现代码。2.1 先读懂数据集三种文件传感器日志、掘进参数、换刀台账这类项目的数据集一般会分成raw和processed两层。raw下面常见的是振动加速度传感器、推进油缸压力、刀盘扭矩、转速的原始记录processed下面可能是已经切好的窗口特征表或npy数组。建议先看特征表的列名和类型再回头对原始数据否则很容易被脏数据带偏。import pandas as pd raw pd.read_csv(raw_data.csv, parse_dates[ts]) print(raw.head()) print(raw[label].value_counts())这里的label字段通常有三种取值normal表示正常wear表示磨损chipped表示偏磨或崩刃。打印标签分布是第一步它会直接决定后面的采样策略和模型目标。如果标签只有正常和磨损两类那就先把二分类做扎实不要强行分成多类标签质量不够的时候多分类只会放大噪声。对齐换刀记录和传感器日志时常见做法是以换刀时间为终点向前取一段持续掘进的数据作为该状态的样本。我一般取换刀前15到30分钟但前提是这段时间刀盘在持续旋转。如果中间有停机换步或拼装管片那段数据要切掉否则模型学到的全是停机段的假信号。replace_log pd.read_csv(replace_log.csv, parse_dates[open_time]) sensor_log pd.read_csv(sensor_log.csv, parse_dates[ts]) def build_samples(cutter_id, before_minutes15): rows replace_log[replace_log[cutter_id] cutter_id] samples [] for _, row in rows.iterrows(): end row[open_time] start end - pd.Timedelta(minutesbefore_minutes) seg sensor_log[(sensor_log[ts] start) (sensor_log[ts] end)] if len(seg) 10: continue samples.append({ cutter_id: cutter_id, sample: seg[[torque, thrust, vibration_rms]].values, label: row[wear_type] }) return samplesbefore_minutes是这里最敏感的参数。换刀时间点如果记录的是“发现问题”的时间那前15分钟的数据已经包含故障特征如果记录的是“实际开舱”的时间那前15分钟可能已经停机了。我在项目里的习惯是先画几条时间序列曲线把换刀时间标进去看看数据在哪个位置断了再决定窗口终点。数据不足10个点就跳过比用零值填充更干净。2.2 滑动窗口切分与特征工程让SVM和随机森林也能吃懂时序CNN和GRU可以直接吃原始序列但SVM、随机森林这些经典模型吃不下变长时间序列。常规做法是把每段样本再切成更小的滑动窗口然后从每个窗口里提取统计特征。时域上重点看均方根、峰值因子、峭度频域上重点看主频幅值和功率谱带能量。from scipy import stats, signal def extract_features(segment): feats {} for col in [torque, thrust, vibration_rms]: x segment[col].values feats[f{col}_rms] np.sqrt(np.mean(x**2)) feats[f{col}_peak] np.max(np.abs(x)) feats[f{col}_kurtosis] stats.kurtosis(x) f, psd signal.welch(x, fs1.0, nperseg64) feats[f{col}_freq_peak] f[np.argmax(psd)] return featsfs1.0在这里对应的数据是重采样到每秒一条的掘进参数。如果你的原始振动采样率是1kHz那建议先对每秒内的振动数据算RMS、峰值、峭度再融合进掘进参数表不要直接拿1kHz原始数据做滑窗几十个通道会让特征维度瞬间爆炸。nperseg64把频谱分辨率压到0.0156Hz对1Hz参数够用高频振动建议放大到256或512否则主频会被平滑掉。特征工程的目的不是堆特征而是让经典模型能理解“磨损产生的冲击特征”。滚刀磨损到中后期后振动RMS和峭度都会明显上升推进力波动也会增大。如果你的特征表里只有均值那大概率会丢掉这些关键信息。2.3 类别不平衡与归一化换刀记录少样本别浪费滚刀数据集里正常样本永远是多数偏磨和崩刃的记录可能只有几十条。这时候直接训练随机森林或者SVM模型会倾向把所有样本判成正常。常见的处理是先看类别分布再做分层采样保证每一类都进入验证集。少数类样本太少时可以做三倍以内的SMOTE过采样超过三倍就会在特征空间生成大量相似假样本模型在真实数据上反而更差。from sklearn.preprocessing import RobustScaler from sklearn.model_selection import train_test_split scaler RobustScaler(quantile_range(5, 95)) X_scaled scaler.fit_transform(feature_matrix) split_idx int(len(X_scaled) * 0.8) X_train, X_val X_scaled[:split_idx], X_scaled[split_idx:] y_train, y_val labels[:split_idx], labels[split_idx:]用RobustScaler而不是StandardScaler是因为振动和扭矩数据里有大量切削冲击造成的离群值均值和方差归一化会被离群值带偏。quantile_range(5, 95)等于去掉了两端最极端的冲击值影响。这里一定要按时间顺序划分不要随机打乱原因后面避坑章节会展开。处理完的特征表和标签建议保存成npy或npz同时把每个样本对应的刀号也存下来。np.savez(processed_data.npz, XX_scaled, ylabels, cutter_idscutter_ids)cutter_ids用于后面按刀号分组划分训练验证集这是滚刀项目里防止标签泄漏的关键。3. 从SVM到GRU五类滚刀状态识别模型的选型与最小实现模型选型不是越深越好而是看数据量。滚刀状态项目一般只有几百到几千条样本这个规模下SVN和随机森林是稳定的baselineCNN、LSTM、GRU则有可能在样本充足时带来额外提升。下面给出每种模型的最小实现和关键参数。3.1 SVM和随机森林有特征工程就能打的baseline如果特征工程做得到位随机森林往往比深度学习更好用。原因很简单滚刀数据的特征是数值型、维度不高而随机森林对非线性关系和高阶特征组合都很敏感。SVM则适合在小样本下找边界但需要用交叉验证调C和gamma。from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report svm SVC(C1.0, kernelrbf, gammascale, class_weightbalanced, probabilityTrue) svm.fit(X_train, y_train) rf RandomForestClassifier( n_estimators500, max_depth10, min_samples_leaf5, class_weightbalanced, random_state42, n_jobs-1 ) rf.fit(X_train, y_train) print(classification_report(y_val, rf.predict(X_val)))SVM的probabilityTrue要开因为后面做模型融合时会用到预测概率。C值不要给太大滚刀数据特征冗余度高较大的C会让模型在个别样本上过度拟合。随机森林的max_depth10是我在滚刀数据集上的常用值太深的树容易记住个别磨损冲击事件min_samples_leaf5让叶子节点不至于太纯。3.2 CNN一维卷积直接吃原始振动序列CNN处理一维振动信号是自然选择。与二维图像不同这里输入形状是(batch, channels, length)。第一层卷积核大小建议设置得比较大让它能覆盖滚刀滚过岩石的几个旋转周期。import torch import torch.nn as nn class CutterCNN(nn.Module): def __init__(self, n_channels3, n_classes3): super().__init__() self.backbone nn.Sequential( nn.Conv1d(n_channels, 32, kernel_size64, stride2, padding32), nn.BatchNorm1d(32), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(32, 64, kernel_size3, padding1), nn.BatchNorm1d(64), nn.ReLU(), nn.AdaptiveAvgPool1d(1) ) self.head nn.Linear(64, n_classes) def forward(self, x): feat self.backbone(x).squeeze(-1) return self.head(feat)kernel_size64对应1kHz采样下的0.064秒能覆盖一个旋转冲击事件。如果采样率只有10Hz建议把第一层卷积核降到8~16否则感受野过大等于直接把整个窗口拉平。AdaptiveAvgPool1d(1)让模型可以接受不同长度的输入验证窗口长度时不需要改网络结构。训练循环里需要关注的是输入数据的形状。Conv1d要求输入是(B, C, L)但很多数据集保存成(B, L, C)不转置会直接报维度错。def train_epoch(model, loader, optimizer, loss_fn): model.train() total_loss 0 for xb, yb in loader: xb xb.permute(0, 2, 1) # (B, L, C) - (B, C, L) optimizer.zero_grad() out model(xb) loss loss_fn(out, yb) loss.backward() optimizer.step() total_loss loss.item() return total_loss / len(loader)permute(0, 2, 1)这行非常重要特别是从pandas DataFrame转出来的数组默认是(B, L, C)顺序。损失函数用CrossEntropyLoss标签要从字符串映射成0,1,2的整数否则会卡在loss计算上。3.3 LSTM与GRU记住磨损的累积过程滚刀磨损不是瞬间发生的而是随掘进累积的过程。LSTM和GRU这类循环模型的优势在于能捕捉时序上的渐变。在滚刀项目上我首选GRU它比LSTM少一个门参数更少在几百级样本上更不容易过拟合。class CutterGRU(nn.Module): def __init__(self, n_inputs3, hidden_size64, n_classes3): super().__init__() self.gru nn.GRU( input_sizen_inputs, hidden_sizehidden_size, num_layers2, batch_firstTrue, dropout0.3 ) self.head nn.Linear(hidden_size, n_classes) def forward(self, x): out, _ self.gru(x) return self.head(out[:, -1, :])输入形状是(B, L, C)和CNN正好相反所以batch_firstTrue必须设置。dropout0.3只对两层GRU之间的层间连接生效如果你只用单层GRU这个参数等于没用别被表面数字骗了。序列长度我一般固定成200到500步如果数据是10Hz采样200步就是20秒足够覆盖多次滚刀旋转冲击。LSTM替换成nn.LSTM即可其余代码一样。实际使用时如果loss不降第一件事检查输入数据是否归一化到了(-1,1)附近GRU的tanh和sigmoid激活对数值范围非常敏感。第二件事检查是不是把字符串标签直接传给了CrossEntropyLoss这会让损失函数尝试把字符串转成张量然后报错。3.4 多模型对比的评判口径别只用准确率滚刀状态识别里漏报一次偏磨可能导致滚刀断裂甚至刀盘受损代价远高于误报。所以评判模型时要把“偏磨/崩刃”当成重点类单独看召回率不能只看准确率。准确率在不平衡数据下几乎没有参考价值。from sklearn.metrics import f1_score from sklearn.metrics import precision_recall_fscore_support pred rf.predict(X_val) print(Macro F1:, f1_score(y_val, pred, averagemacro)) print(precision_recall_fscore_support( y_val, pred, labels[normal, wear, chipped]))关注“wear”和“chipped”两个类别的召回率。如果chipped的召回率低于0.7先不要急着换模型回头看看是不是训练样本里这类样本太少或者特征里没有包含能区分崩刃的频段信息。我见过训练F1接近0.95、验证F1只有0.6的情况后来发现验证集和训练集来自不同岩层模型学到的是岩层特征而不是磨损特征。4. 滚刀状态识别避坑五个让我半夜回工地的翻车现场这一章写的都是我做滚刀状态识别项目时真实踩过的坑每一条都是“现象→原因→解决”的顺序。希望你能绕开。4.1 采样频率不一致特征维度对不上现象训练代码跑得好好的换一批传感器数据后直接报维度不匹配。原因不同班次、不同刀位使用的采样率不一样有的振动传感器是1kHz有的是512Hz。按固定点数切窗后每个窗口的特征数量又相同但不同窗口对应的时间长度不一样导致模型学到的时间尺度完全错乱。解决第一时间重采样到统一频率。高频振动按秒聚合时不要用线性插值要用scipy.signal.resample做频域重采样能把冲击特征保留下来。from scipy import signal def resample_to_fs(data, old_fs, target_fs1000): target_len int(len(data) * target_fs / old_fs) return signal.resample(data, target_len)重采样后再做滑窗特征提取。这个步骤必须放在数据读取之后、任何特征工程之前不是可选操作。4.2 随机划分训练验证标签泄漏现象验证集F1达到0.97模型一上现场立刻失灵。原因用了train_test_split(shuffleTrue)同一把滚刀换刀前15分钟的样本被同时分到训练集和验证集模型只是背下了这段掘进参数并没有学到磨损特征。解决按刀号分组划分保证同一把刀的数据只出现在一边。from sklearn.model_selection import GroupShuffleSplit gss GroupShuffleSplit(n_splits1, test_size0.2, random_state42) train_idx, val_idx next(gss.split(X_scaled, labels, groupscutter_ids))groups参数要传每个样本对应的刀具编号或环号。如果数据集里没有这个字段也要至少按时间顺序切分让验证集全是换刀前最后几环的数据。4.3 把岩层/工况差异当成了磨损差异现象模型在微风化岩层上识别偏磨很准换到全风化岩层准确率掉到一半。原因振动、推力同时受岩层和磨损影响模型学到的可能是岩层分类器而不是磨损分类器。解决把掘进速度、贯入度、刀盘转速作为特征一起输入而不是只靠振动。更严格的做法是把环号或地层信息作为group做跨地层验证。如果某个地层的chipped样本太少就合并成“非正常”二分类顽强保留一个可用模型。4.4 类别不平衡盲上SMOTE少数类反而更虚现象偏磨样本只有30条SMOTE扩到300条后验证F1从0.5涨到0.68但现场测试漏报反而更多。原因SMOTE在特征空间线性插值对振动冲击这类特征容易生成“中间态”样本既不像正常也不像偏磨模型学到的边界是假的。解决先做欠采样把正常类压到少数类的2倍以内或者只在SVM上试SMOTE。深度学习模型更推荐直接设置class_weight或给DataLoader配一个WeightedRandomSampler不要过度依赖插值增强。4.5 推理速度快但实时性假象现象模型单次推理只要5毫秒部署到在线系统后数据不停积压。原因在线识别按0.5秒滑动一次窗口每次要重新读过去几十秒的原始序列、重新做滤波和特征计算。预处理耗时远超模型本身。解决在线管线里用环形缓存保存历史数据每个新样本只更新增量统计量而不是重新计算整个窗口。用collections.deque(maxlenwindow_length)缓存原始序列最实用。窗口重叠时只对新增部分做计算能省下80%的预处理时间。5. 进阶技巧模型融合与阈值校准把漏报率再压一个点滚刀状态识别里单一模型很难同时做到高召回和高精确率。一个常用做法是把SVM、随机森林、GRU的概率输出拼起来再交给一个逻辑回归做融合层也就是简单的stacking。关键点在于融合用的验证概率必须通过交叉验证生成不能直接用训练集上的预测值否则会把模型的过拟合直接传给融合层。from sklearn.linear_model import LogisticRegression prob_svm svm.predict_proba(X_val_feat) prob_rf rf.predict_proba(X_val_feat) prob_gru gru_predict_proba(X_val_seq) # 返回(n, n_classes) stack_feat np.hstack([prob_svm, prob_rf, prob_gru]) meta_clf LogisticRegression(C1.0, max_iter500) meta_clf.fit(stack_feat, y_val)这里三个模型要分别做交叉验证得到“干净”的概率否则融合层会过拟合。C1.0是常规起点融合特征维度不高不需要特别强的正则化。阈值校准则比融合更实用。默认分类是取概率最大的类别但漏报偏磨的代价远大于误报我会把“偏磨/崩刃”类的判定阈值从0.5下调到0.3然后要求连续3个滑动窗口都预测为同一状态才触发告警用时间滤波挡掉偶发冲击。这样的代价是偶尔多报一次换刀检查但换来的是不会漏掉真正的偏磨。最后说一个我自己的习惯每次调完参都不只看F1而是单独把混淆矩阵打印出来盯住“正常被误判成偏磨”和“偏磨被误判成正常”两个格子。指标会骗人但这两类错误在换刀成本表上写得清清楚楚。希望这篇笔记能帮你在滚刀状态识别方向上少走一段弯路。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询