数据清洗 · 体检单与变更留痕
从后台导出的表,八成是这样:日期有 2026.3.1、2026年3月2日、20260303 三种写法,
金额带着 ¥ 和千分位,手机号被 Excel 存成了 1.36E+10,NULL、N/A、—、无 混着当空值用,
底下还躺着十几行完全重复的记录。
这份技能干两件事:先说清楚这表哪儿有问题,再按规则改,改完每一格都能查。
它跟「一键清洗」类工具的区别在 不动手的地方:异常值、同义写法、整列缺失,只标不改。
因为 99999 元那笔可能是录入错,也可能是真单——脚本替你改了,你月底对账就找不到差了。
什么时候用
- 用户丢来一个
.csv/.xlsx,说「帮我看看这数据」「这表怎么这么乱」「清洗一下」 - 每月从后台导台账、对账单、订单明细,要固定口径规整成能统计的样子
- 交接/审计要求说清「这数据你动过什么」
- 表格要拿去跑透视表、报数、上报,得先保证类型统一
不触发:连数据库取数、数据标注/打标、出图、写回业务系统。
三步走
第一步 体检(什么都不改)
python clean.py --file 导出.csv --dry-run
先看健康分和体检单。高危项(整列缺失、科学计数法、身份证校验位不过)先回源处理,
不要在脏数据上做二次加工。
第二步 清洗并出成品
python clean.py --file 台账.xlsx --sheet 明细 --out ./输出
产出三个文件:台账_清洗后.xlsx、台账_清洗报告.md、台账_清洗规则.json。
第三步 下个月复跑
python clean.py --file 下月台账.csv --rules 台账_清洗规则.json
规则和列类型都按上月那份走,不会这个月把「金额」当文本、下个月当数字。
命令行速查
| 参数 | 作用 |
|---|---|
--file |
待清洗文件:.csv / .tsv / .txt / .xlsx |
--sheet |
xlsx 工作表名(默认第一个) |
--out |
输出目录(默认当前目录) |
--dry-run |
只体检,不出清洗后数据(仍出报告) |
--rules |
复跑用规则 json |
--only / --skip |
只开 / 关某几条规则 |
--csv |
额外导一份 csv(UTF-8-BOM,Excel 打开不乱码) |
--restore-sci |
把 1.36E+10 猜回 11 位长整数(结果必须人工核对,默认关) |
--fail-under 60 |
健康分低于阈值时退出码 3,接流水线用 |
--json |
屏幕输出机器可读摘要 |
--demo |
用虚构样本跑一遍看形态 |
--selftest |
内置 8 脏 10 干净用例自检 |
十条规则(默认开 8 条)
| 规则 | 默认 | 干什么 |
|---|---|---|
| 表头修复 | 开 | 空列名补 列N、重名列加 _2、两行表头合并成 上层_下层 |
| 空值统一 | 开 | NULL/N/A/无/—///暂无 一律变空 |
| 空白清理 | 开 | 去首尾空格、去零宽字符、全角空格转普通空格、合并连续空格 |
| 全半角统一 | 开 | 只转全角字母数字,中文标点一个不碰 |
| 手机号转文本 | 开 | 11 位手机号统一成文本,防止下游再被转成科学计数法 |
| 日期归一 | 开 | 五种写法 → YYYY-MM-DD |
| 数值归一 | 开 | ¥1,234.00→1234、1.2万→12000、12%→0.12 |
| 重复行去重 | 开 | 整行完全一致保留首行,删了哪行记在日志 |
| 取值归一 | 关 | 同一取值的全半角/大小写差异归并(改了就是改业务口径,默认只建议) |
| 删空列 | 关 | 整列为空移出主表(要不要删得你定) |
为什么这些只标不改
- 异常值:IQR 口径标出来,但不动。极值可能是真单,也可能是录入错,只有你知道。
- 同义写法(
北京/北京市):归并等于改业务口径,得先确认这两个在你这儿是一个东西。 - 整列缺失:删列是不可逆的,交给你。
- 身份证校验位不过:只标,不替你改数字——改了就是伪造证件号。
- 科学计数法:
1.36E+10的尾数已经丢了,猜出来的 11 位只是「像」,不是「是」。
误报是这么压下去的
中文表格没有词边界,最容易死在「看着像就改」。引擎里三道闸:
- 列级认定:一列里 ≥60% 的非空值能解析成同一类型,才认定这列是那个类型;否则整列当文本,一个字不动。3 行以下的小列一律不认。
- 编号保护:前导零(
00123)和超过 11 位的数字串(条码、单号、身份证)不参与数值归一。 - 全角只转字母数字:整段
FF01-FF5E转换会把中文逗号,变成,,句子就毁了。
回归里 12 条合法文案必须零改动,动一条就算失败。
产出长什么样
_清洗后.xlsx 五个 sheet:
| sheet | 内容 |
|---|---|
| 清洗后数据 | 可直接拿去透视/报数的干净表,首行冻结 + 筛选 |
| 体检单 | 逐列:类型、非空、缺失率、唯一值、问题、风险、样例 |
| 变更日志 | 行号、列、原值、改为、规则、自动/人工、说明 |
| 规则清单 | 这次开了哪些规则、各列认定成什么类型 |
| 原始快照 | 清洗前的原样(前 2000 行),出事能对回去 |
_清洗报告.md 六节:结论(健康分 + 一句话判断)、体检单、已自动修复、需人工确认、复跑方式、边界。
边界
- 只处理本地文件,不联网、不上传、不连数据库
- 不改原文件,清洗结果另存
- 类型识别是规则判断,不是语义理解:业务口径层面的问题(这两列是不是同一个客户)它不管
.xls不支持,先另存为.xlsx
示例数据说明
仓库内所有样例(--demo、--selftest、references/)均为虚构:人名用「示例甲/示例乙/示例丙」,
手机号用 13800000000 这类明显假号,日期为虚构的 2026 年,不含任何真实个人信息与真实业务数据。