news 2026/8/31 3:52:56

从数据分析到工程实践:用pandas构建可复用的数据清洗流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从数据分析到工程实践:用pandas构建可复用的数据清洗流程

上周有人拿了一份订单导出表给我,问能不能帮忙做一下数据清洗。这份 CSV 的打开方式很典型:日期列里横杠和斜杠混用,金额列里夹着“元”和全角空格,用户 ID 被 Excel 转成了科学计数法,末尾还有二十几行看似重复、主键却不完全一样的记录。我一边处理一边意识到,数据清洗这个词,听起来是在做“打扫卫生”,实际是在解决信任问题:清洗后的数据,必须让下游程序可以无条件依赖。

很多人学 pandas 数据清洗时,第一反应是找“哪个 API 能删空值”“哪个参数能去重”,这没有错,但容易把数据清洗理解成几个孤立的动作。真正的问题通常不是不会用函数,而是不清楚要洗到什么程度,也不清楚每一步为什么这样做。数据清洗不是一次性的体力活,而是一套可以沉淀成流程、可以批量复用、可以在出错时按顺序排查的工程实践。

1. 数据清洗真正要解决的不是“脏”,而是“不可信”

1.1 表面功夫:删空值、去重复、改格式

数据清洗最容易看到的部分,就是处理缺失值、重复值和格式问题。比如用dropna()删掉空行,用drop_duplicates()去掉重复记录,用astype()改字段类型。这些操作单独看都很简单,任何一个 pandas 教程都会讲。

但落到真实场景时,麻烦的是这些操作不能随便用。删除空值之前,你要先确认这些空值是不是真的有业务含义;去重之前,你要确认“重复”的业务定义,是两列完全相同,还是三列组合相同;转换类型之前,你还要确认那些“看起来是数字”的字段是否真能被安全转换。

也就是说,函数只是工具,真正重要的是你定义清楚“干净”的标准。

1.2 深层目标:让下游可以无脑消费

如果只是给自己看,数据没那么干净也能凑合。但数据清洗的难点通常在于,下游还有别的程序等着消费这份数据:做报表的同事、训练模型的脚本、对外提供的接口、量化回测的策略。任何一个环节遇到不该出现的NaN、变成字符串的数字、统一不了的日期格式,都会中断。

所以我的判断是:数据清洗的本质是把数据从“人眼能看懂”变成“程序能无条件信任”。这里的“无条件”三个字很重要。程序不会像人一样一边看一边猜,它只会按照类型、格式、空值规则往下跑。清洗越接近“规则明确、边界清楚”,下游就越省心。

很多人也犯过类似的错:拿到一份数据,先把空值删掉,然后输出 CSV 就交差了。结果下游做统计的人发现,某个月的订单金额突然少了一大截,追查下来才意识到,那批订单的金额列不是空值,而是被 Excel 转成了科学计数法,读进来之后变成了字符串。从那之后我才明白,清洗的每一个动作背后都要有一个业务原因,否则就是一次没有把握的冒险。

1.3 回答一个问题:清洗到什么程度才算完成

很多人的困惑是“到底要洗到什么程度”。一个可执行的判断标准是:把清洗后的数据交给一个完全不了解原始业务的人,他不看备注也能直接做统计,就基本算合格了。具体来说,包括:

  • 每列类型符合预期,日期是日期,数值是数值,ID 是字符串。
  • 缺失值要么被填充,要么被标记,不能留下模糊的空值。
  • 重复记录按业务主键去重,且知道保留哪一条。
  • 列名统一、索引稳定、导出格式明确。
  • 清洗规则可以被重新执行,而不是只存在某一个人的记忆里。

这个标准不复杂,但能帮你判断“要不要继续洗”。

2. 环境不是越新越好,先跑通最小闭环

2.1 Python 与 pandas 的安装:版本适配比新版本更重要

标题虽然挂着“2026 年最新版”,但落到实操上,真正决定体验的不是某个新接口,而是你和当前环境的适配。pandas 每年都在迭代,接口会小幅调整,但缺失值、重复数据、类型转换、列名规范这几件事,核心思路没有大变。所以不要被“最新版”三个字带偏,先把环境跑通,比追求最新版本更重要。

实际项目里,我不建议直接在系统全局环境里pip install pandas。更稳妥的做法是给每个项目建一个虚拟环境:

python -m venv .venv source .venv/bin/activate # Windows 下是 .venv\Scripts\activate pip install --upgrade pip pip install pandas pyarrow openpyxl

pyarrow是为了后面导出parquet格式,openpyxl是为了读写 Excel。如果只是学习,装 pandas 够用;如果要进入真实项目,这两个建议一起装上。

如果遇到“pandas 安装不成功”“Python 3.10 应该配哪个 pandas 版本”之类的问题,排查思路是先去python --version确认解释器版本,再确认 pip 指向的是不是同一个 Python,最后用pip check检查依赖冲突。pandas 2.x 是这些年来常见的稳定大版本,但具体能不能装,取决于你本机的 Python 版本和操作系统,不建议硬按网上旧教程锁版本。

2.2 用最小样例验证数据读入

环境装好之后,先用一个小文件把读入跑通,不要一上来就处理几十列的大表。创建一个样例文件,比如orders_raw.csv,包含几行典型脏数据,然后执行:

import pandas as pd df = pd.read_csv("orders_raw.csv", encoding="utf-8-sig") print(df.shape) print(df.head()) print(df.dtypes)

这一步的目的是确认三件事:文件能不能读进来,编码有没有乱码,类型有没有按预期解析。如果读进来的结果已经和你预期差很远,后面的清洗就没有意义。

2.3 读入阶段就做掉一半脏数据

很多人不知道,pandas 在read_csv阶段就能处理很多脏数据问题,根本不需要等读入后再补救。常见写法是:

df = pd.read_csv( "orders_raw.csv", encoding="utf-8-sig", sep=",", na_values=["", "NULL", "null", "N/A", "NA"], keep_default_na=True, )

na_values可以把常见的空值标记统一识别成NaN,避免同一列里同时出现空字符串、NULLN/A三种缺失形态。sep用于指定分隔符,有的文件是分号,有的是制表符,不指定的话可能整列挤在一起。encoding则解决中文乱码,utf-8-sig是处理带 BOM 的 CSV 比较稳妥的选择,也可以根据文件实际情况调整成gbk

读取参数是第一个排查点。很多人清洗结果不对,不是函数写错,而是数据在进入 DataFrame 的时候就已经错了。

3. 三类高频脏数据:缺失、重复、格式不一致

3.1 缺失值处理:删除、填充还是标记

缺失值是最常见的问题,但处理方式不能一概而论。先用df.isna().sum()看每一列的缺失数量,再做出判断。

处理方式适用场景注意点
直接删除缺失比例极低,或缺失值无业务含义删除前先记录行数变化
填充数值列可用中位数,类别列可用“未知”填充会改变分布,要记录规则
标记缺失缺失本身可能是信息新增_is_missing列,不污染原字段

一个比较稳妥的流程是:先删掉缺失比例过高的列,再对数值列和类别列分别处理,最后给那些“缺失可能有含义”的字段加标记。

# 删除缺失比例超过 60% 的列 threshold = 0.6 df = df.dropna(thresh=int(len(df) * threshold), axis=1) # 数值列填充中位数,类别列填充“未知” df["amount"] = df["amount"].fillna(df["amount"].median()) df["category"] = df["category"].fillna("未知") # 对缺失可能有含义的列单独打标 df["income_missing"] = df["income"].isna().astype(int)

这里最想强调的是:不要看到缺失就只想着删。缺失比例高不一定是数据质量差,可能是业务上本来就不该有值。比如“会员到期时间”对未续费用户来说就是空的,这种空值是有业务含义的,填一个默认日期反而是错误的。

3.2 重复数据处理:按业务主键去重

drop_duplicates()是最容易滥用去重的函数。很多人默认对整个 DataFrame 去重,结果把本该保留的多条记录也删了。

正确做法是先想清楚“重复”的业务定义。比如订单表里,user_idorder_id两列都相同才算是重复,那代码是:

df = df.drop_duplicates(subset=["user_id", "order_id"], keep="first")

如果有人问“pandas 如果指定两列的值均相同,则取第一条数据即可”,答案就是这个subset参数。keep="first"表示保留第一次出现的记录,keep="last"则是保留最后一次。实际项目中,我建议先执行:

duplicated_count = df.duplicated(subset=["user_id", "order_id"]).sum() print(f"重复记录数: {duplicated_count}")

看到重复数之后再决定去重方式,比直接调用drop_duplicates()要安全得多。重复数据的出现往往反映上游系统有问题,如果只是默默地删掉,问题还会再来。

3.3 类型与格式统一:日期、数值、字符串

热词里“pandas 数据类型转换”被搜索很多次,说明这是高频需求。类型转换的核心不是记参数,而是记住一条原则:先转换,再检查,最后处理转换失败的值。

日期列统一用pd.to_datetime,并设置errors="coerce",这样无法解析的日期会变成NaT,而不是直接报错中断:

df["order_date"] = pd.to_datetime(df["order_date"], errors="coerce") print(df["order_date"].isna().sum())

日期解析失败会变成NaT,后续需要和缺失值一样处理。如果失败的行不多,可以结合业务决定删除或填充;如果很多,要回到原始数据确认输入格式,不要硬洗。

数值列用pd.to_numeric,同样设置errors="coerce"

df["amount"] = pd.to_numeric(df["amount"].str.replace("元", "").str.strip(), errors="coerce")

字符串 ID 类字段,如果直接astype(str)NaN会变成字符串"nan",这往往不是我们想要的。所以要先处理缺失,再转换:

df["user_id"] = df["user_id"].fillna("unknown").astype(str)

格式清洗还包含一个很多人忽略的点:不可见字符。金额、姓名、备注列里可能混着全角空格、换行符、零宽字符。可以用字符串处理函数清理:

df["remark"] = df["remark"].fillna("").astype(str).str.replace(r"\s+", "", regex=True)

这一步不是每次都需要,但如果你发现“明明两个值看起来一样,drop_duplicates却没有去重”,优先怀疑的就是不可见字符。

4. 从“干净表”到“结构化数据模型”

4.1 规范列名和索引

清洗完脏值之后,下一个层次是让表本身更有结构。第一步是列名统一。不同系统导出的列名五花八门:有大小写、有空格、有中文括号。进入建模前最好统一成小写加下划线的风格:

df.columns = ( df.columns .str.strip() .str.lower() .str.replace(r"\s+", "_", regex=True) .str.replace(r"[^\w\u4e00-\u9fa5]", "_", regex=True) )

索引也一样。如果数据带有稳定的唯一标识,比如order_id,可以考虑设为索引:

df = df.set_index("order_id")

要注意:只有确认这个字段唯一且非空时才适合设为索引。如果只是想快速检索,也可以不设索引,保持普通列即可。

4.2 派生字段与口径统一

很多时候,原始字段满足不了分析需求,需要从现有字段中生成新字段。例如从订单日期里提取月份:

df["order_month"] = df["order_date"].dt.to_period("M")

或者根据金额和数量计算单价:

df["unit_price"] = df["amount"] / df["quantity"]

这类派生字段能让后续分析更直接,但也带来一个要求:口径必须明确。单位是什么,空值怎么处理,除数为 0 怎么处理,都要有统一规则。最怕的是不同批次的数据里,同一字段的计算口径不一致,导致统计结果对不上。

4.3 输出规范:中间层数据要可溯源、可复现

清洗完成后,输出格式要尽量做到“可溯源、可复现”。可溯源的意思是,下游看到一份数据,知道它是从哪里来的、中间经历了哪些处理。可复现的意思是,下次拿到新的原始数据,用同一套脚本能产出同样结构的结果。

保存文件时,推荐优先考虑parquet,而不是 CSV。parquet 保留了数据类型,读取快,体积小,和后续建模、批处理链路也更搭:

df.to_parquet("orders_clean.parquet", index=False)

如果同事还在用 Excel 查看结果,可以再导出一份 CSV:

df.to_csv("orders_clean.csv", index=False, encoding="utf-8-sig")

如果团队里有人用 Spark,清洗后的数据存成 parquet 也能直接衔接;feather 适合单机多语言场景,但跨工具兼容优先选 parquet。需要提醒的是,旧版 Excel.xls格式有 65536 行的上限,如果清洗后的数据行数较多,不要硬往一个 Excel 表里塞,直接用 CSV 或 parquet 更合适。

5. 用一套可复用的清洗流水线,避免每次重写

5.1 清洗流程拆成五个步骤

很多人的清洗脚本是一次性写的,数据跑完就丢。下次拿到新文件,又要重新看字段、重新踩坑。更合理的做法是把清洗流程固定成一个“五步法”:

  1. 读入:设置encodingsepna_valuesdtype
  2. 探查:看shapeinfodescribe、缺失和重复情况。
  3. 修复:处理缺失、重复、类型、格式、异常值。
  4. 输出:统一列名和索引,导出 parquet 或 CSV。
  5. 记录:把清洗规则和关键统计量写入日志或文档。

这五步不是线性的死流程,而是一个可循环的框架。每次拿到新数据,先跑探查,再决定修复,避免一上来就套用上次的规则。

5.2 单文件脚本化

把清洗逻辑封装成一个函数,是流水线的基础:

def clean_orders(file_path: str) -> pd.DataFrame: df = pd.read_csv( file_path, encoding="utf-8-sig", na_values=["", "NULL", "null", "N/A", "NA"], ) df = df.drop_duplicates(subset=["user_id", "order_id"], keep="first") df["order_date"] = pd.to_datetime(df["order_date"], errors="coerce") df["amount"] = pd.to_numeric(df["amount"], errors="coerce") df = df.dropna(subset=["amount"]) df.columns = df.columns.str.strip().str.lower().str.replace(r"\s+", "_", regex=True) return df

函数的好处是:逻辑可以被测试,可以被其他脚本调用,也可以被复用处理多个文件。

5.3 批量处理多个文件与日志

真实工作中经常是一次拿到十几个 CSV,每个文件格式还不完全一样。用pathlib可以批量处理:

from pathlib import Path
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 3:51:52

STC89C52单片机从仿真到实物:Proteus与TX-1C开发板实战指南

简介:本资源是面向单片机初学者与课程实践者的郭天祥TX-1C实验平台配套仿真学习资料,基于STC89C52核心芯片,覆盖嵌入式开发典型外设与综合应用。包内含323个文件,总计7.47MB,以C源码(20个.c)、K…

作者头像 李华
网站建设 2026/8/31 3:49:16

基于STM32的物联网火灾烟雾报警系统开发详解

简介:本资源是一套完整的基于STM32的物联网火灾烟雾报警系统毕业设计实现方案,面向电子信息、自动化、物联网工程等专业的本科生及嵌入式初学者,解决智能安防类课题中传感器采集、本地声光报警、Wi-Fi组网、远程监控与云平台联动等核心需求。…

作者头像 李华
网站建设 2026/8/31 3:49:02

从“摸鱼被抓包”看懂企业行为审计:日志、原理与合规边界

“贪睡的晚冰”的小剧场里,有一个桥段几乎每个上班族都遇到过:下午三点,工位上的显示器亮着一行没写完的代码,精神早已在睡眠边缘游走。就在眼皮快要彻底合上的时候,同事发来消息:“领导在群里问了&#xf…

作者头像 李华
网站建设 2026/8/31 3:46:09

适合自学的5个电机控制实战项目:从STM32到无感FOC

电机控制在工业自动化、机器人、新能源车载驱动和消费电子领域一直属于高价值技能方向。真正进入这个方向之后会发现,FOC、STM32、PID、simulink仿真并不是四门孤立的技术,而是一条完整的学习链路:从单片机产生PWM,到采集相电流&a…

作者头像 李华
网站建设 2026/8/31 3:45:41

信号与系统期末复习:傅里叶变换4.1-4.4核心考点全解析

信号与系统这门课,很多人第一次接触傅里叶变换时,感觉像突然进入了另一个世界:时域里明明很简单的函数,怎么一到频域全是积分、冲激、频谱密度?更麻烦的是,不同教材的4.1到4.4章节安排还不完全一样&#xf…

作者头像 李华
网站建设 2026/8/31 3:44:57

可食用蘑菇图像分类数据集构建全流程:从采集到模型训练

简介:本资源是一个面向人工智能初学者与计算机视觉实践者的可食用/有毒蘑菇图像分类数据集,聚焦食品安全场景下的二分类任务,助力快速构建蘑菇识别模型。压缩包共86个文件,含83张高质量JPG蘑菇实拍图(涵盖菌盖、菌褶、…

作者头像 李华