ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Python机器学习实战:盾构机滚刀状态识别源码全解析

Python机器学习实战:盾构机滚刀状态识别源码全解析 简介这份资源面向机械加工与智能制造方向的学生及工程师提供一套基于机器学习的滚刀状态识别完整项目可用于毕业设计、课程大作业或期末项目。项目采用CNN、LSTM、GRU、SVM、随机森林等多种模型进行对比实验覆盖数据合并、特征生成、模型训练与测试等环节帮助读者理解从原始振动或工况数据到状态分类的完整流程。压缩包共15个文件包含8个Python源码文件、4个CSV数据集、1个PNG示意图、1个Markdown说明文档及gitignore配置整体约2.63MB结构清晰、便于按模块查阅。目前已有233人学习下载。读者可获得可直接部署运行的源码与配套数据快速复现多模型对比结果并在此基础上调整网络结构或替换分类器适合作为入门机器学习与工业状态识别的实践参考。1. 从一组振动信号说起这套滚刀状态识别源码到底能跑出什么盾构机在掘进时滚刀是不是磨损、是不是偏磨、是不是已经崩刃现场往往靠司机听声音、看推力扭矩曲线去猜。等真出问题停机换刀工期和成本都已经付出去了。这套 Python 基于机器学习的滚刀状态识别项目干的就是把这种靠经验猜变成用模型判——它把采集到的滚刀运行数据整理成 CSV用 CNN、LSTM、GRU、SVM、随机森林五类模型分别训练最后输出滚刀当前处于哪种状态。对做毕业设计、期末大作业或者课程设计的同学来说它最大的价值是数据、特征脚本、训练脚本、测试脚本全都齐了不用自己从零造数据对已经上手机器学习、想找一个完整时序分类落地案例的从业者它也是一份能直接拆开看流程的工程样本。下面我按数据怎么进、特征怎么出、模型怎么训、坑在哪的顺序把这份源码拆一遍。2. 数据管线拆解merge_data.py 与 gen_feature.py 到底做了什么拿到这份源码第一件该做的事不是急着跑 cnn.py而是先把数据从哪来、长什么样搞清楚。项目里 data.csv、data_c1.csv、data_c4.csv、data_c6.csv 这几个文件是核心merge_data.py 和 gen_feature.py 负责把它们变成模型能吃的格式。这一章就把这条管线走通。2.1 原始 CSV 的结构与 merge_data.py 的合并逻辑先看数据文件。data_c1.csv、data_c4.csv、data_c6.csv 从命名看是按类别或按采集批次拆分的原始记录data.csv 更像是合并后的总表。滚刀状态识别本质是时序分类问题每条样本通常是一段连续采样的多通道信号比如振动、电流、扭矩标签是状态类别。merge_data.py 的作用就是把分散的 CSV 拼成一张统一表方便后续统一做特征和切分。常见做法是读入多个 CSV按行拼接再补一列来源标记或标签列。我一般会先确认几件事各文件的列名是否一致、采样率是否相同、标签列叫什么。如果列名不统一直接 concat 会得到一堆 NaN这是新手最容易翻车的地方。import pandas as pd import os # 待合并的原始数据文件按项目实际文件名填写 files [data_c1.csv, data_c4.csv, data_c6.csv] frames [] for f in files: df pd.read_csv(f) # 打上来源标记方便后续追溯每条样本来自哪个批次 df[source] os.path.splitext(f)[0] frames.append(df) # 按列名对齐后纵向拼接ignore_index 重置行号 merged pd.concat(frames, axis0, ignore_indexTrue) merged.to_csv(data.csv, indexFalse) print(合并后形状:, merged.shape) print(列名:, list(merged.columns))这段代码的逻辑很直白逐个读文件、加来源列、纵向堆叠、落盘成 data.csv。参数上要注意axis0表示按行合并ignore_indexTrue避免索引重复。真正需要盯的是pd.concat默认按列名对齐如果某个文件列名多了或少了一列结果会出现整列 NaN。跑完先打印 shape 和 columns确认行数等于各文件之和、列数符合预期再往下走。如果行数对不上八成是某个文件有空行或者分隔符不是逗号。2.2 gen_feature.py 的特征工程与标签构造原始信号直接喂给 SVM、随机森林效果通常一般因为这两个模型不吃原始时序需要手工特征。gen_feature.py 承担的就是这个角色把一段时序窗口转成统计特征向量。CNN、LSTM、GRU 这类深度模型理论上可以吃原始序列但工程上为了统一输入、加快收敛很多实现也会先做归一化或滑窗。时域特征是最常用的一类常见的有均值、标准差、均方根、峰值、峭度、偏度。频域特征则要上 FFT取主频、频谱能量等。下面给一个可复用的特征提取骨架字段名按你数据实际列名替换。import numpy as np import pandas as pd from scipy.stats import kurtosis, skew def extract_features(window): window: 二维数组形状为 (时间步, 通道数) feats {} for ch in range(window.shape[1]): sig window[:, ch] feats[fch{ch}_mean] np.mean(sig) feats[fch{ch}_std] np.std(sig) feats[fch{ch}_rms] np.sqrt(np.mean(sig ** 2)) feats[fch{ch}_peak] np.max(np.abs(sig)) feats[fch{ch}_kurt] kurtosis(sig) feats[fch{ch}_skew] skew(sig) return feats # 假设 data.csv 中前 N 列是信号最后一列是 label df pd.read_csv(data.csv) signal_cols [c for c in df.columns if c not in (label, source)] win_size 128 # 窗口长度按采样率和状态变化周期调整 step 64 # 滑窗步长越小样本越多但重叠越高 rows [] for start in range(0, len(df) - win_size, step): win df[signal_cols].iloc[start:start win_size].values label df[label].iloc[start win_size - 1] # 用窗口末端标签 feat extract_features(win) feat[label] label rows.append(feat) pd.DataFrame(rows).to_csv(features.csv, indexFalse)逻辑说明滑窗把长序列切成固定长度片段每个片段算一组统计量作为一行特征标签取窗口末端对应的状态。参数上win_size决定单个样本覆盖多长时间太小则特征不稳太大则状态切换被抹平step控制样本重叠度步长小于窗口长度能扩增样本但重叠过高会让训练集和测试集信息泄漏。这里有个血泪经验如果先滑窗再随机划分训练测试集同一段信号会同时出现在两边测试准确率虚高得离谱。正确做法是按时间或按采集批次划分这一点后面避坑章节还会展开。2.3 数据归一化与训练测试划分特征量纲差异很大均方根可能是几百峭度可能是个位数直接送进 SVM 会被大数值特征主导。标准化是标配。from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split feat_df pd.read_csv(features.csv) X feat_df.drop(columns[label]).values y feat_df[label].values # 先划分再在训练集上 fit 标准化器避免测试集信息泄漏 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) scaler StandardScaler().fit(X_train) X_train scaler.transform(X_train) X_test scaler.transform(X_test)关键点是fit只能作用在训练集上测试集用同一个 scaler 做transform。很多人图省事对全量数据 fit结果标准化参数里混进了测试集统计量这在答辩时被追问会很难解释。stratifyy保证划分后各类别比例一致类别不均衡时尤其重要。3. 五类模型逐个跑通CNN、LSTM、GRU、SVM、随机森林的输入差异数据管线通了之后就进入模型环节。这份源码把五个模型分开写cnn.py、lstm.py、gru.py 是深度模型SVM 和随机森林大概率在 Ext.py 或单独脚本里。它们对输入形状的要求完全不同这是跑通的关键。3.1 CNN 与 LSTM/GRU 的输入张量重塑CNN 做一维时序分类输入形状通常是(样本数, 时间步, 通道数)LSTM、GRU 也是三维输入但关注的是时间依赖。SVM 和随机森林吃的是二维(样本数, 特征数)。所以同一份数据深度模型要用滑窗后的原始序列传统模型要用统计特征。源码里 cnn.py 和 lstm.py 分开正是因为这个差异。import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout # 假设 X_seq 形状为 (样本数, 时间步, 通道数) X_seq np.load(X_seq.npy) y np.load(y.npy) num_classes len(np.unique(y)) model Sequential([ Conv1D(32, kernel_size3, activationrelu, input_shapeX_seq.shape[1:]), MaxPooling1D(pool_size2), Conv1D(64, kernel_size3, activationrelu), MaxPooling1D(pool_size2), Flatten(), Dense(64, activationrelu), Dropout(0.5), # 抑制过拟合时序小数据集必备 Dense(num_classes, activationsoftmax) ]) model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy]) model.summary()逻辑说明两层 Conv1D 提取局部时序模式池化降维Flatten 后接全连接分类。input_shape必须和你的序列形状严格一致时间步和通道数写反是最常见的报错来源。Dropout(0.5)在小数据集上很关键滚刀状态样本往往不多不加 dropout 训练集准确率能到 99%测试集却惨不忍睹。LSTM 和 GRU 把 Conv1D 换成对应的循环层即可GRU 参数比 LSTM 少训练更快小数据上经常表现不差。3.2 SVM 与随机森林的特征输入与调参传统模型这边输入是 features.csv 里的二维特征矩阵。SVM 用 RBF 核随机森林用树集成两者调参重点不同。from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report # SVMC 控制惩罚gamma 控制核宽度 svm SVC(kernelrbf, C10, gammascale, probabilityTrue) svm.fit(X_train, y_train) print(SVM:\n, classification_report(y_test, svm.predict(X_test))) # 随机森林n_estimators 树数量max_depth 控制复杂度 rf RandomForestClassifier(n_estimators200, max_depthNone, random_state42) rf.fit(X_train, y_train) print(RF:\n, classification_report(y_test, rf.predict(X_test)))参数说明SVM 的C越大越容易过拟合gamma越大决策边界越复杂小数据集建议先用gammascale再网格搜索。随机森林的n_estimators到 200 左右通常收益递减max_depthNone让树长满配合min_samples_leaf控制过拟合更有效。classification_report会给出每类的精确率、召回率、F1比只看一个 accuracy 有用得多——滚刀状态如果某类样本少accuracy 高但那一类全错的情况很常见。3.3 五个模型的横向对比与选型建议跑完五个模型该做的是横向对比而不是挑一个准确率最高的就交差。下面这张表是我按这类项目的常见表现整理的对比维度具体数值以你实际跑出来的为准。模型输入形式训练速度小数据表现可解释性适用场景CNN原始序列三维中等较好低局部模式明显、样本中等LSTM原始序列三维慢一般低长时依赖、序列较长GRU原始序列三维较快一般低与 LSTM 类似但资源紧SVM统计特征二维快好中样本少、特征维度不高随机森林统计特征二维快好高需要特征重要性分析选型上如果样本量只有几百条SVM 和随机森林往往比深度模型更稳训练也快样本上千且序列模式复杂CNN 通常性价比最高。答辩时被问为什么选这个模型用这张表的维度去答比说因为它准确率高有说服力得多。4. 避坑与排查这份源码最容易翻车的五个地方源码能跑通不代表结果可信。这一章列的都是我拆这类项目时真实踩过的坑每条按现象、原因、解决写。4.1 测试准确率异常高接近 100%现象模型在测试集上准确率 99% 以上换一批数据就崩。原因滑窗重叠导致训练集和测试集共享同一段信号信息泄漏。解决按时间顺序或按采集批次划分数据集不要用随机划分如果必须随机划分先按窗口分组再分。4.2 深度模型 loss 不下降或直接 NaN现象cnn.py 或 lstm.py 训练几轮后 loss 变 NaN。原因学习率过大或者输入没归一化数值范围差异太大。解决先把序列做标准化学习率从 1e-3 往下调必要时加梯度裁剪clipnorm1.0。4.3 类别不均衡导致少数类全错现象整体 accuracy 很高但某个滚刀状态的召回率为 0。原因该类样本太少模型倾向于预测多数类。解决用class_weightbalanced或者对少数类过采样评估时重点看 macro F1 而不是 accuracy。4.4 列名或形状不匹配报错现象merge_data.py 合并后出现大量 NaN或模型报 input shape 错误。原因各 CSV 列名不一致或时间步与通道数写反。解决合并前统一列名并打印 columns 核对模型输入前打印X.shape确认是(样本, 时间步, 通道)。4.5 环境依赖版本冲突现象import tensorflow 或 sklearn 报版本相关错误。原因深度学习框架和 numpy、scipy 版本不兼容。解决用虚拟环境隔离先装 numpy 再装框架按 README 提示的版本走别直接 pip install 最新版。提示跑任何模型前先单独跑一遍数据加载和 shape 打印确认数据没问题再训练能省掉一大半排查时间。5. 进阶技巧用交叉验证和混淆矩阵把结论坐实模型跑出个准确率就收工是这类项目最容易被导师问倒的地方。想让结论站得住我一般会补两件事交叉验证和混淆矩阵。交叉验证能看出模型在不同数据划分下稳不稳混淆矩阵能看出到底哪两类状态容易混。import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import StratifiedKFold, cross_val_score from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay # 分层交叉验证每折都保持类别比例 cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) rf RandomForestClassifier(n_estimators200, random_state42) scores cross_val_score(rf, X, y, cvcv, scoringf1_macro) print(5折 macro-F1:, scores.mean(), ±, scores.std()) # 混淆矩阵看具体错分方向 rf.fit(X_train, y_train) cm confusion_matrix(y_test, rf.predict(X_test)) ConfusionMatrixDisplay(cm).plot(cmapBlues) plt.savefig(confusion_matrix.png, dpi150)逻辑说明StratifiedKFold保证每折里各类别比例一致scoringf1_macro对不均衡数据比 accuracy 更敏感scores.std()大说明模型对数据划分敏感结论要谨慎。混淆矩阵能直接告诉你哪两类状态被互相误判如果两个状态在物理上本来就接近那这个错分是可以解释的写进报告反而是加分项。还有一个小技巧随机森林训练完可以直接看特征重要性把排名靠前的特征和物理量对应起来比如某个通道的峭度最重要那它可能正好反映了滚刀磨损时的冲击成分。这一步能把纯数据结论和滚刀工况对上答辩时非常吃香。import pandas as pd importances pd.Series(rf.feature_importances_, indexfeat_df.drop(columns[label]).columns) print(importances.sort_values(ascendingFalse).head(10))从那以后我每次拿到这类时序分类项目都强制先跑一遍交叉验证和混淆矩阵再去看那个孤零零的 accuracy不然很容易被一个虚高的数字骗过去。这套源码的数据、特征、模型脚本都齐按上面的顺序拆一遍基本能把滚刀状态识别这条链路走通。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

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