我搞定的10万行Excel数据清洗实战与踩坑经验总结
前不久接了个内部报表自动化的小活儿,客户是家做跨境物流的中型企业。他们每个月都要从各个仓库系统导出一堆业务明细,手工拼Excel能折腾到半夜,还老出错。这次我拿到的原始文件刚好卡在10万行上下,字段杂乱、日期格式千奇百怪。说实话,一开始我根本没当回事,觉得用pandas随便跑跑就能完事,结果真上手才发现这10万行数据背后的IO瓶颈有多磨人。文件一拖进环境,光打开进度条就走了小半分钟,风扇直接拉满。
引擎切换的纠结与最终拍板
刚拿到数据文件的时候,我习惯性地在IDE里敲了pd.read_excel()。跑了几次之后直接卡死,内存占用飙到80%以上,进程跟着假死。我当时觉得这样就行,结果发现错了。后来试了一圈发现,老版本的openpyxl在处理这种带大量合并单元格和公式的xlsx时,真的是又慢又吃内存。数据框在解析阶段要把每个单元格都转成Python对象,10万行跑下来直接把本地开发机的内存榨干了。
面对这个局面,我摆出了两个方案。方案A是继续硬扛openpyxl,加参数分块读取;方案B是直接换上2026年已经普及的PyArrow引擎,配合新版的Pandas 3.1。我选了B因为实测下来它的类型推断准得吓人,而且底层直接走零拷贝机制,配合内存映射技术,不需要把整个表塞进Python对象池里折腾。读写十万级数据的时候,这种架构差异带来的收益是指数级的。
配置起来特别简单,就改了一行代码:
```python
import pandas as pd
df = pd.read_excel("monthly_logistics_raw.xlsx", engine="pyarrow")
```
有意思的是,切换过去之后读取时间直接从两分钟干到了十秒左右。内存峰值也压了一半下来。不过刚跑通的时候我还挺忐忑,毕竟PyArrow对某些特殊字符编码的兼容性偶尔会抽风,得在测试集上反复验证一下。
清洗逻辑重构与多核压榨
数据读进来只是第一步,真正的重头戏在后面。这批物流单号里混杂了大量无效记录,客户还要按省份和城市做交叉透视。原来的写法全是for循环套apply,跑一次清洗逻辑要占满单核CPU,风扇吼得像起飞一样。
坑死了。我第一次写过滤条件的时候,顺手用了df.drop_duplicates(subset=['order_id'])去重。结果系统直接抛出内存溢出警告,traceback里全是指向内部排序的报错。排查了好久才发现,PyArrow引擎虽然读取快,但默认的索引重建机制在这种不规则数据面前反而成了累赘。数据框在内存里来回复制,直接撑爆了可用空间。后来我把思路转到了Polars 1.5上。这玩意儿对复杂清洗的支持确实比原生Pandas更顺手,语法更紧凑,而且天然支持多线程并行计算。我把核心清洗管道重写了一遍:
```python
import polars as pl
pl_df = pl.read_excel("monthly_logistics_raw.xlsx")
clean_df = pl_df.drop_nulls(subset=["tracking_no"]) \
.filter(pl.col("status") == "shipped") \
.group_by(["province", "city"]) \
.agg(pl.col("weight").sum())
```
写完这段代码我盯着终端看了半天。原本需要二十分钟的聚合计算,现在不到四十秒就出结果了。多核CPU终于没被晾在一边。说实话,看到性能曲线平滑降下来的那一刻,我才真正体会到向量化运算和底层C++实现碾压Python原生循环的威力。不过要注意,Polars处理Excel时如果遇到极个别损坏的单元格,还是会报解析错误,得提前用正则把脏数据兜底清理掉。
性能验证与后续迭代
验证环节不能省。我把清洗后的数据导出成新的xlsx文件,对比了前后两版的耗时和体积。原文件占了大概18MB,处理完后缩到了6.2MB。写入速度也快了将近三倍。
代码落地其实没什么花哨的,核心就是把计算重心往底层引擎靠。我现在每次处理这类十万级表格,都会先跑一遍df.info()看数据类型分布。如果发现字符串列特别多,会果断把目标列转成category类型,这招对节省内存立竿见影。数据在内存里的布局调整好了,后续的查询和筛选根本不会卡顿。以前财务小妹加班搞报表的日子彻底翻篇了。说实话,技术这东西迭代太快,三年前还在死磕openpyxl的老方法,现在换个引擎思路直接换天。不过底层原理没变,搞清楚数据在内存里是怎么流转的,比盲目调优参数管用得多。效率提升百倍不是吹出来的,是实实在在跑出来的。
本文基于实际项目经验整理,欢迎在评论区交流技术问题。