4、数据清洗与预处理:缺失值处理、异常值检测、数据标准化与归一化

各位工程师,咱们接着聊。上一章我们把数据从FDC、EES、测试机这些源头拽了进来,但说实话,这些数据直接扔进模型里,十有八九要出问题。为什么?因为半导体产线的数据,脏得很。

我见过太多新手,拿到数据就急着跑算法,结果模型一塌糊涂。其实,数据清洗和预处理才是整个良率分析里最耗时的环节,没有之一。我个人习惯,花在这个阶段的时间,至少要占到整个项目的60%以上。你想想看,垃圾进,垃圾出,这个道理在半导体行业尤其残酷。

4.1 缺失值处理:产线数据的老大难

产线数据缺失,太常见了。传感器偶尔掉线、机台维护期间数据没记录、或者某些参数在特定工艺步骤本来就不采集。嗯,这里要注意,处理缺失值之前,你得先搞清楚它为什么缺失。

我把它分成三类:

  • 完全随机缺失:比如某个传感器突然被干扰了一下,丢了一个数据点。这种最省心。
  • 随机缺失:比如某个机台在特定Recipe下,某个参数经常不记录。这跟其他变量有关,但跟它自己没关系。
  • 非随机缺失:这个最麻烦。比如当晶圆缺陷密度过高时,检测机台直接报错不输出数据。缺失本身就跟良率相关,处理不好会引入偏差。

怎么处理?我常用的方法有这几种:

4.1.1 直接删除法

简单粗暴。如果某个参数缺失比例超过70%,我一般直接扔掉这个特征。如果某条记录(某片晶圆)的关键参数缺失太多,也直接删掉。

注意: 千万别在不知道原因的情况下乱删。我曾经因为删掉了一批“缺失”的晶圆数据,结果发现那批晶圆全是良率极低的边缘片,导致模型严重高估了产线能力。

4.1.2 填充法

对于缺失比例不高的数据,填充是主流。我常用的填充策略:

填充方法 适用场景 我的经验
均值/中位数填充 数据分布较对称,且缺失比例<5% 简单,但会降低方差,适合快速预览
前向/后向填充 时间序列数据,如机台腔体温度 产线数据常用,但要注意机台切换Recipe时的断点
KNN填充 特征间相关性较强 效果好,但计算量大,我一般只用在关键参数上
模型预测填充 缺失值与其他特征有明确关系 比如用其他机台参数预测某个缺失的膜厚值

代码示例,用Python的pandas和sklearn做个简单演示:

import pandas as pd
from sklearn.impute import KNNImputer

# 假设df是我们的良率数据
# 先用中位数填充简单的缺失
df['Temperature'].fillna(df['Temperature'].median(), inplace=True)

# 对于关键参数,用KNN填充
imputer = KNNImputer(n_neighbors=5)
df[['Pressure', 'Gas_Flow', 'RF_Power']] = imputer.fit_transform(df[['Pressure', 'Gas_Flow', 'RF_Power']])

4.2 异常值检测:揪出产线上的“坏孩子”

异常值,说白了就是那些跟大多数数据格格不入的点。在半导体产线里,异常值往往意味着机台报警、工艺偏移或者测量错误。我个人习惯,异常值检测不是一次性工作,而是迭代的。

常用的方法:

4.2.1 基于统计的方法

最经典的就是3σ原则。假设数据服从正态分布,超过均值±3个标准差的数据就是异常。但说实话,产线数据很多并不服从正态分布,这时候我会用箱线图法(IQR)。

核心公式: 异常值定义为小于 Q1 - 1.5*IQR 或大于 Q3 + 1.5*IQR 的数据点。其中IQR = Q3 - Q1。

4.2.2 基于距离的方法

比如LOF(局部异常因子)。这个方法适合发现局部异常点。我记得有一次,某个机台的整体参数都在正常范围内,但LOF算法揪出了几个点,后来一查,是那个批次的晶圆在腔体里停留时间长了3秒。这种全局看正常、局部看异常的情况,LOF特别好用。

4.2.3 基于模型的方法

比如孤立森林。这个方法速度快,适合高维数据。我经常用它来做第一轮粗筛。

代码示例:

from sklearn.ensemble import IsolationForest

# 孤立森林检测异常
iso_forest = IsolationForest(contamination=0.05, random_state=42)
df['anomaly'] = iso_forest.fit_predict(df[['Pressure', 'Temperature', 'Gas_Flow']])

# -1表示异常,1表示正常
anomaly_data = df[df['anomaly'] == -1]
print(f"发现 {len(anomaly_data)} 个异常点")
我的经验: 检测出异常值后,别急着删。先回去查机台日志、维护记录。有时候异常值反而是工艺创新的信号。我曾经发现一批异常数据,后来证明是新工艺窗口的起点。

4.3 数据标准化与归一化:让所有参数站在同一起跑线

为什么要做这一步?你想想看,温度是几百度,压力是几十帕,气体流量是几千sccm。这些数值的量纲完全不同。如果你直接拿原始数据跑模型,那些数值大的特征会主导模型,数值小的特征就被淹没了。

我常用的两种方法:

4.3.1 归一化(Min-Max Scaling)

把数据缩放到[0, 1]区间。公式很简单:

X_scaled = (X - X_min) / (X_max - X_min)

适合数据有明确边界的情况,比如温度范围0-500℃。但要注意,如果数据里有异常值,归一化会把正常数据压缩到很小的区间里。

4.3.2 标准化(Z-score Scaling)

把数据变成均值为0,标准差为1的分布。公式:

X_scaled = (X - μ) / σ

这个我用的最多。它不依赖数据的最大值最小值,对异常值的鲁棒性更好。而且很多机器学习算法(比如SVM、PCA)都假设数据是标准化的。

代码示例:

from sklearn.preprocessing import StandardScaler, MinMaxScaler

# 标准化
scaler_std = StandardScaler()
df_std = scaler_std.fit_transform(df[['Pressure', 'Temperature']])

# 归一化
scaler_mm = MinMaxScaler()
df_mm = scaler_mm.fit_transform(df[['Pressure', 'Temperature']])
避坑指南: 标准化和归一化的参数(均值、标准差、最大值、最小值)一定要用训练集计算,然后应用到测试集上。千万不要把测试集和训练集混在一起算。我曾经见过有人把全量数据标准化后再切分,结果模型在线上表现一塌糊涂,因为测试集的信息提前泄露了。

好了,数据清洗和预处理这块,核心就是这三板斧:缺失值处理、异常值检测、标准化/归一化。做扎实了,后面的建模工作才能事半功倍。下一章,我们聊聊特征工程,那才是真正考验工程师经验的地方。