kp-025
数据质量:去重、校验与清洗管线
前置知识
本文基于模型知识整理。
一句话定义
数据质量工作 = 用确定性规则(去重、类型与范围校验、一致性检查)+ 统计方法(异常值识别)把原始数据变成可信数据,并输出质量报告。
为什么重要
「垃圾进,垃圾出」在爬虫场景被放大:重复抓取、页面模板差异、接口部分失败都会制造脏数据。未经质量检查就做的分析,结论无法采信——数据可信度是 kp-024 管线的验收标准。
前置知识
kp-011(清洗函数基础)、pandas 基础。
核心概念
- 重复三型:完全重复(整行相同)、主键重复(同 ID 多条)、近似重复(标题空格/大小写差异)。
- 校验四类:类型(价格是数值)、范围(0 < price < 1e7)、枚举(state ∈ {在售,下架})、跨字段一致(上架时间 ≤ 采集时间)。
- 异常值:偏离整体的值(IQR 法:低于 Q1−1.5IQR 或高于 Q3+1.5IQR)。
- 空值策略:删除 / 填充 / 保留标记——按字段业务语义逐个决定,拒绝一刀切。
原理与机制
质量管线的标准顺序与 pandas 实现:
import pandas as pd
def quality_pipeline(df: pd.DataFrame) -> tuple[pd.DataFrame, dict]:
report = {}
n0 = len(df)
df = df.drop_duplicates() # ① 完全重复
report["exact_dup_removed"] = n0 - len(df)
key_dup = df["sku_id"].duplicated().sum() # ② 主键重复(保留最新)
df = df.sort_values("crawled_at").drop_duplicates("sku_id", keep="last")
report["key_dup_removed"] = key_dup
df["title_norm"] = (df["title"].str.strip() # ③ 近似重复: 归一化后再比
.str.lower().str.replace(r"\s+", "", regex=True))
report["fuzzy_dup_removed"] = int(df["title_norm"].duplicated().sum())
q1, q3 = df["price"].quantile([0.25, 0.75]) # ④ 异常值: 标记而非删除
iqr = q3 - q1
df["price_outlier"] = ~df["price"].between(q1 - 1.5 * iqr, q3 + 1.5 * iqr)
report["null_rate"] = df.isna().mean().round(4).to_dict() # ⑤ 空值画像
return df, report
三条纪律:异常值先标记后处置(可能恰是爆款低价/乌龙价,是业务信号不是噪声);清洗必须幂等(跑两遍结果相同,才能安全重跑);每轮清洗输出质量报告(kp-023 的告警可挂在空值率上)。
实例或案例
抓取的 10000 条商品记录质量报告:完全重复 412(翻页重叠)、主键重复 87(同 SKU 两入口)、价格空值率 2.3%(详情页缺货模块)、异常高值 23 条(其中 3 条实为万元级奢侈品——若直接删除将得出错误品类均价)。结论:没有质量报告的分析不敢汇报。
常见误区
- 误区一:见重复就删,见异常就删。 删除前先问「这条为什么会出现」——重复可能暴露翻页 bug,异常可能是真实业务。
- 误区二:静默修正。 填充值/修正类型却不记录,下游无人知晓数据被加工过;修正必须留痕(新列或日志)。
- 误区三:一次性清洗。 质量检查应成为管线常态步骤(每次批次都跑),而不是分析前的一次性动作。
自测题
- IQR 法判定异常值的公式?
答:低于 Q1−1.5×IQR 或高于 Q3+1.5×IQR(IQR=Q3−Q1);先标记再按业务决定处置。
- 为什么清洗必须幂等?
答:管线可能因 bug 修复或规则更新而重跑;非幂等清洗重跑会二次加工,破坏数据。
- 空值「一刀切填 0」的危害?
答:均值/总量被系统性低估,且掩盖了「采集失败」与「真实为零」的语义差异。
与其他知识点的关系
kp-021 的采集侧去重减少重复源;kp-026 的分词依赖本篇清洗过的文本;kp-023 用空值率/失败率指标联动告警。
延伸阅读
pandas 官方「Working with missing data」;本库 kp-011、kp-023。