第四节:数据采集与预处理——从车间到模型的“第一公里”

各位同行,今天咱们聊聊数据。做烧结收缩率预测,说白了就是“用历史数据预测未来”。但车间里的数据,可不是实验室里那么干净。我见过太多人,模型建得花里胡哨,结果一跑就崩——问题全出在数据上。

这一节,我把自己踩过的坑、总结的经验,全盘托出。你想想看,如果数据不准,再牛的算法也是白搭。

4.1 历史生产数据收集——别嫌麻烦,这是地基

数据收集,听起来简单吧?不就是把生产记录导出来嘛。但我在项目里遇到过,有的工厂连“烧结温度”都记不全,更别说“升温速率”这种细节了。

我个人习惯,数据收集要覆盖这三大类:

  • 原材料数据:粉末牌号、粒度分布、松装密度、化学成分(比如碳含量、氧含量)。
  • 工艺参数:压制压力、保压时间、烧结温度曲线(升温段、保温段、降温段)、气氛类型(氢气、氮气、真空)。
  • 成品检测数据:烧结后的尺寸(长、宽、高、内径)、密度、硬度、金相组织。

嗯,这里要注意:数据的时间跨度最好超过3个月,覆盖不同季节、不同批次。为什么?因为车间温湿度会影响粉末流动性,进而影响收缩率。我吃过这个亏,夏天和冬天的数据混在一起,模型直接“懵了”。

核心原则:数据量不是越多越好,而是“全”且“准”。至少500条以上,每条记录都要有完整的工艺链。

4.2 数据清洗——把“垃圾”筛出去

数据拿到手,第一件事不是建模,而是“洗菜”。车间数据里,什么妖魔鬼怪都有。

4.2.1 异常值处理——别让一个坏点带偏整个模型

我曾经遇到一批数据,收缩率突然从1.2%跳到了3.5%。查了半天,原来是操作工把“烧结温度”写成了“炉膛温度”——差了200度!

我常用的方法:

  • 3σ原则:超出均值±3个标准差的数据,标记为异常。适用于正态分布的数据。
  • 箱线图法:用IQR(四分位距)判断。低于Q1-1.5*IQR或高于Q3+1.5*IQR,视为异常。
  • 业务规则:比如“烧结温度低于1000℃”或“收缩率超过5%”,直接人工复核。

举个例子,我处理过一批铁基粉末的数据:

import pandas as pd
import numpy as np

# 假设df是数据框,'shrinkage'是收缩率列
Q1 = df['shrinkage'].quantile(0.25)
Q3 = df['shrinkage'].quantile(0.75)
IQR = Q3 - Q1

# 定义异常值边界
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 标记异常值
df['is_outlier'] = (df['shrinkage'] < lower_bound) | (df['shrinkage'] > upper_bound)

# 查看异常值
print(df[df['is_outlier']])

注意:别一棍子打死所有异常值。有些“异常”其实是新工艺试产的数据,反而有价值。我建议先标记,再人工确认。

4.2.2 缺失值填充——别让“空”变成“错”

车间记录本上,经常有空白。比如“保压时间”没填,“密度”没测。怎么办?

我的处理策略:

  • 删除法:如果缺失率超过30%,直接删掉该特征或该样本。别心疼,留着也是祸害。
  • 均值/中位数填充:适用于数值型特征,比如“烧结温度”缺失,用同批次均值补上。
  • 前向/后向填充:适用于时间序列数据。比如“炉温”每隔1秒记录一次,中间缺失了,用前一个值补。
  • 模型预测填充:用其他特征(如压制压力、粉末粒度)预测缺失值。这个方法最准,但计算量大。

我记得有一次,一个客户的数据里“氧含量”缺失了40%。我直接用“粉末牌号+存储时间”做了个线性回归模型来预测,效果还不错。

4.3 特征工程——从原始数据里“挖金子”

数据洗干净了,但原始特征还不够。比如“烧结温度曲线”是一个序列,你不能直接把1000个温度点扔进模型。得提炼出有物理意义的特征。

4.3.1 温度曲线特征——把“形状”变成数字

温度曲线,说白了就是“升温-保温-降温”三段。我习惯提取这些特征:

  • 升温速率:从室温到保温温度的斜率。单位℃/min。速率太快,粉末内部气体来不及排出,容易鼓包。
  • 保温时间:在最高温度停留的时长。单位min。时间越长,收缩越充分,但晶粒也会长大。
  • 降温速率:从保温温度到出炉温度的斜率。单位℃/min。冷却太快,容易产生内应力。
  • 最高温度:曲线峰值。这个不用多说,直接影响液相烧结的程度。
  • 曲线下面积:积分后的总热量。相当于“热输入总量”。

举个例子,我处理过一组316L不锈钢粉末的数据:

# 假设temp_curve是温度曲线列表,time是时间列表
import numpy as np

# 计算升温速率(前30%的数据)
heating_segment = temp_curve[:int(len(temp_curve)*0.3)]
heating_rate = (heating_segment[-1] - heating_segment[0]) / (time[int(len(time)*0.3)] - time[0])

# 计算曲线下面积(梯形积分)
area = np.trapz(temp_curve, time)

print(f"升温速率: {heating_rate:.2f} ℃/min")
print(f"曲线下面积: {area:.2f} ℃·min")

4.3.2 密度特征——从“压坯密度”到“烧结密度”

密度是收缩率的“晴雨表”。我一般提取这几个:

  • 压坯密度:压制后的密度。单位g/cm³。压坯密度越高,烧结收缩率越小(因为已经比较密实了)。
  • 烧结密度:烧结后的密度。这个直接测量。
  • 相对密度:烧结密度/理论密度。理论密度可以从粉末成分查表得到。
  • 密度增量:烧结密度 - 压坯密度。这个值越大,说明收缩越剧烈。

小技巧:如果压坯密度数据缺失,可以用“压制压力+粉末粒度”来估算。我做过一个简单模型,R²能达到0.85以上。

4.3.3 成分特征——别小看那0.1%的差异

粉末成分,哪怕差0.1%,收缩率都可能天差地别。我重点关注:

  • 主要元素含量:比如Fe、Cu、Ni、C。这些是骨架元素。
  • 微量元素:比如P、S、O。P能促进液相烧结,但多了会脆;O多了会氧化。
  • 粒度分布:D10、D50、D90。细粉多,收缩率大;粗粉多,收缩率小。
  • 形状因子:球形粉 vs 不规则粉。球形粉流动性好,但收缩率相对稳定。

我曾经遇到一个案例:两批粉末,成分几乎一样,但收缩率差了0.3%。查了半天,发现是“碳含量”差了0.05%。别看这0.05%,在烧结过程中,碳会与氧反应生成CO气体,影响致密化。

4.4 知识体系总览——一张图看懂数据预处理

说了这么多,我画了张图,把整个流程串起来。你一看就明白:

数据采集与预处理流程 历史生产数据收集 原材料/工艺/成品 数据清洗 异常值处理 | 缺失值填充 特征工程 温度/密度/成分特征 建模就绪数据 3σ原则 箱线图法 均值填充 模型预测 温度曲线 密度特征 成分特征 数据预处理是建模的“第一公里”,走稳了,后面才快 关键特征一览表 特征类别 典型特征 对收缩率的影响 温度曲线 升温速率、保温时间 速率快→收缩大;时间长→收缩充分 密度特征 压坯密度、相对密度 压坯密度高→收缩小 成分特征 碳含量、粒度D50 碳高→液相多→收缩大;粉细→收缩大

4.5 避坑指南——我踩过的那些坑

最后,分享几个实战教训:

  • 别信“全自动采集”:有一次,客户说数据是系统自动采集的,绝对准。结果我一查,传感器坏了3天,数据全是“25℃”。嗯,手动复核永远不能省。
  • 小心“批次效应”:不同批次的粉末,即使配方一样,收缩率也可能有差异。我建议把“批次号”也作为一个特征,或者做分层采样。
  • 特征不是越多越好:我曾经一口气提取了50个特征,结果模型过拟合得一塌糊涂。后来用PCA降维,只留了10个主成分,反而更准。
  • 数据标准化:温度是1000℃级别,密度是7g/cm³级别,不标准化的话,模型会“偏袒”数值大的特征。我习惯用Z-score标准化。

一句话总结:数据预处理花的时间,至少占整个项目的60%。别急着建模,先把数据伺候好了。数据干净了,模型自然就听话了。


公众号:蓝海资料掘金营,微信deep3321