3. 数据采集与预处理:传感器数据采集、MES系统数据导出、数据清洗
各位同学,咱们直接进入正题。质量检测的数据挖掘,说白了就是「垃圾进,垃圾出」。你模型再牛,数据源头是脏的,结果一定翻车。这一章我重点讲数据怎么来、怎么导、怎么洗。都是我在车间里踩过的坑,你们拿笔记一下。
3.1 传感器数据采集——别小看这根线
传感器数据采集,听起来高大上,其实核心就三件事:频率、精度、同步。
我在一家汽车零部件厂遇到过这么个事。产线上装了一批振动传感器,用来监测主轴状态。结果采集上来的数据,波形全是毛刺。查了两天,最后发现是信号线没做屏蔽,跟旁边的变频器串扰了。嗯,硬件上的坑,往往比软件更隐蔽。
采集频率怎么定?我个人习惯遵循奈奎斯特采样定理:采样频率至少是信号最高频率的两倍。但实际项目中,我一般取 5~10 倍。为什么?留余量。你想想看,万一信号有高频噪声,刚好卡在 2 倍上,混叠效应会让你完全看错波形。
| 传感器类型 | 典型采样率 | 常见问题 |
|---|---|---|
| 温度(热电偶) | 1~10 Hz | 响应慢,注意滤波 |
| 振动(加速度计) | 1~10 kHz | 高频噪声多,需抗混叠滤波 |
| 压力(应变片) | 100~1000 Hz | 零点漂移,需定期校准 |
| 视觉(工业相机) | 30~200 fps | 数据量大,注意存储带宽 |
采集到的原始数据,我建议直接存成时间戳 + 数值的格式。别搞花里胡哨的压缩,后期清洗时你会感谢我的。
3.2 MES系统数据导出——跟IT部门打好交道
MES(制造执行系统)里的数据,才是质量分析的「正主」。但说实话,从MES导数据,技术难度不高,沟通成本极高。
我记得有一次,需要导出某条产线过去三个月的检验记录。IT 小哥给我导了个 CSV,打开一看,字段名全是中文缩写,什么「CPK」「LSL」「USL」混在一起,还有一堆空行。我问他有没有数据字典,他说「没有,你自己猜」。唉,这种事太常见了。
导出时,我建议你注意以下几点:
- 明确时间范围:别导全量,除非你硬盘不要钱。按批次或按日期分段导出。
- 确认字段含义:拿到数据后,先跟工艺工程师对一遍字段。尤其是「检验结果」这类字段,是 0/1 还是 Pass/Fail,还是数值范围?
- 保留原始记录:导出的数据不要直接修改原表。我习惯建一个
raw_data文件夹,每次导出都加时间戳命名。
SELECT * FROM inspection_records WHERE batch_id = 'B20240301' AND create_time >= '2024-01-01'
3.3 数据清洗——脏活累活,但最见功力
数据清洗,占整个数据挖掘工作量的 60%~80%。别嫌烦,这一步做不好,后面全是白费。
3.3.1 缺失值处理
缺失值怎么来的?传感器断线、MES 漏录、人工录入时跳过……原因很多。处理方式我分三种情况:
- 直接删除:如果缺失比例小于 5%,且是随机缺失,直接删行。简单粗暴,但有效。
- 填充:连续型数据,我用中位数填充(比均值更抗异常值)。离散型数据,用众数填充。
- 插值:时间序列数据,比如温度曲线,我用线性插值或前向填充。我曾经处理过一个炉温数据,中间有 10 分钟断档,用前后 5 分钟的平均值插补,效果还不错。
import pandas as pd
import numpy as np
# 读取数据
df = pd.read_csv('sensor_data.csv')
# 查看缺失情况
print(df.isnull().sum())
# 方式1:删除缺失比例小的列
df.dropna(thresh=len(df)*0.95, axis=1, inplace=True)
# 方式2:中位数填充连续型特征
df['temperature'].fillna(df['temperature'].median(), inplace=True)
# 方式3:时间序列前向填充
df['vibration'].fillna(method='ffill', inplace=True)
3.3.2 异常值处理
异常值,说白了就是「明显不对劲」的数据。比如一个零件尺寸要求 10±0.1mm,结果测出来 15mm,那肯定是异常。
我常用的检测方法:
- 3σ 原则:数据服从正态分布时,超过均值 ±3 倍标准差的值视为异常。适合大多数工业场景。
- IQR 方法:四分位距法,不依赖正态分布。超过 Q1-1.5IQR 或 Q3+1.5IQR 的值视为异常。适合偏态分布。
- 业务规则:这个最靠谱。比如设备最高转速 3000 rpm,超过的直接标红。我在项目中经常把业务规则放在第一位,统计方法只是辅助。
# 3σ 方法
mean = df['size'].mean()
std = df['size'].std()
df['is_outlier_3sigma'] = (np.abs(df['size'] - mean) > 3 * std)
# IQR 方法
Q1 = df['size'].quantile(0.25)
Q3 = df['size'].quantile(0.75)
IQR = Q3 - Q1
df['is_outlier_iqr'] = (df['size'] < Q1 - 1.5*IQR) | (df['size'] > Q3 + 1.5*IQR)
# 业务规则:尺寸公差 ±0.5
df['is_outlier_rule'] = (df['size'] < 9.5) | (df['size'] > 10.5)
处理异常值时,我建议先标记,再处理。别直接删。为什么?因为有些异常值其实是「故障前兆」,删了就丢了重要信息。我曾经在轴承振动数据里发现一组异常值,车间老师傅说「这是快要坏了」,后来果然停机了。从那以后,我处理异常值都留个心眼。
1. 先跑业务规则,标记明显异常
2. 再用 IQR 或 3σ 辅助检测
3. 异常值先置为 NaN,统一走缺失值处理流程
4. 保留原始数据副本,方便回溯
3.4 实战小贴士——数据预处理 checklist
最后,给你们一个我在项目里用的 checklist。每次拿到新数据,按这个过一遍:
- 数据量有多大?行数、列数、内存占用。
- 有没有重复行?有的话去重。
- 各字段数据类型对不对?比如时间列是不是 datetime 类型。
- 缺失值分布如何?画个热力图看看。
- 异常值有没有?画箱线图或散点图。
- 数据分布是否合理?画直方图,看有没有离谱的峰值。
嗯,这一章内容不少。数据采集和预处理,听起来枯燥,但做多了你会发现,真正的高手不是在建模上炫技,而是在数据清洗上稳得住。下一章咱们讲特征工程,到时候你们就知道,数据洗得干净,特征工程做起来有多顺手。