4. 数据采集与预处理:传感器数据采集、数据清洗、标准化与归一化
在半导体制造中,良率预测模型的性能高度依赖于输入数据的质量。晶圆厂每时每刻都在从数百台工艺设备中采集海量传感器数据,这些原始数据包含缺失值、噪声、异常点以及不同量纲的特征。本章将系统讲解从传感器数据采集到预处理的全流程,确保输入模型的数据干净、一致且可比较。
核心原则:数据预处理不是一次性任务,而是与工艺波动监控同步进行的持续校准环节。预处理质量直接决定模型校准的收敛速度与最终精度。
4.1 传感器数据采集架构
半导体制造中的传感器数据采集通常采用 SECS/GEM(半导体设备通信标准/通用设备模型)协议,从刻蚀、沉积、光刻等设备中实时获取工艺参数。典型采集参数包括:
| 参数类别 | 典型传感器参数 | 采样频率 | 数据量级(单设备/天) |
|---|---|---|---|
| 温度 | 腔体温度、基座温度、壁面温度 | 1–10 Hz | ~500 MB |
| 压力 | 腔体压力、气体分压、泵背压 | 1–5 Hz | ~200 MB |
| 气体流量 | MFC 设定值/实际值、比例阀开度 | 1–10 Hz | ~300 MB |
| 射频功率 | 正向功率、反射功率、阻抗匹配 | 10–50 Hz | ~1 GB |
| 光学发射光谱 | OES 全谱(200–900 nm) | 1–2 Hz | ~2 GB |
下图展示了从传感器到数据湖的典型采集与存储架构:
实战建议:在采集阶段就为每个传感器数据打上时间戳、设备ID、腔体ID和工艺配方ID标签,避免后续溯源困难。推荐使用 Apache Kafka 或类似消息队列缓冲高频数据流。
4.2 数据清洗:缺失值与异常值处理
原始传感器数据中常见的质量问题包括:传感器短暂离线导致的 缺失值、设备跳变或腔体污染导致的 异常值、以及时间戳不同步导致的 对齐偏差。以下表格总结了不同场景下的处理策略:
| 数据问题 | 典型成因 | 处理方法 | 适用场景 |
|---|---|---|---|
| 随机缺失 | 传感器瞬时通信中断 | 线性插值 / 前向填充 | 缺失比例 < 5% |
| 连续缺失 | 设备维护、传感器故障 | 删除该段数据 / 使用配方均值填充 | 缺失比例 > 20% |
| 离群点(3σ 外) | 腔体颗粒、射频打火 | Winsorize 截尾 / 中位数替换 | 工艺稳定阶段 |
| 阶跃异常 | MFC 阀门卡滞、加热器失控 | 基于变化率检测 + 局部插值 | 需保留工艺事件 |
| 时间戳抖动 | 采集时钟不同步 | 重采样至固定频率(如 1 Hz) | 多传感器融合前 |
下图展示了基于 滑动窗口 + 3σ 准则 的异常值检测与处理流程:
避坑提醒:不要对整批数据一次性计算全局均值和标准差来检测异常。工艺配方切换时参数均值会自然漂移,全局统计会将正常切换误判为异常。务必按配方ID分组,在组内使用滑动窗口。
4.3 数据标准化与归一化
传感器参数的量纲差异巨大(例如温度 400°C vs 压力 10 mTorr),直接输入模型会导致梯度更新失衡。标准化和归一化是解决量纲问题的两种核心方法:
| 方法 | 公式 | 输出范围 | 适用模型 | 对异常值敏感性 |
|---|---|---|---|---|
| Z-score 标准化 | \( x' = \frac{x - \mu}{\sigma} \) | 无固定范围(通常 -3 ~ 3) | 线性回归、SVM、PCA | 高(异常值拉偏 μ 和 σ) |
| Min-Max 归一化 | \( x' = \frac{x - x_{min}}{x_{max} - x_{min}} \) | [0, 1] | 神经网络、KNN、K-Means | 高(异常值压缩正常值区间) |
| Robust 标准化 | \( x' = \frac{x - median}{IQR} \) | 无固定范围 | 含异常值的工艺数据 | 低(使用中位数和四分位距) |
| 均值归一化 | \( x' = \frac{x - \mu}{x_{max} - x_{min}} \) | [-1, 1] | 神经网络(tanh 激活) | 中等 |
下图对比了三种标准化方法对同一组含异常值的传感器数据的处理效果:
4.4 预处理管道实战代码
以下 Python 代码片段展示了针对半导体工艺传感器数据的完整预处理管道,包含缺失值处理、异常值检测和 Robust 标准化:
import pandas as pd
import numpy as np
from scipy import stats
def preprocess_sensor_data(df, recipe_col='recipe_id', value_col='value',
window=50, z_thresh=3.0):
"""
半导体传感器数据预处理管道
参数:
df: 原始DataFrame,包含recipe_id, timestamp, value等列
recipe_col: 配方ID列名
value_col: 传感器数值列名
window: 滑动窗口大小
z_thresh: Z-score异常阈值
返回:
df_clean: 清洗后的DataFrame
stats_dict: 预处理统计信息
"""
df_clean = df.copy()
stats_dict = {'total_rows': len(df_clean),
'missing_before': df_clean[value_col].isna().sum(),
'outliers_removed': 0}
# 1. 缺失值处理:按配方分组,组内线性插值
df_clean[value_col] = df_clean.groupby(recipe_col)[value_col].transform(
lambda x: x.interpolate(method='linear', limit_direction='both')
)
# 若仍有缺失(如首尾),使用配方中位数填充
df_clean[value_col] = df_clean.groupby(recipe_col)[value_col].transform(
lambda x: x.fillna(x.median())
)
stats_dict['missing_after'] = df_clean[value_col].isna().sum()
# 2. 异常值检测:滑动窗口Z-score
def detect_outliers_window(series, window, thresh):
outliers = np.zeros(len(series), dtype=bool)
for i in range(window, len(series) - window):
local_data = series.iloc[i - window:i + window + 1]
local_mean = local_data.mean()
local_std = local_data.std()
if local_std > 0:
z = (series.iloc[i] - local_mean) / local_std
if abs(z) > thresh:
outliers[i] = True
return outliers
outlier_mask = df_clean.groupby(recipe_col)[value_col].transform(
lambda x: detect_outliers_window(x.reset_index(drop=True), window, z_thresh)
)
stats_dict['outliers_removed'] = outlier_mask.sum()
# 异常值替换为局部中位数
df_clean.loc[outlier_mask, value_col] = (
df_clean.groupby(recipe_col)[value_col]
.transform(lambda x: x.rolling(window=window, center=True, min_periods=1).median())
.fillna(method='bfill').fillna(method='ffill')
)
# 3. Robust 标准化(按配方分组)
def robust_scale_group(group):
median = group.median()
iqr = group.quantile(0.75) - group.quantile(0.25)
if iqr == 0:
iqr = 1.0 # 避免除零
return (group - median) / iqr
df_clean[value_col + '_scaled'] = (
df_clean.groupby(recipe_col)[value_col].transform(robust_scale_group)
)
return df_clean, stats_dict
# 使用示例
# df_raw = pd.read_parquet('sensor_data.parquet')
# df_clean, stats = preprocess_sensor_data(df_raw)
# print(f"缺失值: {stats['missing_before']} → {stats['missing_after']}")
# print(f"异常值处理: {stats['outliers_removed']} 个")
工程要点:上述代码中使用了
groupby(recipe_col) 确保每个配方的数据独立标准化,避免配方切换引入的分布偏移。Robust 标准化使用中位数和 IQR,对工艺数据中常见的尖峰和漂移具有天然鲁棒性。
4.5 预处理质量验证
完成预处理后,必须通过以下指标验证数据质量是否满足模型校准要求:
- 缺失率:最终缺失率应 < 0.1%,否则需回溯采集链路。
- 异常值比例:被替换的异常值比例应在 1%–5% 之间,过高说明工艺不稳定或阈值过松。
- 分布一致性:同一配方下,不同批次数据的标准化后分布应近似 N(0,1)(Robust 标准化下近似对称分布)。
- 时间连续性:清洗后数据的时间戳间隔应均匀,无跳变或重复。
| 验证指标 | 合格标准 | 检测方法 | 不合格时的行动 |
|---|---|---|---|
| 缺失率 | < 0.1% | isna().sum() / len() | 检查采集网关日志,修复传感器连接 |
| 异常值比例 | 1% – 5% | 统计被替换的索引数量 | 调整滑动窗口大小或 Z-score 阈值 |
| 标准化后偏度 | |skewness| < 1.0 | scipy.stats.skew | 考虑使用 Box-Cox 变换后再标准化 |
| 时间间隔标准差 | < 采样周期的 10% | diff().std() | 执行重采样至固定频率 |
校准前置条件:只有通过上述验证的数据集,才能进入后续的模型校准环节。建议将预处理管道封装为 CI/CD 中的自动化步骤,每次新批次数据到达时自动执行并生成质量报告。