4. 良率数据清洗与预处理实战

高速光模块的良率数据来自多个环节:光芯片测试、耦合工序、老化(Burn-in)、终测(Final Test)、外观检查等。这些数据往往由不同设备、不同班次、不同格式导出,直接拿来做良率统计或根因分析,结论很容易被脏数据带偏。数据清洗与预处理的目标,就是把“能用的数据”变成“可信、可对齐、可追溯的数据集”,为后续的良率建模、SPC 监控和失效分析提供统一底座。

一、先明确数据对象与字段口径

以一条 400G QSFP-DD 光模块产线为例,典型良率数据表包含以下字段:batch_id(批次号)、sn(模块序列号)、station(工站)、test_time(测试时间)、tx_power_dbm(发射光功率)、rx_sens_dbm(接收灵敏度)、temp_c(测试温度)、result(PASS/FAIL)、fail_code(失效代码)。清洗前必须先确认单位、量纲和判定阈值,例如发射光功率以 dBm 为单位,接收灵敏度以 dBm 为单位,温度以 ℃ 为单位。口径不统一,后面的异常值判断就会失真。

二、异常值识别:不能只看 3σ

光模块参数常呈非正态分布,直接用 3σ 会误杀正常的高性能样本。实战中建议组合使用三类方法:

  • 物理边界法:根据器件规格设定硬边界,如 tx_power_dbm 合理范围设为 [-2, 6] dBm,超出即判为采集异常或单位错误。
  • 统计法:用 IQR(四分位距)识别离群点,Q1-1.5×IQR 与 Q3+1.5×IQR 之外视为可疑;对近似正态的参数可辅以 Z-score。
  • 业务规则法:同一 SN 在同一工站重复出现、测试时间早于上一工站、FAIL 却无 fail_code,都属于逻辑异常。

识别出异常后不要直接删除,应先打标签。例如新增 outlier_flag 列,标记为 physical、statistical、logic,保留原始值以便追溯。只有确认是采集错误时才剔除,若是真实但极端的良品,应保留并单独分析。

三、缺失值处理:先判断缺失机制

缺失值分三类:完全随机缺失(MCAR)、随机缺失(MAR)、非随机缺失(MNAR)。光模块数据中,rx_sens_dbm 缺失往往是因为该工站未测或测试中断,属于 MNAR,不能简单用均值填充。处理策略如下:

  • 缺失比例 < 5% 且为 MCAR:可删除对应行,或按工站分组用中位数填充。
  • 缺失比例 5%~30%:按 station + temp_c 分组,用组内中位数填充,减少温度带来的偏差。
  • 缺失比例 > 30% 或关键判定字段缺失:不填充,标记为 missing_flag,在良率统计中单独列出。
注意:result 和 fail_code 是良率判定的核心字段,缺失时不能猜测填充,必须回查原始记录或标记为“数据不可用”,否则会直接污染良率分母。

四、数据对齐:时间、SN 与工站三重对齐

同一模块会经过多个工站,每个工站产生一条记录。数据对齐要解决三件事:

  1. SN 对齐:以 sn 为主键,将各工站记录横向合并为一行,形成“模块级”宽表。
  2. 时间对齐:确保 test_time 按工站顺序递增,若出现倒序,说明时间戳异常或数据串批,需要标记。
  3. 批次对齐:同一 batch_id 内的模块应共享相同的物料批次、设备编号和工艺参数,若不一致,需拆分批次或标记为混批。

对齐后建议生成一张“模块级良率宽表”,每行一个 SN,列包含各工站的关键参数和最终结果。这样后续按批次、按工站、按温度区间统计良率时,口径才一致。

五、批次追溯:从良率异常反查到具体环节

批次追溯的核心是建立“批次—工站—设备—物料—时间”的关联链。当某批次良率突然下降时,可以按以下路径反查:先锁定异常批次,再对比该批次在各工站的 FAIL 分布,找出 FAIL 集中的工站;然后查该工站当班使用的设备编号、校准记录和物料批次;最后与相邻正常批次对比,确认是设备漂移、物料差异还是工艺参数偏移。追溯结果应记录到追溯表中,字段包括 batch_id、station、equipment_id、material_lot、fail_code、fail_count、suspected_cause,便于后续闭环。

良率数据清洗与预处理主线(含批次追溯回路) 原始数据 多工站 / 多设备导出 异常值识别 物理边界 / IQR / 业务规则 打标签 outlier_flag 缺失值处理 分组中位数 / 标记 missing_flag 关键字段不猜测填充 数据对齐 SN 主键 / 时间递增 / 批次一致 生成模块级宽表 清洗后可信数据集 每行一个 SN,含各工站参数、结果、异常/缺失标记 良率统计 / SPC 监控 / 根因分析 按批次、工站、温度区间分组 批次追溯回路 ① 锁定异常批次 batch_id ② 定位 FAIL 集中工站 ③ 关联设备 / 物料 / 时间 ④ 对比正常批次确认原因 追溯结果回写 追溯记录表(示例字段) batch_id station equipment_id material_lot fail_code fail_count suspected_cause owner / status (用于闭环跟踪) 关键原则:异常值先打标签再决定去留;缺失值先判断机制再填充;对齐以 SN 为主键、时间为顺序、批次为一致性约束; 追溯必须形成“批次→工站→设备→物料→时间”的闭环,并将结果回写到清洗后的数据集,保证良率结论可复现、可追责。

六、Python/Pandas 实操要点

下面给出一段可直接参考的清洗骨架代码,重点展示异常标记、缺失填充和对齐合并的写法。示例参数为教学假设,实际使用时请替换为产线真实阈值。

import pandas as pd
import numpy as np

# 1. 读取多工站数据
df = pd.read_csv("module_yield_raw.csv", parse_dates=["test_time"])

# 2. 异常值标记:物理边界 + IQR
df["outlier_flag"] = ""
df.loc[(df["tx_power_dbm"] < -2) | (df["tx_power_dbm"] > 6), "outlier_flag"] = "physical"
q1, q3 = df["rx_sens_dbm"].quantile([0.25, 0.75])
iqr = q3 - q1
low, high = q1 - 1.5 * iqr, q3 + 1.5 * iqr
df.loc[(df["rx_sens_dbm"] < low) | (df["rx_sens_dbm"] > high), "outlier_flag"] = "statistical"

# 3. 缺失值处理:按工站分组中位数填充
df["rx_sens_dbm"] = df.groupby("station")["rx_sens_dbm"].transform(
    lambda s: s.fillna(s.median())
)
df["missing_flag"] = df["rx_sens_dbm"].isna()

# 4. 数据对齐:以 SN 为主键,按工站透视
wide = df.pivot_table(
    index=["sn", "batch_id"],
    columns="station",
    values=["tx_power_dbm", "rx_sens_dbm", "result"],
    aggfunc="last"
)
wide.columns = ["_".join(col) for col in wide.columns]
wide = wide.reset_index()

# 5. 批次追溯:统计各批次各工站 FAIL 数
fail_stat = (df[df["result"] == "FAIL"]
             .groupby(["batch_id", "station", "fail_code"])
             .size()
             .reset_index(name="fail_count")
             .sort_values("fail_count", ascending=False))

运行后应重点检查三件事:outlier_flag 是否集中在某些工站或设备;missing_flag 为 True 的记录是否集中在特定时间段;fail_stat 中 fail_count 最高的批次与工站组合,是否与设备校准记录或物料批次变更时间吻合。若吻合,即可进入根因确认;若不吻合,说明清洗口径或对齐逻辑仍需修正。

建议把清洗规则固化为可复用的函数或配置文件,例如将物理边界、IQR 系数、分组填充字段写入 YAML,每次换线或换型号时只改配置,不改代码,保证不同批次之间的清洗口径一致。

数据清洗不是一次性动作,而是伴随良率分析持续迭代的过程。每发现一类新的异常模式,就应把它转化为一条明确的清洗规则,并记录到数据质量日志中。只有这样,后续的良率对比、趋势监控和根因定位才建立在同一套可信数据之上。