你刚接手一份一万条销售记录打开Excel一看日期列混合着“2023-01-01”“2023/01/01”“2023年1月1日”甚至“01/01/2023”金额列有的带货币符号有的是文字“待确认”省份列出现了“广东、广东省、GD、粤”四种写法。这不是数据是泥巴——而Pandas就是你的洗泥机。我见过太多人花三天手动清理最后还漏掉几百条。今天这场实战咱们就拿着真实场景把一万条记录从坟墓里挖出来用Pandas从头洗到脚。第一步直面混乱——加载数据并初探脏数据别急着写代码先把脏数据“摸一遍”。用pd.read_csv(sales.csv)加载但永远不要相信read_csv的默认参数。我习惯先设置low_memoryFalse防止类型推断报错再用pd.set_option(display.max_columns, None)看全貌。第一件事跑df.info()看看每列的非空计数和数据类型。你会发现“订单金额”的dtype是object——数值列居然是字符串这就有鬼了。再跑df.head(100)[订单金额].unique()各种妖魔鬼怪 “1,200.00”、“1200.00”、“-“、“NULL”、“待确认”。数据清洗的本质不是删除而是把非结构信息转化为可计算的格式。这时候你需要的不是公式而是对每列批量执行的三五条Pandas指令。缺失值不是魔鬼盲目填充才是很多教程告诉你用dropna()或fillna(0)但在销售数据里粗暴填充会葬送分析。比如“客户姓名”为空可能是匿名订单而“订单金额”为空可能是待付款——处理逻辑天差地别。在清洗一万条记录前你必须和业务方确认三件事每列缺失的含义、业务可接受的最小阈值、以及填充的默认值策略。实操中我通常先做缺失值矩阵df.isnull().sum()再按列分类处理。对于“省份”列缺失我绝不填充“未知”而是根据“城市”列反向推断——比如城市是“深圳”省份必然是“广东”。用Pandas的map或np.select写个推断函数能救回80%的缺失省份。而对于“订单日期”缺失如果订单号有规律如20230101开头的订单是当天生成可以用str.extract抓取日期否则直接删除——时间序列上绝不能留下黑洞否则任何趋势分析都是骗自己。重复值你可能删掉的不只是重复还有数据故事df.duplicated()默认检查全部列但销售记录里“完全重复”很少见。常见的是“同一客户同一天多次下单”这不算重复需要聚合。真正的重复可能是同样订单号出现两次但金额不同——订单重复且金额不一致是业务系统bug的表征不能简单删除要标记出来给IT排查。我用df[df.duplicated(subset[订单号], keepFalse)]揪出所有可疑行然后逐个看。有一次发现某供应商的订单号前两位是“AB”系统自动补单每次金额翻倍——清洗不是孤立的技术动作它在挖掘业务流程的漏洞。保持冗余记录先新建一列is_duplicate_flag等业务方确认后再决定去留。一万条记录里往往只有几十条真正需要删除但如果你懒到直接drop_duplicates()你会错过改进系统的机会。数据类型字符串翻身的三个杀招object类型的“订单金额”列清洗时最头痛。我的三件套先删除货币符号和千分位逗号df[金额] df[金额].str.replace([$,], , regexTrue)再把文字标识如“待确认”、“退款”转为NaNdf[金额] pd.to_numeric(df[金额], errorscoerce)最后用业务阈值判断异常值小于0或大于100万的金额改成NaN因为一万条销售记录里单价不可能低于0元。这一步做不好后面所有统计都是错的。我见过有人用astype(float)转换结果遇到“-”直接报错整列变成NaN——转换失败不是代码bug是你没提前处理非数字字符。更隐蔽的是“销量”列看起来是整数但有些值是“1.0”、“0.5kg”——这已经不是纯整数了。我的原则所有数值列最终都要能被pd.to_numeric( errorscoerce )无警告通过否则清洗没到位。文本清洗用正则把混乱变成规范“省份”列是最典型的文本乱象大小写、全角半角、简称、城市级别人名混入。一万条记录里至少存在七八种写法。我的做法是先统一转为大写df[省份] df[省份].str.upper().str.strip()然后用re.sub或str.replace将全角字符转半角。但最重要的是建立映射字典把“GD、GUANGDONG、粤、广东”全映射到“广东省”。别手动写100个映射。用df[省份].unique()列出所有不重复值然后写个字典生成代码map_dict {GD:广东省, GUANGDONG:广东省, ...}再df[省份] df[省份].map(map_dict).fillna(df[省份])未匹配的原始值保留再人工检查。这步做完省份列的非唯一值数量会从几十个降到2个含空值。文本清洗的本质是降维把无限可能的字符串还原成有限数量的合法值。日期清洗统一时间轴才能做时间序列一万条销售记录跨越不同年份日期格式五花八门。我用pd.to_datetime(df[日期], formatmixed, dayfirstFalse)但注意formatmixed只支持常见混合格式碰到“2023年1月1日”这种中文格式会报错。一个更可靠的策略先用正则将中文日期替换为横线df[日期] df[日期].str.replace(年, -).str.replace(月, -).str.replace(日, )再转成datetime。转换时留意时间戳有时日期时间列包含了“2023-01-01 12:30:00”但业务上只需要“YYYY-MM-DD”那就用df[日期] df[日期].dt.date。时间是销售数据的脊柱清洗日期就是为了确保所有记录都站在同一条时间线上。如果出现未来日期比如2025年通常是录入错误要么删除要么用该客户的历史日期的均值推断。异常值别用IQR一刀切要结合业务常识很多教程教你用四分位距IQR揪出异常值——销售数据里单价1000元的商品突然出现1元1就是异常。但一万条记录里可能有真实促销价是99元而某恶意刷单全是1元。我的做法是先做分箱统计df[金额].describe(percentiles[0.01,0.05,0.95,0.99])然后关注两个极端0.01分位以下和0.99分位以上。1元以下的订单如果占0.1%直接标记为“疑似刷单”不删除但隔离。100万以上的订单可能是大客户批发不能直接删除——你需要看客户ID是否其他订单也异常。在清洗环节没有“标准答案”只有“业务上下文”。把异常值做标记而不毁灭是专业数据工程师的修养。我会新建一列is_outlier记录原因“金额异常高/低”然后在后续分析中用参数控制是否包含。多表关联清洗一万条记录不是孤岛销售记录通常有客户表、产品表、门店表。清洗时如果只盯着“sales.csv”这一张表你会忽略外键不存在的脏数据。比如“客户ID”列里有“C001”但客户表里没有对应记录——这叫“悬挂记录”。清洗的核心原则之一所有外键必须能匹配到主表否则就是死数据。用df_sales[客户ID].isin(df_customers[客户ID])筛选出不匹配行通常原因是客户被删除了或ID录入错误。我遇到过客户表里“C001”写成“C01”Pandas里isin是严格匹配发现不了这种问题——所以要对ID列做标准化去除空格和零填充df_sales[客户ID] df_sales[客户ID].str.strip().str.upper().str.zfill(5)。清洗是堆叠的小工程每一步都以为简单但每一步都可能漏掉细节。清洗后的验证洗过的数据要能通过“10秒检查”当你跑完所有清洗步骤不要直接写SQL存库。做10秒快速验证df.describe()看数值列min/max是否合理df[日期].min(), df[日期].max()看时间跨度是否吻合df[省份].value_counts()看前5个省份是否能覆盖业务重点区域。更狠的一招把清洗后的数据画一个简单的分布图——如果金额分布出现不该有的尖刺说明还有数据没洗干净。比如你会看到“销量”列出现了0——业务规定销量不能为0那可能是退款订单被误处理。赶紧回头检查replace步骤很可能你把“退”字替换成了0。错误的清洗比不洗更可怕因为它会让你相信数据是准确的而实际全是垃圾。保存与文档化别让明天的人骂你清洗完一万条记录后用df.to_csv(sales_cleaned.csv, indexFalse, encodingutf-8-sig)保存。但更重要的是写一个清洗日志——哪怕只是代码顶部的注释。注明删除的行数及原因、填充的列及策略、新建的标记列的含义。数据清洗的终极产出不是干净数据而是可重复的清洗流程。如果下个月又来一万条同样脏的数据你不需要重写代码只需要修改参数。我建议把清洗脚本分成三层第一层是通用清洗缺失值、重复值、类型转换第二层是业务清洗映射字典、异常阈值、日期范围第三层是人工验证抽样查看、分布检查。这样即使业务规则变化你也只需改动第二层。一万条记录洗下来代码可能超过200行但每行都是你对抗混乱的武器。最后送你一句我贴在工作台上的话“数据清洗不是脏活是你在和世界的不确定性拔河。”手握Pandas这把全能扳手一万条销售记录不过是一万个需要被理解的故事——而你的任务是为它们穿上统一格式的校服送到分析师的课堂上。
Python数据处理实战:用Pandas清洗一万条销售记录
发布时间:2026/7/14 2:07:15
你刚接手一份一万条销售记录打开Excel一看日期列混合着“2023-01-01”“2023/01/01”“2023年1月1日”甚至“01/01/2023”金额列有的带货币符号有的是文字“待确认”省份列出现了“广东、广东省、GD、粤”四种写法。这不是数据是泥巴——而Pandas就是你的洗泥机。我见过太多人花三天手动清理最后还漏掉几百条。今天这场实战咱们就拿着真实场景把一万条记录从坟墓里挖出来用Pandas从头洗到脚。第一步直面混乱——加载数据并初探脏数据别急着写代码先把脏数据“摸一遍”。用pd.read_csv(sales.csv)加载但永远不要相信read_csv的默认参数。我习惯先设置low_memoryFalse防止类型推断报错再用pd.set_option(display.max_columns, None)看全貌。第一件事跑df.info()看看每列的非空计数和数据类型。你会发现“订单金额”的dtype是object——数值列居然是字符串这就有鬼了。再跑df.head(100)[订单金额].unique()各种妖魔鬼怪 “1,200.00”、“1200.00”、“-“、“NULL”、“待确认”。数据清洗的本质不是删除而是把非结构信息转化为可计算的格式。这时候你需要的不是公式而是对每列批量执行的三五条Pandas指令。缺失值不是魔鬼盲目填充才是很多教程告诉你用dropna()或fillna(0)但在销售数据里粗暴填充会葬送分析。比如“客户姓名”为空可能是匿名订单而“订单金额”为空可能是待付款——处理逻辑天差地别。在清洗一万条记录前你必须和业务方确认三件事每列缺失的含义、业务可接受的最小阈值、以及填充的默认值策略。实操中我通常先做缺失值矩阵df.isnull().sum()再按列分类处理。对于“省份”列缺失我绝不填充“未知”而是根据“城市”列反向推断——比如城市是“深圳”省份必然是“广东”。用Pandas的map或np.select写个推断函数能救回80%的缺失省份。而对于“订单日期”缺失如果订单号有规律如20230101开头的订单是当天生成可以用str.extract抓取日期否则直接删除——时间序列上绝不能留下黑洞否则任何趋势分析都是骗自己。重复值你可能删掉的不只是重复还有数据故事df.duplicated()默认检查全部列但销售记录里“完全重复”很少见。常见的是“同一客户同一天多次下单”这不算重复需要聚合。真正的重复可能是同样订单号出现两次但金额不同——订单重复且金额不一致是业务系统bug的表征不能简单删除要标记出来给IT排查。我用df[df.duplicated(subset[订单号], keepFalse)]揪出所有可疑行然后逐个看。有一次发现某供应商的订单号前两位是“AB”系统自动补单每次金额翻倍——清洗不是孤立的技术动作它在挖掘业务流程的漏洞。保持冗余记录先新建一列is_duplicate_flag等业务方确认后再决定去留。一万条记录里往往只有几十条真正需要删除但如果你懒到直接drop_duplicates()你会错过改进系统的机会。数据类型字符串翻身的三个杀招object类型的“订单金额”列清洗时最头痛。我的三件套先删除货币符号和千分位逗号df[金额] df[金额].str.replace([$,], , regexTrue)再把文字标识如“待确认”、“退款”转为NaNdf[金额] pd.to_numeric(df[金额], errorscoerce)最后用业务阈值判断异常值小于0或大于100万的金额改成NaN因为一万条销售记录里单价不可能低于0元。这一步做不好后面所有统计都是错的。我见过有人用astype(float)转换结果遇到“-”直接报错整列变成NaN——转换失败不是代码bug是你没提前处理非数字字符。更隐蔽的是“销量”列看起来是整数但有些值是“1.0”、“0.5kg”——这已经不是纯整数了。我的原则所有数值列最终都要能被pd.to_numeric( errorscoerce )无警告通过否则清洗没到位。文本清洗用正则把混乱变成规范“省份”列是最典型的文本乱象大小写、全角半角、简称、城市级别人名混入。一万条记录里至少存在七八种写法。我的做法是先统一转为大写df[省份] df[省份].str.upper().str.strip()然后用re.sub或str.replace将全角字符转半角。但最重要的是建立映射字典把“GD、GUANGDONG、粤、广东”全映射到“广东省”。别手动写100个映射。用df[省份].unique()列出所有不重复值然后写个字典生成代码map_dict {GD:广东省, GUANGDONG:广东省, ...}再df[省份] df[省份].map(map_dict).fillna(df[省份])未匹配的原始值保留再人工检查。这步做完省份列的非唯一值数量会从几十个降到2个含空值。文本清洗的本质是降维把无限可能的字符串还原成有限数量的合法值。日期清洗统一时间轴才能做时间序列一万条销售记录跨越不同年份日期格式五花八门。我用pd.to_datetime(df[日期], formatmixed, dayfirstFalse)但注意formatmixed只支持常见混合格式碰到“2023年1月1日”这种中文格式会报错。一个更可靠的策略先用正则将中文日期替换为横线df[日期] df[日期].str.replace(年, -).str.replace(月, -).str.replace(日, )再转成datetime。转换时留意时间戳有时日期时间列包含了“2023-01-01 12:30:00”但业务上只需要“YYYY-MM-DD”那就用df[日期] df[日期].dt.date。时间是销售数据的脊柱清洗日期就是为了确保所有记录都站在同一条时间线上。如果出现未来日期比如2025年通常是录入错误要么删除要么用该客户的历史日期的均值推断。异常值别用IQR一刀切要结合业务常识很多教程教你用四分位距IQR揪出异常值——销售数据里单价1000元的商品突然出现1元1就是异常。但一万条记录里可能有真实促销价是99元而某恶意刷单全是1元。我的做法是先做分箱统计df[金额].describe(percentiles[0.01,0.05,0.95,0.99])然后关注两个极端0.01分位以下和0.99分位以上。1元以下的订单如果占0.1%直接标记为“疑似刷单”不删除但隔离。100万以上的订单可能是大客户批发不能直接删除——你需要看客户ID是否其他订单也异常。在清洗环节没有“标准答案”只有“业务上下文”。把异常值做标记而不毁灭是专业数据工程师的修养。我会新建一列is_outlier记录原因“金额异常高/低”然后在后续分析中用参数控制是否包含。多表关联清洗一万条记录不是孤岛销售记录通常有客户表、产品表、门店表。清洗时如果只盯着“sales.csv”这一张表你会忽略外键不存在的脏数据。比如“客户ID”列里有“C001”但客户表里没有对应记录——这叫“悬挂记录”。清洗的核心原则之一所有外键必须能匹配到主表否则就是死数据。用df_sales[客户ID].isin(df_customers[客户ID])筛选出不匹配行通常原因是客户被删除了或ID录入错误。我遇到过客户表里“C001”写成“C01”Pandas里isin是严格匹配发现不了这种问题——所以要对ID列做标准化去除空格和零填充df_sales[客户ID] df_sales[客户ID].str.strip().str.upper().str.zfill(5)。清洗是堆叠的小工程每一步都以为简单但每一步都可能漏掉细节。清洗后的验证洗过的数据要能通过“10秒检查”当你跑完所有清洗步骤不要直接写SQL存库。做10秒快速验证df.describe()看数值列min/max是否合理df[日期].min(), df[日期].max()看时间跨度是否吻合df[省份].value_counts()看前5个省份是否能覆盖业务重点区域。更狠的一招把清洗后的数据画一个简单的分布图——如果金额分布出现不该有的尖刺说明还有数据没洗干净。比如你会看到“销量”列出现了0——业务规定销量不能为0那可能是退款订单被误处理。赶紧回头检查replace步骤很可能你把“退”字替换成了0。错误的清洗比不洗更可怕因为它会让你相信数据是准确的而实际全是垃圾。保存与文档化别让明天的人骂你清洗完一万条记录后用df.to_csv(sales_cleaned.csv, indexFalse, encodingutf-8-sig)保存。但更重要的是写一个清洗日志——哪怕只是代码顶部的注释。注明删除的行数及原因、填充的列及策略、新建的标记列的含义。数据清洗的终极产出不是干净数据而是可重复的清洗流程。如果下个月又来一万条同样脏的数据你不需要重写代码只需要修改参数。我建议把清洗脚本分成三层第一层是通用清洗缺失值、重复值、类型转换第二层是业务清洗映射字典、异常阈值、日期范围第三层是人工验证抽样查看、分布检查。这样即使业务规则变化你也只需改动第二层。一万条记录洗下来代码可能超过200行但每行都是你对抗混乱的武器。最后送你一句我贴在工作台上的话“数据清洗不是脏活是你在和世界的不确定性拔河。”手握Pandas这把全能扳手一万条销售记录不过是一万个需要被理解的故事——而你的任务是为它们穿上统一格式的校服送到分析师的课堂上。