第3章 数据质量检查与清洗流程

机会评分模型对输入数据的质量高度敏感。缺失值、异常值和不一致数据会直接扭曲评分分布,导致模型区分度下降甚至失效。本章围绕缺失值处理规范、异常值识别标准和数据一致性验证三个核心环节,建立可执行的清洗SOP,确保进入建模环节的数据符合质量门槛。

适用场景

  • 原始机会数据首次入库后,进入特征工程前的强制质检环节。
  • 模型迭代时增量数据接入后的质量复核。
  • 跨系统(CRM、ERP、第三方数据源)合并数据后的冲突消解。
  • 定期(月度/季度)数据健康度巡检。

前置条件

  • 已完成数据采集与初步集成(参见第2章)。
  • 已定义字段级元数据:字段名称、数据类型、取值范围、是否可空。
  • 已准备数据质量检查环境(Python 3.8+ / SQL 分析工具 / 可视化平台)。
  • 已制定缺失值、异常值、一致性规则的业务阈值文档。

操作步骤

以下流程围绕三个检查维度并行展开,完成后合并输出数据质量报告。

核心原则:先检查后处理;保留原始字段快照;所有修改必须可追溯;阈值需经业务方确认。

步骤1:数据加载与字段画像

  • 加载目标数据集,记录总行数、字段数、内存占用。
  • 对每个字段计算:非空计数、唯一值计数、均值/中位数/标准差(数值型)、频数分布(分类型)。
  • 生成字段画像摘要表,作为后续清洗的基线。
import pandas as pd
import numpy as np

df = pd.read_parquet("opportunities_raw.parquet")
profile = {
    "total_rows": len(df),
    "fields": []
}
for col in df.columns:
    info = {
        "field": col,
        "dtype": str(df[col].dtype),
        "non_null": int(df[col].notna().sum()),
        "null_pct": round(df[col].isna().mean() * 100, 2),
        "n_unique": int(df[col].nunique())
    }
    if df[col].dtype in ["float64", "int64"]:
        info["mean"] = round(df[col].mean(), 2)
        info["std"] = round(df[col].std(), 2)
        info["min"] = round(df[col].min(), 2)
        info["max"] = round(df[col].max(), 2)
    profile["fields"].append(info)

步骤2:缺失值处理规范

  1. 缺失模式识别:计算每个字段缺失率,标记缺失率 > 50% 的字段为高风险;绘制缺失矩阵图,识别系统性缺失。
  2. 缺失机制判定:区分完全随机缺失(MCAR)、随机缺失(MAR)、非随机缺失(MNAR),不同机制选择不同处理策略。
  3. 处理策略选择:
    • 缺失率 < 1%:直接删除缺失行(需记录删除行数)。
    • 缺失率 1%–30%:根据字段类型选择填充方式(均值/中位数/众数/前向填充/模型预测)。
    • 缺失率 > 30% 且无法补充:删除该字段并记录原因。
  4. 插值与填充执行:对关键连续型字段使用多重插补(MICE)或KNN插值;分类字段使用众数或“未知”标记。
# 缺失率计算与标记
null_pct = df.isna().mean().sort_values(ascending=False)
high_risk = null_pct[null_pct > 0.5].index.tolist()
print("高风险字段(缺失率>50%):", high_risk)

# 均值填充示例(MAR机制)
df["amount_filled"] = df["amount"].fillna(df["amount"].median())

# 多重插补(使用sklearn的IterativeImputer)
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
imputer = IterativeImputer(max_iter=10, random_state=42)
df_imputed = imputer.fit_transform(df[numeric_cols])

步骤3:异常值识别标准

  1. 统计分布检测:
    • Z-score 法:|Z| > 3 标记为异常(适用于近似正态分布数据)。
    • IQR 法:低于 Q1−1.5×IQR 或高于 Q3+1.5×IQR 标记为温和异常;3×IQR 为极端异常。
  2. 领域规则校验:根据业务阈值直接判定(如:机会金额 ≤ 0 或 > 年预算上限、概率值不在 [0,1] 区间)。
  3. 异常值标记与处理:
    • 创建异常标记字段(is_outlier),记录异常原因。
    • 业务可解释的异常:保留但参与模型时降权;不可解释的异常:删除或截尾处理(winsorize)。
# Z-score 异常检测
from scipy import stats
z_scores = np.abs(stats.zscore(df["score"]))
df["score_outlier_z"] = z_scores > 3

# IQR 异常检测
Q1 = df["amount"].quantile(0.25)
Q3 = df["amount"].quantile(0.75)
IQR = Q3 - Q1
df["amount_outlier_iqr"] = (df["amount"] < (Q1 - 1.5*IQR)) | (df["amount"] > (Q3 + 1.5*IQR))

# 领域规则:金额必须 > 0 且 < 500万
df["amount_outlier_biz"] = (df["amount"] <= 0) | (df["amount"] > 5_000_000)

步骤4:数据一致性验证

  1. 格式校验:日期字段统一为 YYYY-MM-DD;电话号码、邮箱按正则表达式校验;编码字段匹配字典表。
  2. 范围校验:数值字段是否在声明范围内;分类字段值是否在允许列表中。
  3. 跨字段逻辑校验:
    • “成交日期” ≥ “创建日期”。
    • “机会金额” = Σ“产品行项金额”。
    • “客户行业”与“产品线”的适用关系。
  4. 不一致数据追溯与修正:记录不一致记录ID,按优先级修正;无法修正的标记并隔离。
-- SQL 跨字段一致性检查示例
SELECT
    opportunity_id,
    create_date,
    close_date,
    CASE
        WHEN close_date < create_date THEN '日期倒挂'
        WHEN close_date = create_date THEN '同日关闭'
        ELSE '正常'
    END AS date_consistency,
    amount,
    (SELECT SUM(line_amount) FROM line_items WHERE line_items.opp_id = opp.opportunity_id) AS calc_amount,
    CASE
        WHEN ABS(amount - calc_amount) > 0.01 THEN '金额不匹配'
        ELSE '一致'
    END AS amount_consistency
FROM opportunities opp
WHERE close_date IS NOT NULL;

步骤5:生成数据质量报告

  • 汇总各维度检查结果:缺失字段列表、异常值统计、不一致记录清单。
  • 输出清洗前后对比指标:行数变化、缺失率变化、异常值占比。
  • 报告经数据负责人与业务方会签后归档。
数据质量检查与清洗流程 缺失值处理规范 异常值识别标准 数据一致性验证 ① 缺失模式识别 ② 填补/删除决策 ③ 多重插值处理 ① 统计分布检测 ② 领域规则校验 ③ 标记与修正 ① 格式范围校验 ② 跨字段逻辑校验 ③ 追溯与修正 三重检查并行执行,输出统一数据质量报告 所有修改操作均需保留原始数据快照,确保可追溯

输入输出物

类别名称格式说明
输入原始机会数据集Parquet / CSV / 数据库表待检查的原始业务数据
输入字段元数据字典JSON / YAML / 数据字典文档字段名、类型、允许值、是否可空
输入业务阈值规则表Excel / 配置文件缺失率阈值、异常值阈值、一致性规则
输出清洗后数据集Parquet / CSV经过缺失、异常、一致性处理后的数据
输出数据质量报告PDF / HTML包含检查结果、处理记录、清洗前后对比
输出操作日志JSON Lines / 数据库日志表每步操作的详细记录,用于审计追溯

责任边界

角色职责决策权
数据工程师编写并执行清洗脚本;生成数据质量报告技术方案选择(插值算法、检测方法)
数据分析师验证清洗逻辑的合理性;审核质量报告阈值微调建议;标记字段是否可删除
业务负责人确认业务规则与阈值;审批最终数据质量报告高缺失字段保留/删除决策;异常值业务含义判定
模型负责人接收清洗后数据并确认可用性对清洗结果提出补充要求

记录材料

  • 数据检查清单:逐字段记录缺失率、异常值数、不一致数及处理方式。
  • 清洗操作日志:每步操作的时间、执行人、影响行数、参数配置。
  • 例外事项登记表:无法自动处理的异常记录,标注原因和人工处理状态。
  • 数据质量报告:包含清洗前基线、清洗后指标、对比分析、审批签字。
# 清洗操作日志示例结构
{
  "timestamp": "2025-03-21T14:30:00Z",
  "operator": "data_engineer_01",
  "action": "缺失值填充",
  "field": "amount",
  "method": "中位数填充",
  "affected_rows": 1247,
  "params": {"median_value": 85000.0},
  "status": "completed"
}

异常处理

常见异常与应对措施: 遇到以下情况时暂停自动清洗流程,升级至人工判定。
异常场景识别标志处理措施
全字段缺失率 > 80%字段画像中大部分字段缺失率极高停止清洗,检查数据源是否采集失败;与数据源确认后重新拉取
异常值占比 > 15%Z-score / IQR 标记异常比例异常高重新审视阈值设定;排查是否存在数据录入系统故障
跨字段一致性严重冲突超过 20% 记录存在逻辑矛盾检查ETL映射关系;与业务确认规则定义是否准确
插值后数据分布畸变填充后均值/标准差突变 > 30%改用更保守的填充策略(如前向填充);评估是否删除该字段
数据量级不符合预期行数与上一周期差异 > 50%核对数据源抽取范围;检查过滤条件是否正确

验收标准

  1. 缺失率达标:所有字段缺失率 ≤ 5%(业务特批字段除外),且已记录缺失原因。
  2. 异常值受控:异常值占比 ≤ 3%,所有异常记录已标记 is_outlier 字段并填写异常原因。
  3. 一致性通过:核心逻辑规则(日期顺序、金额匹配、编码合法性)通过率 = 100%,不一致记录已隔离或修正。
  4. 可追溯:所有数据修改操作均有日志记录,原始数据快照完整保留。
  5. 报告完备:数据质量报告包含三个维度的检查结果、处理明细、清洗前后对比,并经业务负责人签字确认。
  6. 模型可用性确认:模型负责人运行基础特征工程脚本无报错,特征分布符合预期。
经验提示: 数据清洗不是一次性的。建议在模型训练集、验证集、测试集上分别执行相同的清洗逻辑,并检查清洗后分布是否一致。若分布差异显著,说明清洗规则对数据子集有偏向,需要调整策略。