做电商数据这么久,最让我头疼的不是建模,也不是写报表,而是最不起眼的数据清洗。尤其是订单数据,它直接关系到GMV、退款率、复购率这些核心指标,一旦源头数据脏了,后面所有的分析都是白搭。你可以把订单数据想象成会计的账本——账目如果记错了,算出来的利润就是假的,做决策的人拿着假数据,结果可想而知。
这篇文章我就用自己处理电商订单数据的实际经验,从脏数据的来源、清洗流程、pandas具体实现到排查技巧,完整走一遍“从脏数据到准确反映业务事实”的过程。内容偏实操,代码基本可以直接抄,适合做数据分析、数据运营和刚开始接触数据清洗的朋友。
1. 电商订单数据为什么会烂:先看清楚脏数据从哪来
很多人拿到数据的第一反应是“这数据怎么这么烂”,但很少有人去想背后的原因。理解脏数据的来源,清洗的时候才能对症下药,而不是拿到就一顿操作猛如虎,结果越洗越脏。
1.1 脏数据的常见形态:除了“空”和“错”,还有“对不上”
我接手过好几个电商项目的订单表,脏数据的形态五花八门,但归纳起来逃不出这几类:
缺失值是最容易发现的。订单号为空、用户ID为空、支付时间为空,这些一眼就能看出来。但有些缺失藏得很深,比如“收货地址”字段,看起来有值,实际上是一串无意义的字符;再比如“优惠金额”字段,没参加活动的订单直接留空,这个不算脏,但如果没参加活动的订单填了0,参加活动的订单也漏填了,那统计优惠总额的时候就会出大问题。
重复数据是另一个重灾区。用户在下单页连续点了好几次提交,产生了多条订单号相同但数据略有差异的记录;后台接口超时重试,同一笔订单被打回两次;还有更隐蔽的情况——同一订单号出现在上午的数据导出和下午的数据导出里,时间字段不同,导致对账的时候重复统计。我见过最离谱的一次,一条订单在表里出现了7次,金额被重复计算了7遍,那段时间GMV曲线直接“跳楼式”上涨,后来排查才发现是同步任务重复执行导致的。
异常值处理起来最考验业务理解。订单金额出现负数,可能是退款单混进了正向订单表;订单数量出现小数,可能是测试数据没清理干净;客单价高得离谱,比如订单金额500万,不是大客户下单就是数据导出时单位搞错了(分和元混淆)。这类问题如果只靠统计学的“3σ原则”去判定,很容易把真实的合理数据误杀,比如双十一大促的真实高客单价订单会被当异常值删掉。
格式不统一属于“看起来不脏,实则很脏”。日期有的存成“2024-01-01 10:30:00”,有的存成“2024/1/1”,还有的存成时间戳;手机号有的带区号,有的不带;金额有的保留两位小数,有的是一长串浮点数,保留下来一长串小数点。这些字段如果直接做聚合或者关联,结果不会报错,但一定是错的。
逻辑矛盾是脏数据的终极形态,也是最难发现的。订单状态显示“已支付”,但支付时间字段为空;订单状态显示“已发货”,但没有物流单号;订单金额的构成里,商品金额 - 折扣金额 + 运费 ≠ 实付金额。这些问题单看每个字段都是正常的,但合在一起就自相矛盾,说明数据在流经不同系统时发生了错位或丢失。
1.2 脏数据的源头:系统、人为、还有流程
理解了脏数据长什么样,还要知道它从哪来,不然今天清完明天又脏,永远在救火。
系统层面的原因最多。电商系统通常由用户端、订单中心、支付中心、库存中心、物流系统等多个子系统组成,订单数据在子系统之间通过接口传递,任何一个接口超时、重试、字段映射错误,都会导致数据不一致。典型场景:支付成功的回调通知因为网络抖动丢失了,订单状态停留在“待支付”,但钱已经扣了,这就是支付时间和订单状态对不上的根本原因。
另外,数据库表结构变更也会产生脏数据。开发在订单表新增了一个字段,老数据该字段全部为空;或者字段类型从varchar改成bigint,导入时解析失败,数据变成了NULL。促销活动上线时,运营手工在后台改了某个订单的金额,但没有走正常的变更流程,订单金额和流水表对不上。
人为因素也不容忽视。运营人员手工导入历史订单时Excel单元格格式混乱,手机号被Excel自动转成了科学计数法;客服在后台修改订单地址时不小心改了订单金额;测试人员在生产环境留下的测试订单没有及时清理。
流程层面的脏数据往往最致命。业务系统之间没有统一的数据字典,“订单状态”这个字段,订单系统里0表示待支付,支付系统里0表示支付成功,两边的数据汇到一起,同一个数字代表了完全相反的含义。数据仓库在抽取数据时没有做幂等控制,同一天的数据被同步了多次,就会产生重复记录。
注意:清洗订单数据之前,先花半小时搞清楚数据是怎么产生的,比直接写100行清洗代码更高效。因为很多清洗规则其实是“业务规则”的体现,不了解业务逻辑,你连“什么是脏”都无法定义。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 清洗的准备工作:目标、范围与黄金法则
拿到一张脏乱差的订单表,第一步不是写代码,而是想清楚“洗成什么样算干净”。没有目标就动手,等于蒙着眼睛开车。
2.1 先定清洗规则:和业务方对齐“什么叫对”
数据清洗的工作量统计口径常常是这样的:技术以为自己已经把数据洗干净了,业务跑完数说不对,然后两边开始扯皮。为了不背这个锅,动手前一定要先确认清洗规则。
以“订单金额”为例,你需要和业务方确认好:订单金额是商品金额还是实付金额?是否包含运费?退款订单的金额是正数还是负数?优惠券分摊怎么处理?这些规则没对齐,清洗出来的数一定是两边对不上的。
再比如“订单状态”,你要确认状态枚举值有哪些,每个值代表什么含义,“已取消”的订单要不要参与GMV统计,“已退款”订单要不要保留在订单明细表里。这些决策直接影响最终的分析结果。
我的习惯是先用一页纸把清洗规则写下来,包括:
- 数据范围:哪些天、哪些渠道、哪些订单状态的记录参与清洗
- 字段标准:每个关键字段的格式标准、取值范围、是否允许为空
- 业务口径:GMV、订单量、客单价等指标的计算口径
- 异常处理策略:缺失的怎么补、异常的怎么处理、矛盾的怎么取舍
然后拿着这页纸跟业务方过一遍,确认签字。这一步看起来繁琐,但能让后续的清洗工作少走很多弯路。在实际操作中,我见过太多因为口径没对齐而返工的情况——开发把“退款订单金额全部置为负数”,业务说“我要保留原始正数,另外用退款状态标记”,结果整个清洗流程推倒重来,白白浪费两天时间。
2.2 动手前必做:数据备份、抽样探查和字段体检
清洗规则确认后,我一般不会直接开干,而是先做三件不起眼但极其重要的事:
第一,备份原始数据。这个动作看起来多余,但实际上救过我很多次。清洗过程中写错一个条件,可能就把几万条有效订单抹掉了,没有备份就只能从数仓重新拉取,既费时间又可能错过数据回溯窗口。我的做法是先把原始表导出成parquet或csv存档,再用df.copy()生成一个工作副本,所有清洗操作都在副本上做,绝不直接改原始数据。
第二,抽样探查。用df.head()、df.sample(1000)随机抽几批数据,肉眼过一遍关键字段的取值分布。这个动作能帮你快速发现很多代码发现不了的问题,比如某个字段的值明明是0和1,但抽出来一看居然有“男”、“女”这种文本,说明字段映射完全错位了。还比如某个日期字段看着正常,但抽样发现年份是2099年,明显是系统默认值混进来了。
第三,字段体检。在动手清洗前,先对每个关键
