☰
数据清洗:缺失值、重复值与异常值处理
2026/10/7 8:10:41 网站建设 项目流程

摘要

原始数据通常包含缺失值、重复记录、格式错误和业务异常。数据清洗的目标不是简单删除问题数据,而是在理解业务含义的基础上,识别问题、选择处理策略、保留处理记录,并验证清洗结果。

本文使用 pandas 介绍缺失值统计与填充、重复记录识别、异常值检测、字段标准化和清洗结果校验,构建一套可复用的数据清洗流程。

一、背景与问题

数据质量问题通常来自多个环节:

  • 用户填写不完整。
  • 不同系统字段规则不一致。
  • 文件导出时出现空行或重复行。
  • 数据迁移造成格式变化。
  • 业务状态和金额规则没有统一。
  • 人工修改表格时产生异常值。

如果不处理这些问题,后续统计会出现:

问题可能影响
缺失值平均值、比例和分组结果失真
重复值订单量、用户数和金额重复计算
异常值极端值拉高或拉低统计指标
格式不一致分组时同一类别被拆成多个类别
类型错误日期和数值无法正确计算

清洗流程应遵循:

保留原始数据 → 识别问题 → 记录规则 → 执行处理 → 校验结果 → 输出清洗数据和处理报告

二、核心概念

1. 缺失值

缺失值表示字段没有有效内容,但缺失原因可能不同:

  • 真正未知。
  • 业务上不适用。
  • 尚未产生。
  • 采集失败。
  • 转换失败。

不同原因不能使用同一种填充方式。比如“未发生退款”和“退款金额未知”都为空时,业务含义并不相同。

2. 重复值

重复值至少分为三类:

  1. 完全重复:所有字段都相同。
  2. 主键重复:业务 ID 重复,但其他字段不同。
  3. 逻辑重复:字段有细微差异,实际代表同一条业务记录。

完全重复可以较容易处理,主键重复和逻辑重复需要结合业务规则判断。

3. 异常值

异常值不一定是错误。它可能是:

  • 真实的大额订单。
  • 正常退款。
  • 录入错误。
  • 单位错误。
  • 测试数据。

异常检测负责发现可疑记录,最终处理需要业务确认。

4. 清洗规则

每条规则都应说明:

内容示例
字段amount
条件小于 0
判断只有退款订单允许
处理保留并标记
原因负数具有业务含义

不要只保存清洗后的结果,还要保存规则和处理数量。

三、工作原理

1. 清洗流程

数据读取 → 字段和类型检查 → 缺失值检查 → 重复值检查 → 业务范围检查 → 字符串和分类标准化 → 应用处理规则 → 清洗结果验证

清洗顺序会影响结果。一般先完成类型转换和字段标准化,再执行缺失、重复和异常判断。

2. 删除与填充的取舍

缺失值处理常见方式:

方法适用场景
删除行缺失记录很少且不影响代表性
删除列字段缺失率极高且当前分析不需要
常量填充业务上明确存在默认值
统计值填充数值近似随机缺失
分组填充不同群体有不同典型值
保留并标记缺失本身具有业务含义

删除前要记录删除数量,填充后要保留原始缺失标记。

3. 异常值检测

常见方法包括:

  • 业务规则。
  • 分位数和 IQR。
  • Z-score。
  • 时间范围。
  • 分类枚举。
  • 同期对比。

业务规则通常优先于纯统计方法。统计上的极端值可能正是业务最重要的记录。

四、实战示例

1. 准备数据

importpandasaspd orders=pd.DataFrame({"order_id":["A001","A002","A003","A003","A005",None],"region":["华东","华东 ","华南","华南",None,"华东"],"amount":[1200.0,800.0,None,1560.0,-20.0,500.0],"status":["paid","Paid","paid","paid","refund","paid"],"order_date":["2026-09-01","2026-09-02","2026-09-03","2026-09-03","2026-09-04","bad-date",],})

2. 统一字段类型

orders["order_id"]=orders["order_id"].astype("string")orders["region"]=orders["region"].astype("string")orders["status"]=orders["status"].astype("string")orders["amount"]=pd.to_numeric(orders["amount"],errors="coerce",)orders["order_date"]=pd.to_datetime(orders["order_date"],errors="coerce",)

类型转换可能产生新的缺失值,因此转换后要重新检查。

3. 保留缺失标记

orders["amount_was_missing"]=orders["amount"].isna()orders["date_was_invalid"]=orders["order_date"].isna()print(orders.isna().sum())

保留标记后,后续可以区分“原始就是缺失”和“清洗过程中生成缺失”。

4. 处理字符串格式

orders["region"]=orders["region"].str.strip()orders["status"]=orders["status"].str.strip().str.lower()print(orders["region"].value_counts(dropna=False))print(orders["status"].value_counts(dropna=False))

标准化字符串前应确认大小写、空格和别名是否确实代表同一业务类别。

5. 删除完全重复行

before=len(orders)orders=orders.drop_duplicates()removed_rows=before-len(orders)print("removed:",removed_rows)

如果重复行具有业务含义,例如同一订单的多次状态快照,就不能直接删除。

6. 检查主键重复

duplicated_ids=orders.loc[orders["order_id"].notna()&orders["order_id"].duplicated(keep=False)]print(duplicated_ids)

发现重复主键后,应根据订单明细、状态快照或导入批次判断如何处理。

7. 删除或填充缺失值

required=orders.dropna(subset=["order_id","status"],).copy()orders["amount"]=orders["amount"].fillna(0)orders["region"]=orders["region"].fillna("未知")

示例中的填充只是演示。金额填充为 0 只有在业务明确表示“没有金额”时才合理。

8. 使用分组统计填充

orders["amount"]=orders["amount"].fillna(orders.groupby("region")["amount"].transform("median"))

分组填充比全局平均值更能保留群体差异,但分组样本过少时可能不稳定。

9. 使用 IQR 识别异常值

amount=orders["amount"].dropna()q1=amount.quantile(0.25)q3=amount.quantile(0.75)iqr=q3-q1 lower=q1-1.5*iqr upper=q3+1.5*iqr outliers=orders.loc[(orders["amount"]<lower)|(orders["amount"]>upper)]print(outliers)

IQR 只负责筛选可疑记录,不代表这些记录一定需要删除。

10. 应用业务规则

valid_statuses={"paid","pending","cancelled","refund"}invalid_status=~orders["status"].isin(valid_statuses)invalid_amount=((orders["amount"]<0)&(orders["status"]!="refund"))quality_issues=orders.loc[invalid_status|invalid_amount].copy()print(quality_issues)

业务规则应输出问题记录,而不是静默删除。

11. 清洗报告

report=pd.DataFrame([{"rule":"missing_order_id","count":int(orders["order_id"].isna().sum())},{"rule":"missing_amount","count":int(orders["amount"].isna().sum())},{"rule":"invalid_status","count":int(invalid_status.sum())},{"rule":"invalid_amount","count":int(invalid_amount.sum())},])report.to_csv("output/cleaning_report.csv",index=False,encoding="utf-8-sig",)

清洗报告可以作为数据管道的运行结果,帮助定位源数据质量变化。

五、常见问题与实践建议

1. 缺失值是否一定要填充?

不一定。某些分析可以忽略缺失值,某些场景需要保留“未知”状态。先理解业务含义,再选择删除、填充、保留或标记。

2. 异常值是否应该直接删除?

不应该。先保存异常记录,确认它是错误、特殊业务还是单位问题。直接删除可能丢失真实的重要事件。

3. 如何处理重复主键?

可以根据时间、版本、状态和更新时间选择保留规则。例如保留最新记录、聚合明细或拆分为订单主表和状态流水表。

4. 清洗后数据量减少怎么办?

记录每一步处理前后的行数:

print("after drop duplicates:",len(orders))

如果数据量突然大幅减少,应检查过滤条件、日期解析和缺失处理逻辑。

5. 清洗规则应该写在 Notebook 里吗?

探索阶段可以写在 Notebook 中,稳定后应提取到函数或模块,并配套测试、日志和配置。

六、进阶思考

1. 原始数据不可变

推荐分层保存:

data/raw/ 原始数据,只读 data/interim/ 中间结果 data/processed/ 清洗后的数据 output/ 报告和交付结果

不要直接覆盖原始文件,否则无法复核清洗前后的差异。

2. 清洗规则版本化

规则可能随着业务变化而变化。建议记录:

  • 规则版本。
  • 执行时间。
  • 输入文件或数据批次。
  • 处理行数。
  • 删除行数。
  • 输出文件。

3. 不同字段使用不同策略

金额、订单号、日期和状态不能使用同一套通用逻辑。字段级规则更容易解释,也更适合单元测试。

4. 数据清洗与数据质量

清洗是处理问题,数据质量是持续监控问题。稳定流程需要在清洗前检查质量,在清洗后验证质量,并在问题超阈值时停止发布。

结论

数据清洗的关键是先识别问题,再根据业务含义选择处理方法。缺失值、重复值和异常值都不能机械处理,应该保留规则、统计和审计信息。

下一篇将重点讲解数据类型转换和日期时间处理,解决字符串、数字、日期、时区和时间范围统计中的常见问题。

参考资料

  1. pandas 缺失值处理:https://pandas.pydata.org/docs/user_guide/missing_data.html
  2. pandas 重复数据处理:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.drop_duplicates.html
  3. pandas 数据类型:https://pandas.pydata.org/docs/user_guide/basics.html

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询