2. 良率数据清洗与缺失值处理

任务目标

对晶圆测试原始数据(CP 测试结果)进行清洗:识别缺失值、识别超出物理量程的异常值,并给出可复现的清洗结果,为后续良率计算提供干净数据。

环境与依赖

pip install pandas numpy

实现思路

原始CSV 缺失值检测 isna / 填充或删除 异常值检测 量程 / 3σ 规则 清洗后数据 clean.csv 缺失率统计 → 决定填充/丢弃 超出量程或偏离均值3σ → 标记异常

完整代码

import pandas as pd
import numpy as np

# 1. 构造模拟晶圆测试数据(含缺失与异常)
np.random.seed(42)
n = 200
raw = pd.DataFrame({
    "wafer_id": np.repeat(["W01", "W02"], n // 2),
    "die_x": np.tile(np.arange(10), n // 10),
    "die_y": np.repeat(np.arange(10), 10)[:n],
    "vth": np.random.normal(0.5, 0.05, n),      # 阈值电压,正常范围 0.3~0.7V
    "idsat": np.random.normal(500, 30, n),       # 饱和电流,正常范围 300~700uA
    "leakage": np.random.exponential(2, n),      # 漏电流,正常范围 0~20nA
})

# 注入缺失值
raw.loc[5, "vth"] = np.nan
raw.loc[12, "idsat"] = np.nan
raw.loc[30, "leakage"] = np.nan
raw.loc[45, "vth"] = np.nan
raw.loc[60, "idsat"] = np.nan

# 注入异常值(超出物理量程)
raw.loc[20, "vth"] = 2.5      # 远超 0.7V
raw.loc[55, "idsat"] = 1500   # 远超 700uA
raw.loc[80, "leakage"] = 95   # 远超 20nA

# 2. 缺失值统计
print("=== 缺失值统计 ===")
missing = raw.isna().sum()
print(missing[missing > 0])

# 3. 缺失值处理:数值列用中位数填充
num_cols = ["vth", "idsat", "leakage"]
df = raw.copy()
for col in num_cols:
    median_val = df[col].median()
    df[col] = df[col].fillna(median_val)
    print(f"{col} 中位数填充值: {median_val:.4f}")

# 4. 异常值检测:物理量程 + 3σ 双重规则
spec = {"vth": (0.3, 0.7), "idsat": (300, 700), "leakage": (0, 20)}
outlier_mask = pd.Series(False, index=df.index)

for col, (lo, hi) in spec.items():
    range_out = (df[col] < lo) | (df[col] > hi)
    mu, sigma = df[col].mean(), df[col].std()
    sigma_out = (df[col] - mu).abs() > 3 * sigma
    col_out = range_out | sigma_out
    outlier_mask |= col_out
    print(f"{col}: 量程外 {range_out.sum()} 个, 3σ外 {sigma_out.sum()} 个")

print(f"\n合计异常行: {outlier_mask.sum()}")

# 5. 清洗:剔除异常行
clean = df[~outlier_mask].reset_index(drop=True)
print(f"清洗前: {len(df)} 行, 清洗后: {len(clean)} 行")

# 6. 保存
clean.to_csv("clean_wafer_data.csv", index=False)
print("已保存 clean_wafer_data.csv")

# 7. 验证
assert clean[num_cols].isna().sum().sum() == 0, "仍有缺失值"
for col, (lo, hi) in spec.items():
    assert clean[col].between(lo, hi).all(), f"{col} 仍有量程外值"
print("验证通过:无缺失值,无超量程异常值")

运行与验证

python clean_yield.py

预期输出(由代码逻辑唯一确定):缺失值统计显示 vth/idsat/leakage 各有缺失;填充后无缺失;异常检测报告各列量程外与 3σ 外的数量;清洗后行数减少;末尾打印"验证通过"。若断言失败会抛出 AssertionError。

关键点

  • 缺失值用中位数填充,避免均值受异常值拉偏。
  • 异常值采用"物理量程 + 3σ"双重规则:量程规则捕获硬性越界,3σ 规则捕获统计离群。
  • 清洗后通过 assert 验证无缺失、无量程外值,确保数据质量闭环。