news 2026/9/30 5:02:19

Python+Excel自动化:从脏数据清洗到一键汇总

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python+Excel自动化:从脏数据清洗到一键汇总

周五下午,同事甩给我一份水果进货表,Excel里密密麻麻几百行,让我统计每种水果一共进了多少。我瞄了一眼,数据里还混着“苹果(大)”、“苹果 ”、“apple”这种乱七八糟的写法。如果手动筛选再求和,我估计晚饭前都别想下班。这种活儿,以前我也认,打开Excel,筛选,SUMIF,拖拖拽拽,运气好十分钟搞定,运气不好遇到合并单元格和隐藏行,心态直接崩。

后来我彻底换了个思路:用Python。不管表格里有几百行还是几万行,不管苹果叫“苹果”还是“apple”,不管今天是统计水果还是统计外卖订单,代码一跑,结果几秒钟就出来。今天这篇就把我的做法完整拆给你,从环境准备到处理脏数据,再到把脚本封装成真正能“一键运行”的小工具,全程按小白能跟上的节奏来。你只要会复制粘贴代码、会改文件路径,就能搞定。

1. 为什么非要用Python来汇总Excel——手动操作的真实痛点

先说说我为什么放着现成的Excel不用,非要写Python。

你可能觉得Excel自带的数据透视表、SUMIF函数已经够用了。没错,数据规规矩矩的时候确实够用。但真实世界的表格从来不是按教科书长的。

我那天拿到的水果表,第一列是“品名”,第二列是“数量”,第三列是“单位”。看起来很简单对吧?实际里面全是坑:有的格子写着“苹果”,有的写着“苹果 ”,多了个空格;有的写“苹果(红富士)”;还有的直接把数量写成“10个”、“5斤”这种带单位的文本。用SUMIF一求和,结果全是0,因为Excel根本不会把“10个”当成数字来算。

就算数据是干净的,手动操作也有一堆隐藏问题。

第一,筛选求和的时候容易漏行。几百行的表格,鼠标滚轮滚来滚去,眼神稍微一飘就漏掉一条。第二,领导的需求经常变。你今天按品名汇总,明天可能要求按产地汇总,后天可能要求把两个sheet的数据合在一起再汇总。每次需求一变,你就得重新筛一遍、重新拉一遍公式,时间全搭进去了。第三,这种活是周期性的。如果每个月都要处理类似的表,手动处理一次和写个脚本处理一百次,长期来看效率天差地别。

Python的方案底层逻辑完全不一样:把数据丢给程序,让程序按你的规则跑,不管是10行还是10万行,速度都差不多,而且只要你脚本写得对,永远不会漏。

核心思路就三步:读取Excel、按规则分组汇总、把结果写回Excel。听着简单,但每一步都有细节,下面一个个说。

2. 环境准备与工具选型——pandas和openpyxl的分工

很多小白一听“配置环境”就头疼,觉得这是程序员才需要干的事。其实装Python比装某些国产软件还简单,不需要懂什么底层原理,跟着步骤点就行。

2.1 安装Python的几个关键选择

去Python官网下载安装包,版本选3.10以上的就行,别纠结哪个新用哪个。安装的时候有一个勾选框叫“Add Python to PATH”,一定要勾上,不然后面在命令行里敲python会提示找不到命令。

装完验证一下:打开命令行(Windows按Win+R,输cmd回车),输入:

python --version

如果显示类似Python 3.10.x,说明装好了。这一步卡住的人不少,多半是没勾PATH选项,重装一遍,把勾打上就可以。

2.2 为什么选pandas和openpyxl这两个库

处理Excel的Python库有好几个,我直接给结论:你只需要装pandas和openpyxl。

pip install pandas openpyxl

你可能听说过头号Excel库openpyxl,也听说过pandas干这个活儿很强大。它俩不是二选一的关系,而是配合关系。

库名主要用途擅长的事
pandas数据处理、分组汇总、清洗按条件分组求和、过滤行、合并多个表,底层基于NumPy,快
openpyxlExcel文件读写底层引擎让pandas能把数据写进xlsx格式,也支持直接改单元格样式

简洁一点说:pandas是干活的,openpyxl是跑腿的。pandas要读取xlsx文件的时候,会叫openpyxl去当翻译;pandas要把结果写回Excel的时候,也靠openpyxl落地。你直接安装pandas的时候,openpyxl不一定会自动装全,所以两个都装一遍最省事。

换一个角度说选型:为什么不选xlrd、xlwt?xlrd读老格式.xls没问题,但新版已经不支持.xlsx的读取了;xlwt只能写.xls,功能太老。这三个库之间的区别,新手不用记住,直接pandas加openpyxl,兼容性最好,资料最多,出了问题随便一搜就有答案。

2.3 一个必须知道的概念:DataFrame长什么样

装好库之后,你接触的第一个pandas核心概念叫DataFrame。你可以把它理解成“一个带行号和列名的Excel表格”。比方说水果表读进来之后,控制台会显示类似这样的结构:

品名数量单位
0苹果10斤
1香蕉5斤
2苹果8斤

最左边那一列0、1、2是索引,相当于Excel的行号,但pandas里叫index。品名、数量、单位是列名。记住这个结构,后面一切操作都好理解。

3. 读入Excel数据——从小白视角看pandas的read_excel

写代码的第一步,是让Python知道你文件放在哪、叫什么名字、要读哪个sheet。

3.1 第一段能跑的代码

假设你的Excel文件名字叫“水果进货表.xlsx”,和你的Python脚本放在同一个文件夹,那么读取数据的代码很简单:

import pandas as pd df = pd.read_excel("水果进货表.xlsx") print(df.head())

df.head()的意思是显示前5行,用来快速确认数据读对了没有。

如果文件路径不一样,改成绝对路径,Windows下面要注意反斜杠的问题:

df = pd.read_excel(r"D:\我的文档\水果进货表.xlsx")

加粗重点:路径前面加一个r,表示这个字符串里的反斜杠不要当转义字符处理。不然\我这种路径会直接报错或乱掉。这个是新手最容易踩的坑。

3.2 三个高频参数:sheet_name、header、usecols

真实的Excel文件往往有好几个sheet。默认read_excel只读第一个sheet。如果水果数据在第二个表里,只要加一个参数:

df = pd.read_excel("水果进货表.xlsx", sheet_name="Sheet2")

如果表格第一行不是表头,而是从第三行才出现“品名”“数量”这些列名,就指定表头行号(0表示第一行):

df = pd.read_excel("水果进货表.xlsx", header=2)

如果表里有多余的列,只要品名和数量两列,我习惯在读取的时候直接筛选掉,省得后面清理:

df = pd.read_excel("水果进货表.xlsx", usecols=["品名", "数量"])

用usecols还有一个小技巧:如果列名含特殊字符,可以直接用列号,比如“A, C”这种写法:

df = pd.read_excel("水果进货表.xlsx", usecols="A,C")

先读进来,看一眼前几行,确认数据没跑偏,再去做汇总。这一步花不了十秒钟,但能给你省掉后面排查问题的半小时。

4. 按水果名称汇总数量——groupby与手动循环两套方案

数据读进来了,接下来是重头戏:按品名分组,把数量加起来。这里给你两套方案,一套是pandas的正规军打法,一套是给完全看不懂正则和分组逻辑的新手准备的备选方案。

4.1 正规军打法:groupby

用一个生活化类比:groupby就像把一堆积木按颜色倒进不同的桶里。品名这一列一样的水果,会被归到同一个桶里,然后再对每个桶执行求和操作。代码就一行:

result = df.groupby("品名")["数量"].sum() print(result)

运行之后你会看到类似这样的输出:

品名 苹果 18 香蕉 5 Name: 数量, dtype: int64

苹果的10加8等于18,香蕉是5,分毫不差。如果你还想知道每种水果有几条进货记录,也就是统计出现次数,改成count()就行:

df.groupby("品名")["数量"].count()

如果想同时求总和和平均值,一行也可以写完:

df.groupby("品名")["数量"].agg(["sum", "mean"])

这条代码一次给出总和和平均进货量,应对领导临时加需求特别好使。

有一个细节值得单独说。groupby的结果是一个Series,不是DataFrame。用print打印没问题,但后面如果想把这个结果再加工、再合并,最好把它转回DataFrame:

result = df.groupby("品名")["数量"].sum().reset_index()

reset_index()把“品名”变成普通列,索引重新变成0、1、2……这样result的结构就变成:

品名数量
0苹果18
1香蕉5

后面写回Excel、排序、加总计行,都基于这种规整的结构来操作,最顺手。

4.2 备选方案:手动循环统计

如果看到groupby感到头大,完全没关系。Python还有最朴素的写法——用字典手动统计。逻辑特别直白:一个空字典,循环每一行,如果水果名字还没出现过,就新建一个键;如果出现过了,就把数量累加上去。

result_dict = {} for index, row in df.iterrows(): name = row["品名"] num = row["数量"] if name in result_dict: result_dict[name] += num else: result_dict[name] = num print(result_dict)

运行完你会得到一个字典:{'苹果': 18, '香蕉': 5}。这个方案虽然没有groupby那么优雅,但每一步都是人眼看得懂的逻辑:遇到苹果就加,遇到香蕉就加,最后字典里存的就是每个水果的总数。对于纯小白,我甚至推荐先写一遍这个循环,体会一下“一行一行处理数据”到底是什么感觉,然后再去拥抱groupby的简洁。

4.3 两种方案怎么选

如果数据量在几千行以内,两种方案速度上几乎没有区别。如果数据量到了十万行以上,groupby的效率会明显优于手写循环。不过对这个场景来说,你只需要记住:groupby是pandas的核心功能,也是日常最常写的代码,熟练它就等于跨过了Excel自动化的第一道门槛。

5. 真实数据里的脏东西——汇总前必须处理的地雷

标题写的是“告别手动统计”,但你拿到手的原始数据通常不会让你跑一遍代码就美美收工。我那天处理的水果表就是个典型,汇总之前必须先洗数据。下面几种情况,你大概率也会遇到。

5.1 数量列是文本,还带着单位

水果表里最常见的坑就是“10个”“5斤”这种写法。表面看是数字,实际上在Excel里是文本,pandas读进来也会当成字符串,一求和直接报错或者全变0。

处理思路是把数量列清洗成纯数字。一行正则替换就能处理:

import pandas as pd df["数量"] = df["数量"].astype(str).str.replace(r"[0-9.]", "", regex=True)

先把数量列变成文本,再把数字和点以外的符号(比如“个”“斤”)统统替换为空字符串,最后转成数值。

有一个更简单的思路,如果单位不影响汇总逻辑(你只管数量数字,不管单位是不是斤),那么不管后面跟的是“个”还是“斤”,统一不要。代码如下:

df["数量"] = df["数量"].astype(str).str.extract(r"(\d+\.?\d*)").astype(float)

这一行的意思是:从文本里提取第一个数字部分(支持小数),然后转成小数。如果某个单元格写的是“苹果一箱”,提取不出来,会变成NaN,后续可以用fillna(0)补成0。这一步在真实数据里特别常用。

5.2 同一水果有多个名字

我那份表里,苹果至少有三种写法:“苹果”、“苹果 苹果”、“apple”。如果直接按品名分组,这三种会被当成三种水果统计,结果完全不对。

处理办法也简单,定义一张别名映射表,把所有写法映射到标准名:

name_map = { "苹果": "苹果", "苹果 ": "苹果", "apple": "苹果", "红富士": "苹果", } df["品名"] = df["品名"].replace(name_map)

replace的意思是:遇到“苹果 苹果”就替换成“苹果”,遇到“apple”也替换成“苹果”,替换完之后再groupby,结果就收敛了。

5.3 单元格前后空格

Excel里手打数据经常带上空格,肉眼看不出来。我的习惯是汇总前先做一个通用清洗:把品名列里所有的首尾空格去掉、把列名里的空格也去掉。

df["品名"] = df["品名"].str.strip()

这一步要放在别名映射之前做,因为“苹果 苹果”如果不去掉首尾空格,even替换表也匹配不上。

5.4 空行和无效数据

表格里偶尔会有整行空的,或者数量是负数要剔除的。最简单的做法是:把品名为空的行删掉,数量为正数的才保留。

df = df.dropna(subset=["品名"]) df = df[df["数量"] > 0]

dropna是“把缺失行删掉”,subset指定只看品名这一列有没有空值。这两行写完,很多莫名其妙的问题就自动消失了。

5.5 清洗顺序很重要

不要一上来就groupby。我建议的顺序是:

  1. 读入数据后用df.info()或df.head()快速看一眼结构;
  2. 处理列名(去空格、统一大小写);
  3. 处理单位、提取数字;
  4. 处理品名的别名和空格;
  5. 删除空行和无效值;
  6. 最后再groupby汇总。

为什么顺序这么重要?因为如果你先groupby,再清洗,分组的结果已经错掉了,清洗也白清洗。清洗和汇总的关系,就像先洗菜再切菜——你非得先切再洗,最后菜全是湿的,还得返工。

6. 把脚本武装成“一键”小工具——写回Excel与批量处理改造

到这一步,你已经能把一个脏乱的水果表汇总成干净的结果了。但离标题说的“一键”还有一步:让脚本自动把结果写回Excel,并且支持处理多个文件。

6.1 把结果写回Excel:详解to_excel

pandas写Excel的接口和对read_excel是对称的。一行代码就能落盘:

result.to_excel("水果汇总结果.xlsx", index=False)

index=False的意思是不要把索引写进Excel。如果不加这个参数,结果表里会多出左边一列0、1、2、3,看着很蠢。

如果你想控制写入到第几个sheet,加sheet_name参数:

with pd.ExcelWriter("水果汇总结果.xlsx") as writer: result.to_excel(writer, sheet_name="汇总", index=False)

这种写法还能实现一个需求:把原始明细和汇总结果放到同一个Excel的两个sheet里。

6.2 加一个总计行和排序

领导看汇总表,很多时候还想知道总数是多少,还想让数量最多的水果排在最前面。三行代码就能实现:

result = result.sort_values("数量", ascending=False) total_row = pd.DataFrame([{"品名": "总计", "数量": result["数量"].sum()}]) result = pd.concat([result, total_row], ignore_index=True)

sort_values按数量降序排,concat把总计行加在最后,这个表就是按标准汇报逻辑输出的。

6.3 批量处理多个Excel文件

这个需求特别常见。每个月销售发来12张表,分别叫“1月水果表.xlsx”、“2月水果表.xlsx”……你不可能写12遍代码。用Python的glob库遍历文件夹,自动找所有xlsx文件,批量处理:

import pandas as pd import glob all_data = [] for file in glob.glob("水果/*.xlsx"): df = pd.read_excel(file) # 清洗(省略),按你的实际情况写 df["来源文件"] = file all_data.append(df) merged_df = pd.concat(all_data, ignore_index=True) result = merged_df.groupby("品名")["数量"].sum().reset_index() result.to_excel("全年水果汇总.xlsx", index=False)

这个脚本的逻辑:先用glob通配符找到“水果”文件夹下所有xlsx文件,逐个读取、清洗,加上“来源文件”这个列标记数据出处,然后合并成一个大表,最后groupby汇总。这样不管你有12个文件还是120个文件,代码一行都不用改。

6.4 真正意义上的“一键”运行

脚本写完之后,怎么做到双击就运行,不用每次打开命令行敲python?Windows下写一个.bat批处理文件,两行内容:

@echo off python 水果汇总.py pause

保存成一键汇总.bat放在和脚本同一个文件夹,以后双击这个bat就行了。pause的作用是程序跑完后窗口不会立刻闪退,方便你看到结果。想更丝滑一点,可以把脚本里的路径全部改成相对路径,再把源数据文件都放在同一个文件夹下,配合input()输入日期或者文件名,整个流程就很像一个专用小软件了。比如:

month = input("请输入要汇总的月份,例如202506:") file = f"水果进货表_{month}.xlsx"

这么一改,每个月拿到新表,双击bat,输入月份,回车,结果文件就自己生成好了。这套流程我用下来,比在Excel里反复筛选、拉公式、做透视表省太多时间,而且接手同事的表也完全不慌——数据再乱,跑一遍清洗逻辑都能掰回正轨。

后来我又给这个脚本加了个功能,把每种水果从小到大的所有进货记录也拆出来,方便核对。用Python处理Excel这件事,入门真的不难,先照着上面的代码跑通一个小例子,然后试着改一改列名、换一换文件,你很快就会有自己的手感。

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

植物气孔检测:小目标定位与表型量化技术实践

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

作者头像 李华
网站建设 2026/9/30 5:01:44

基于Hadoop与Spark的图书自动标注系统设计与实现

前阵子做了一个图书类别自动标注系统,正好把 Hadoop、Spark、Django 和机器学习串成了一整条链路,标题看着像课程设计,但真做下来涉及的坑一点都不少。从大数据环境搭建到数据清洗,再到模型训练和可视化大屏,每一步都值…

作者头像 李华
网站建设 2026/9/30 5:01:42

Unity iOS Deep Link 完整接入:从链接配置到 C# 参数透传避坑指南

做手游的都知道,拉新靠买量,回流靠唤醒。而 iOS 端的 Deep Link,就是那条把用户从 Safari、广告页、活动 H5 重新拽回游戏 App 的绳子。很多人以为这不就是配个 URL Scheme 的事,但真做到 Unity 工程里就会发现,从链接…

作者头像 李华
网站建设 2026/9/30 5:01:40

用AI做数据分析作业全复盘:从拆题到Excel交付的五个可复用方法

作业群在晚上十一点弹出第三次作业文档的时候,我正对着电脑里密密麻麻的Excel表格发呆。题目其实不复杂:结合自身专业,利用人工智能工具完成一项数据分析任务,提交可编辑的Excel文档和300字以上的操作说明。但恰恰是这种“看起来有…

作者头像 李华
网站建设 2026/9/30 5:01:39

C#: 托盘

NotifyIcon.csusing System; using System.Windows.Forms; using System.Drawing; using System.Diagnostics;class Program {static void Main() { NotifyIcon NI new NotifyIcon();NI.Icon new Icon("camera.ico");NI.Text "托盘";NI.Visible true;…

作者头像 李华
网站建设 2026/9/30 5:00:27

FreeRTOS任务通知详解:轻量级IPC替代信号量与队列

1. 为什么我直到系列第六篇才专门讲任务通知1.1 必须先理清一个选型逻辑前五篇我们聊了任务创建、调度、队列、信号量和互斥量,这些都是 FreeRTOS 里最容易想到的 IPC 手段。这期想认真讲讲任务通知(Task Notification),因为它在实…

作者头像 李华