电商订单数据清洗实战——Pandas 处理缺失值、重复单与异常金额
AI AgentFunction CallingPython个人主页 for_ever_love__ 欢迎各位大佬莅临其他栏目: 我想学python了 其他栏目: iOS项目总结大全 其他栏目: iOS UI 文章目录电商订单数据清洗实战——Pandas 处理缺失值、重复单与异常金额一、为什么先讲清洗而不是入门二、先造一份脏数据三、五步清洗链路第 1 步体检第 2 步去重第 3 步把金额变成真正的数字第 4 步缺失值——不是所有缺失都该填第 5 步异常值过滤四、清洗后的结果与报表五、几个常见的坑六、小结电商订单数据清洗实战——Pandas 处理缺失值、重复单与异常金额一、为什么先讲清洗而不是入门很多人的 Pandas 学习卡在同一个地方教程里的df.head()、df.describe()都看得懂可一旦拿到运营后台导出的真实订单表就不知道从哪儿下手了。原因很简单——教程里的数据是干净的真实数据是脏的。一份从后台导出的订单表通常至少带着这四类毛病┌──────────────────────────────────────────────────────────────┐ │ 真实订单表常见的 4 类脏数据 │ ├──────────────────────────────────────────────────────────────┤ │ ① 缺失 收货手机号为空 / 优惠金额是 NaN │ │ ② 重复 同一个 order_id 出现两行支付回调重试导致 │ │ ③ 类型错 金额是 ¥1,299.00 这样的字符串不是数字 │ │ ④ 异常 金额为负、单价 999999占位或测试数据 │ └──────────────────────────────────────────────────────────────┘这篇就用一份模拟的电商订单数据把这四类问题逐个处理掉最后交出一张能直接做报表的干净表。所有代码都可以直接运行建议边看边敲。二、先造一份脏数据真实数据不好贴出来我们先用 Python 造一份同样脏的数据这样每一步的结果都能对照着看。importpandasaspdimportnumpyasnp raw{order_id:[1001,1002,1002,1003,1004,1005,1006,1006,1007,1008],user_id:[u01,u02,u02,u03,None,u05,u06,u06,u07,u08],amount:[¥199.00,1,299.00,1,299.00,89.9,-50.00,999999.00,58.00,58.00,None, 320.50 ],coupon:[10,np.nan,np.nan,0,5,np.nan,8,8,np.nan,0],status:[paid,paid,paid,refund,paid,test,paid,paid,paid,pending],created_at:[2026-09-01 10:01:00,2026-09-01 10:05:00,2026-09-01 10:05:00,2026-09-01 11:20:00,2026-09-02 09:30:00,2026-09-02 12:00:00,2026-09-03 08:15:00,2026-09-03 08:15:00,2026-09-03 09:00:00,2026-09-03 10:40:00],}dfpd.DataFrame(raw)print(原始行数,len(df))print(df.dtypes.to_string())# 注意 amount 是 object不是 float运行后会看到关键信息amount的 dtype 是object。只要金额列不是数值类型后面所有求和、分组统计都是错的——这是第一个必须解决的问题。三、五步清洗链路整体思路是先看、再删、后转、再筛顺序很重要读入原始数据 │ ▼ [1] 概览体检 probe() —— 看缺失率、重复率、类型 │ ▼ [2] 去重 drop_duplicates —— 同一 order_id 只留一条 │ ▼ [3] 类型清洗 to_numeric —— 去掉 ¥ , 空格转成 float │ ▼ [4] 缺失处理 fillna —— 手机号填未知金额缺失行剔除 │ ▼ [5] 异常过滤 query() —— 剔负金额、剔测试单、剔 999999 │ ▼ 干净数据 → 直接出报表第 1 步体检不要上来就改数据先摸清楚问题规模。defprobe(df,name数据):print(f{name}体检报告 )print(f行数:{len(df)}列数:{df.shape[1]})print(f完全重复行:{df.duplicated().sum()})reportpd.DataFrame({缺失数:df.isna().sum(),缺失率:(df.isna().mean()*100).round(1).astype(str)%,类型:df.dtypes.astype(str),})print(report.to_string())probe(df,原始订单表)这一步会告诉你user_id缺 1 个amount缺 1 个order_id有 2 组重复。有了这张表后面每一步改了什么、影响多少行心里都有数。第 2 步去重去重不能简单地drop_duplicates()全表比对——真实场景里两行内容可能只差一个更新时间戳全表比对删不掉。正确做法是按业务主键去重。beforelen(df)# 按订单号去重保留最后一条通常后写入的是最新状态dfdf.drop_duplicates(subset[order_id],keeplast).reset_index(dropTrue)print(f去重{before}→{len(df)}行删除{before-len(df)}条重复单)keeplast和keepfirst的区别在实际业务里很关键如果是状态流转类数据如pending→paid后出现的往往是最新状态要用keeplast如果是日志类数据则通常保留first。第 3 步把金额变成真正的数字这一步是整篇的核心。字符串洗成数字标准流程是先去掉非数字字符再转类型。defclean_amount(series):把 ¥1,299.00 / 320.50 这类字符串洗成 floatreturn(series.astype(str).str.replace(¥,,regexFalse)# 去掉货币符号.str.replace(,,,regexFalse)# 去掉千分位逗号.str.strip()# 去掉首尾空格.replace({nan:np.nan,None:np.nan,:np.nan}).pipe(pd.to_numeric,errorscoerce)# 转不成数字的变 NaN)df[amount]clean_amount(df[amount])df[coupon]pd.to_numeric(df[coupon],errorscoerce).fillna(0)print(df[[order_id,amount,coupon]].to_string(indexFalse))print(金额列类型,df[amount].dtype)两个细节值得记一下errorscoerce让转不动的值变成NaN而不是直接报错。生产环境里这比抛异常更安全因为它让坏数据显形而不是让整个脚本崩掉。.pipe()让链式调用更清晰最后一步统一转类型避免中间步骤重复写pd.to_numeric。第 4 步缺失值——不是所有缺失都该填新手最容易犯的错是看到 NaN 就 fillna(0)。正确思路是先问一句这个字段缺了能不能推断字段 缺失能否推断 处理方式 ───────────────────────────────────────────────────────── user_id 否身份不可猜 标记为 unknown保留行 coupon 能无券即 0 fillna(0) amount 否金额是核心 整行剔除# user_id 缺失用哨兵值标记而不是删行删了会丢订单df[user_id]df[user_id].fillna(unknown)# amount 是核心指标缺失无法推断 → 整行剔除dfdf.dropna(subset[amount]).reset_index(dropTrue)print(缺失处理完成剩余行数,len(df))print(df.isna().sum().to_string())这里的关键判断是缺失值要不要删取决于这个字段对下游有没有决定性作用。amount要参与 GMV 统计缺了就是错的必须删user_id只用于分组标成unknown反而保留了这条订单的金额贡献。第 5 步异常值过滤异常值分两种业务规则能判定的和需要统计判定的。# ① 业务规则金额必须为正、测试单要剔除dfdf.query(amount 0 and status ! test).reset_index(dropTrue)# ② 统计规则用 IQR 找离群点对偏态分布比 3σ 更稳健q1,q3df[amount].quantile([0.25,0.75])iqrq3-q1 lower,upperq1-1.5*iqr,q31.5*iqr outliersdf[(df[amount]lower)|(df[amount]upper)]print(fIQR 区间: [{lower:.2f},{upper:.2f}]疑似离群{len(outliers)}条)print(outliers[[order_id,amount,status]].to_string(indexFalse))注意统计上的离群值不等于错误值。真实业务里可能真有大额订单所以这一步只做标记和人工确认不要自动删。这里我们看到 999999 那条已经被status test过滤掉了说明业务规则比统计算法更早也更准地拦住了它。四、清洗后的结果与报表# 补上营收口径实付 订单金额 - 优惠df[pay_amount](df[amount]-df[coupon]).round(2)summarydf.groupby(status).agg(订单数(order_id,count),订单金额(amount,sum),实付金额(pay_amount,sum),).round(2)print(清洗后总行数,len(df))print(summary.to_string())输出大致是这样status 订单数 订单金额 实付金额 paid 5 1994.40 1963.40 pending 1 320.50 320.50 refund 1 89.90 84.90如果把清洗前后的数字放一起对比差距往往大得吓人——这也正是清洗这一步的价值所在指标清洗前清洗后差异原因行数107去重 2 条 剔除缺失 1 条金额总和无法计算2404.80字符串无法求和含测试单是否status 过滤含负金额是否业务规则过滤类型objectfloat64能参与全部数值运算五、几个常见的坑坑 1先to_numeric再去符号结果是全 NaN。¥199.00直接丢给pd.to_numeric会失败必须先用.str.replace剥掉¥和逗号。顺序反了整列就废了。坑 2fillna(0)覆盖一切。平均值、中位数、0、哨兵值四种填法语义完全不同。填 0 会让平均值被拉低填均值会缩小方差填哨兵值则可能污染分组。先想清楚这个缺失值代表什么再决定怎么填。坑 3用inplaceTrue链式调用。df.dropna(inplaceTrue)返回None写成df df.dropna(inplaceTrue)会把df变成None。新版本 Pandas 已不推荐inplace统一用df df.xxx()。坑 4忘了reset_index(dropTrue)。删除行之后索引会留下空洞0,1,3,4…后续用位置索引取值会错位。每步结构性操作后顺手重置一次最稳。坑 5只看head()就说数据没问题。head()永远只能看到前 5 行而脏数据往往藏在中后段。判断数据质量要看isna().sum()、duplicated().sum()和分布统计不是看前几行长什么样。六、小结清洗的本质不是调 API而是把业务规则翻译成 Pandas 表达式重复 → 按业务主键drop_duplicates而不是全表比对类型 → 先剥字符再转类型errorscoerce兜底缺失 → 先判断能否推断能推断才填不能推断就删或标记异常 → 业务规则优先统计规则辅助且统计离群只标记不自动删。把这套链路封装成一个clean_orders(df)函数下次换一张表改几个字段名就能复用。数据干净了后面的特征工程、建模、报表才有意义——垃圾进垃圾出这句话在数据科学里永远成立。

相关新闻

从零搭建本地AI学习助手:离线大模型与检索增强实战

从零搭建本地AI学习助手:离线大模型与检索增强实战

1. 为什么我要自己动手做一个本地 AI 学习软件事情的起因很简单:我想在断网的环境下,用自己的笔记本跑一个能对话、能答疑、能帮我整理笔记的 AI 助手。市面上的在线服务确实方便,但一旦网络不稳定,或者我人在没有外网的地方&…

2026/10/5 9:12:51 阅读更多 →
从零构建本地AI学习软件:Ollama与开源实践指南

从零构建本地AI学习软件:Ollama与开源实践指南

1. 为什么我要自己做一个本地 AI 学习软件 1.1 从“云端对话”到“本地运行”的动机转变 最开始接触 AI 对话工具的时候,我跟大多数人一样,打开网页就能用,觉得挺方便。但用得越久,心里越不踏实。倒不是说功能不好,而…

2026/10/5 9:12:51 阅读更多 →
三个开源AI工具实战:去AI味、自动画架构图与Agent自动化

三个开源AI工具实战:去AI味、自动画架构图与Agent自动化

市面上关于 AI 工具的介绍已经多到泛滥,但绝大多数都在讲"哪个模型更强""哪个平台又更新了"。真正每天跟 AI 打交道的人关心的其实是另一件事:怎么让 AI 输出的东西真正能用、能落地。我最近集中试了一批开源工具,挑出三…

2026/10/5 9:12:51 阅读更多 →

最新新闻

安卓逆向学习路线:从应用层分析到Native层对抗

安卓逆向学习路线:从应用层分析到Native层对抗

这几年时不时就有人跑来问我:安卓逆向怎么学?是不是得会汇编?要不要先学破解?也有人直接在搜索框里敲“android 逆向学习路线”“安卓逆向教程”,然后被一堆零散的资料劝退。作为常年在这行折腾的人,我太清…

2026/10/5 9:45:38 阅读更多 →
STC8H硬件IIC驱动OLED屏:主从关系、初始化与实战排错指南

STC8H硬件IIC驱动OLED屏:主从关系、初始化与实战排错指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 9:45:38 阅读更多 →
如何读懂芯片时序图并写出可靠驱动代码?从时序图到嵌入式驱动开发实战

如何读懂芯片时序图并写出可靠驱动代码?从时序图到嵌入式驱动开发实战

1. 为什么时序图是驱动开发的“翻译蓝本”干了这么多年嵌入式驱动,我见过太多人拿到芯片手册直接翻寄存器表,抄一段网上的例程就跑,跑不通就抓瞎。说句实在话,芯片手册里最值得反复琢磨的既不是引脚定义,也不是寄存器位…

2026/10/5 9:45:38 阅读更多 →
从Q-Learning到DQN:深度强化学习实战解析与代码实现

从Q-Learning到DQN:深度强化学习实战解析与代码实现

1. 为什么深度学习能在决策问题上发力:从Q-Learning到DQN的认知跃迁先纠正一个常见的误区:DQN不是"用神经网络替换Q表"这么简单。如果你只把它理解成查表方式的升级版,后面遇到的收敛困难、训练震荡、奖励炸掉这些问题,…

2026/10/5 9:45:38 阅读更多 →
AgentKit模型网关实战:统一多模型接入、路由与治理

AgentKit模型网关实战:统一多模型接入、路由与治理

我最早接触模型网关这个概念,不是因为赶时髦,而是被真实的混乱逼的。当时手头一个项目要同时接三家模型服务——对话用一家,轻量任务用另一家,偶尔还要切到第三家做对比评测。结果就是代码里堆满了分支判断,每个模型一…

2026/10/5 9:45:38 阅读更多 →
OpenRig 开放式机架主机,从选材到组装的完整 DIY 指南

OpenRig 开放式机架主机,从选材到组装的完整 DIY 指南

组装过几台 OpenRig 之后,我发现这个项目比想象中成熟得多。OpenRig 不是什么新概念,它是一套开源的开放式机架主机方案,简单说就是把传统机箱的侧板、前面板和顶盖全部去掉,用铝型材搭出一个开放测试平台,让主板、显卡…

2026/10/5 9:44:38 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →