数据清洗实战演练心得体会
原始数据里的数据实战脏东西,远比想象中离谱。清洗上周处理一份电商订单表,演练200万行记录,数据实战光手机号字段就冒出17种格式:带括号的清洗、带+86的演练、中间夹空格的数据实战,甚至有一行写着“138 0013 8000(这是清洗老板的)”。清洗脚本跑完第一遍,演练我盯着日志里那行“成功转换198万条”,数据实战以为万事大吉。清洗结果抽样一看,演练有3000多条手机号被统一成了“13800138000”——因为代码里写死了默认值。数据实战这事让我明白,清洗数据清洗不是演练跑通脚本就完事,得亲眼盯着结果长什么样。
缺失值处理最考验判断力。不是所有空值都该填。用户年龄字段空缺,你拿平均值30岁去补,等于凭空造出一批中年用户。我见过一个更隐蔽的坑:某次清洗销售数据,把“销售额”为空的记录全删了。后来业务方说,那些空值代表“退货未录入金额”,删掉等于把退货订单从报表里抹掉了。现在我处理缺失值,先查三件事:这个字段怎么产生的?空值在业务上代表什么?填错和删掉哪个后果更严重?
异常值检测不能只看统计分布。用3σ原则筛出某门店日销售额50万,标记为异常。跑去问业务,人家说那天是店庆,正常。反过来,有个门店连续30天销售额都是整数,像2500、3800这种。统计上毫无异常,但现实中不可能天天刚好卖整数。查下去发现是店长手动填的预估数,根本没接POS机。所以异常值要结合业务节奏看,光靠箱线图会漏掉真正的问题。
重复记录比想象中狡猾。完全相同的两行好去重,难的是“看起来不同但实际是同一实体”。客户表里“北京朝阳区建国路88号”和“北京市朝阳区建国路88号SOHO现代城”,系统判为两条。更麻烦的是姓名字段,“张伟”和“张 伟”中间多个空格,或者“李娜”和“李娜(离职)”。我现在的做法是先做标准化——统一地址关键词、去掉括号备注、压缩多余空格——再算相似度。但阈值不能拍脑袋,得拿几百条人工标注的样本去调。
日期格式的混乱程度能逼疯人。同一张表里,“2023-01-01”“01/01/2023”“2023年1月1日”“Jan 1, 2023”全有。最坑的是“01/02/2023”,到底是1月2日还是2月1日?看上下文猜没用,得查数据来源。美国系统导出的默认月在前,欧洲系统默认日在前。我现在的习惯是:清洗前先问数据从哪个系统来,时区是什么,有没有夏令时问题。有次没注意,把一批UTC时间当本地时间处理,结果所有订单时间戳偏移了8小时,报表直接错位。
清洗完的数据要留痕。不是简单覆盖原文件。我习惯建三张表:原始表不动,清洗中间表记录每一步变换,最终表只存干净数据。每步变换写清楚:删了多少行,改了哪些值,为什么这么改。有次同事问“为什么客户ID 10086的注册日期变了”,我翻出中间表,发现原始数据里这个ID对应两条记录,一条注册日期是空的,另一条有值但姓名不同。合并逻辑写在注释里,两分钟就解释清楚了。没有这层留痕,就得重新跑一遍全流程。
最后说个反直觉的体会:清洗太干净反而危险。把用户地址全部标准化成“省-市-区-街道-门牌号”五级结构,看起来漂亮,但丢掉了“XX大厦B座”这种非标准描述。后来做配送范围分析,需要识别“靠近地铁站”的地址,标准结构里根本没这个信息。现在我会保留一列原始地址,清洗后的结构化地址另存一列。脏数据里藏着业务真相,洗掉容易,找回来难。
```








