资讯详情

Python学习第49天:数据清洗到报表自动化完整实战

📅 2026/10/20 16:22:04 | 华诺云谱 👁 阅读
Python学习第49天:数据清洗到报表自动化完整实战
今天是我 pythonstudy 的第49天。坚持将近50天坦白说中间有几天想放弃尤其是看到教程里“代码能跑”和“自己能写”之间那道坎的时候。第40天左右我开始接触 pandas 和 matplotlib发现一个很尴尬的情况库里每个函数单独看都认识一到真处理数据就不知道从哪下手。所以 Day49 我没有继续往后学新知识点而是做了一件事——把前面学的所有东西串起来完整走一遍“原始数据 → 清洗 → 汇总 → 可视化 → 自动报表”的小项目。这篇文章就是第49天的完整记录。包括我为什么选这个方向、三个库怎么分工、每一步代码怎么写、中间踩过的坑以及给同样在坚持学习的小伙伴一些实用建议。如果你是学Python一个月以上、准备开始做点小东西却不知道怎么开头的人这应该能给你一个非常具体的参考路径。1. 第49天为什么我突然决定做一个“完整小项目”1.1 前48天都干了什么我的前半程其实很普通变量、字符串、列表、字典、元组然后函数、类、文件读写再往后学了点异常处理和常用标准库。大概30天左右语法层面的东西基本过了一遍但要说能解决一个实际问题心里完全没底。于是从第35天开始啃 pandas接着是 matplotlib、openpyxl越学越发现自己陷入“什么都听过、什么都不熟”的状态。这种状态很典型每次打开文档都觉得懂了关上又两眼一黑。真正让我下决心做项目是因为我发现自己写代码时总在一个地方卡住——不是不会用某个函数而是不知道整个流程该先做什么、后做什么。比如拿到一份数据是先处理空值还是先去重日期格式乱了是直接改字符串还是转时间类型这些问题教程里不会统一告诉你只能靠完整跑一遍项目来体会。1.2 项目目标让报表自动化所以 Day49 我给自己定的目标非常具体造一份比较乱的销售明细表用 pandas 读进来把里面所有能想到的脏数据问题都处理掉然后按区域汇总金额画出柱状图最后生成一个排版还不错的 Excel 报表。选择“报表自动化”这个方向是因为它离真实工作场景最近。几乎每个公司都有类似需求定时把一堆流水表统计成日报、周报、月报。而且这个项目能把 pandas、matplotlib、openpyxl 三个库全部用上覆盖了从数据读取到结果输出的完整闭环。做完之后你会发现自己对“工具链”的理解完全不同不再是零散学了一个函数而是知道每个工具在整个流程里的位置。2. 技术选型pandas、matplotlib、openpyxl到底怎么分工2.1 pandas是核心但不是全部一开始我想过用 csv 内置模块直接读文件但很快放弃。原因很简单csv 模块要一行一行手动处理遇到列对不齐、字段里有逗号、数据量稍微大一点代码就会变得很长。pandas 最大的优势是它的 DataFrame 概念可以让你把数据当成一张表格看待然后直接用函数操作整张表而不是写循环去遍历每个单元格。Day49 这个项目里读文件、看数据概况、清洗、分组汇总这些都是 pandas 一条龙搞定的。它承担了整个流程最重的工作。但要注意pandas 不是万能的它擅长“处理数据”不擅长“把数据做得美观”。如果你只想快速把数据导出成 ExcelDataFrame.to_excel() 确实够用可导出的效果往往是黑底白字、列宽挤在一起、没有任何排版美感所以我还需要别的工具来收尾。2.2 matplotlib画图如果不配中文字体会当场翻车matplotlib 是Python最经典的绘图库功能很强但有个老毛病默认设置下图表里的中文会全部显示成方块。这个问题几乎每个用中文做图的人都会遇到第49天我也没能幸免。我第一次运行画图代码时标题和坐标轴标签全是□□□当时还以为代码写错了。解决办法其实就两行配置import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False这里第一行指定了中文字体第二行是让坐标轴上的负号正常显示。因为默认字体不支持中文但负数符号又会被某种字体影响变成乱码所以一定要两条都写上。不同操作系统选的字体会不一样Windows 上微软雅黑和黑体通常可用Mac 上可以用 PingFang SCLinux 上常见的是 Noto Sans CJK。事前统一配置一下能省后面很多事。2.3 openpyxlpandas的to_excel不够用的补充项目最后要把结果输出成 Excel 报表这里我选 openpyxl 而不是 pandas 自带的 to_excel是因为 to_excel 只能把数据老老实实写进去不能做复杂排版。准确的说是pandas 的 ExcelWriter 底层虽然也能调用 openpyxl但你在上面很难方便地设置列宽、合并单元格、改字体颜色、插入图片。openpyxl 是一个专门操作 Excel 文件的库它把工作簿、工作表、单元格都变成了对象你可以像操作一个真正的表格一样去设置样式。比如我想让表头加粗、背景色变成浅灰色、列宽根据内容自动调整、把柱状图图片插到指定位置这些用 openpyxl 都很顺手。所以我最终的分工是pandas 负责数据matplotlib 负责图openpyxl 负责呈现。3. 从脏数据到干净表格完整清洗流程实录3.1 先造一份“够脏”的数据为了把问题暴露出来我写了个小脚本生成了100行模拟销售数据文件名是 sales_data.csv。字段包括订单编号、日期、区域、产品名称、数量、金额。里面的问题我特意埋了一堆日期有“2024/01/05”“20240105”“2024-01-05”三种格式金额有的带“元”字有的带千分位逗号30%的行有缺失值还有几条完全重复的记录另外区域列里混了空格比如“华南区 ”和“华南区”其实是同一个地方。这种脏数据不是凭空瞎编现实中从系统导出的表经常就是这副模样。在多系统对接的时候尤其常见一个系统导出的是“2024/1/5”另一个导出的是“20240105”合并在一起就是灾难。造完数据后我先用一行命令看整体情况import pandas as pd df pd.read_csv(sales_data.csv, encodingutf-8) print(df.head()) print(df.info())info() 会告诉你每一列有多少个非空数据、是什么类型、总行数多少。这一步非常关键因为清洗的第一步不是动手改数据而是先知道数据到底“脏”在哪里。3.2 日期、金额、空值、重复——四类脏数据怎么一步步收拾干净第一类是日期。我先把日期列统一转成 pandas 的时间类型遇到解析不了的会变成 NaTdf[日期] pd.to_datetime(df[日期], errorscoerce)这里 errorscoerce 的意思是能转就转不能转就置为 NaT而不是让程序报错中断。转完之后再把 NaT 的行过滤掉。因为日期都解析不了的话这条记录基本没法用于时间相关的统计。第二类是金额。金额列读进来之后大概率是字符串因为里面有“元”和逗号。我的处理办法是先把单位去掉再删掉逗号最后转为 floatdf[金额] df[金额].astype(str).str.replace(元, ) df[金额] df[金额].str.replace(,, ) df[金额] pd.to_numeric(df[金额], errorscoerce)用 astype(str) 是为了防止某些单元格已经是数字类型时报错稳妥起见先统一转成字符串再做替换。pd.to_numeric 同样用 errorscoerce保证遇到异常值不会让程序死掉。第三类是空值。空值不能一刀切要看业务含义。数量列如果为空说明这笔订单可能没成交但金额还在所以数量用中位数填充比用0填充更合理产品名称如果为空我选择填充“未知”因为直接删掉可能会丢掉金额信息金额为空则会影响汇总如果数量有、金额没有我选择用0填充并在后面过滤掉成交金额为0的明细。第四类是重复。去重时要注意不是所有列都完全一样才算重复订单编号可能因为生成方式不同但日子、区域、金额都一模一样这时候就该认定为重复。我用 subset 指定列df df.drop_duplicates(subset[日期, 区域, 产品名称, 金额], keepfirst)keepfirst 是保留第一条把后面重复的删掉。真正处理业务数据时重复规则要根据场景调整没有万能方案但原则是去重前一定要想清楚“哪些列相同就意味着重复”。另外还有一个容易忽略的坑区域列里的空格。这个我在后面专门说但清洗顺序上它应该放在去重之前否则“华南区 ”和“华南区”会因为一个空格被认为是两条不同记录。3.3 分组汇总为什么汇总要同时算三个指标清洗完之后我用 groupby 按区域分组但汇总的时候不只算总金额还同时算了订单数量和平均金额result df.groupby(区域).agg( 总金额(金额, sum), 订单数(订单编号, count), 平均金额(金额, mean) ).reset_index()很多初学者做汇总只会用一个 sum但实际报表里只看总金额很容易误导。比如某个区域总金额很高可能只是因为它订单数量多另一个区域平均金额很高才说明客单价做得好。把三个指标放一起看一张表就能判断区域质量而不是单单看一个数。算出结果后我按总金额降序排了一下再用 nlargest 取前10。这里有个细节排序后取前10用 sort_values 也可以但 pandas 提供了 nlargest 可以直接取最大几个不用先排完整序性能更好代码也更简洁。4. 报表输出与图表落地的关键细节4.1 绘图环节的代码和输出汇总表我打印出来确认无误后就开始画柱状图。目标很直接用一张图展示各区域总金额对比高亮第一名。为了让图表更像“报表里的图”我做了几个设置图形大小设置为10×6柱状图颜色用了蓝色系把数值标签显示在柱子顶部。核心代码如下import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False top10 result.nlargest(10, 总金额) fig, ax plt.subplots(figsize(10, 6)) bars ax.bar(top10[区域], top10[总金额], color#5B9BD5) ax.set_title(各区域销售总金额 Top10) ax.set_xlabel(区域) ax.set_ylabel(总金额元) ax.set_xticklabels(top10[区域], rotation45) for bar in bars: ax.text(bar.get_x() bar.get_width() / 2, bar.get_height(), f{bar.get_height():,.0f}, hacenter, vabottom, fontsize9) plt.tight_layout() plt.savefig(region_sales.png, dpi150, bbox_inchestight) plt.close()这里有两个细节值得说。一是保存图片时用了 bbox_inchestight不然旋转后的区域名称容易被截掉二是 plt.close() 一定要写不然在交互环境里图片会一直占着内存后面循环画图时容易出各种奇怪问题。4.2 把数据写进Excel并做好排版绘图完成后我用 openpyxl 把汇总表写进 Excel。流程分三步先创建 Workbook拿到默认工作表然后把列名和数据逐行写进去最后统一调整样式。from openpyxl import Workbook from openpyxl.styles import Font, Alignment, PatternFill from openpyxl.drawing.image import Image as XLImage wb Workbook() ws wb.active ws.title 区域汇总 headers [区域, 总金额, 订单数, 平均金额] ws.append(headers) for _, row in result.iterrows(): ws.append([row[区域], row[总金额], row[订单数], row[平均金额]]) header_fill PatternFill(start_colorDDEBF7, end_colorDDEBF7, fill_typesolid) header_font Font(boldTrue) for col in range(1, len(headers) 1): cell ws.cell(row1, columncol) cell.fill header_fill cell.font header_font cell.alignment Alignment(horizontalcenter) widths {A: 12, B: 16, C: 12, D: 16} for col, width in widths.items(): ws.column_dimensions[col].width width img XLImage(region_sales.png) img.width 600 img.height 360 ws.add_image(img, F2)为什么用 ws.append 而不是循环写 cell因为 append 会自动把数据放到下一行写起来更简洁。设置列宽时我用字典一次配好比一个个写更容易维护。这里也验证了选 openpyxl 的价值pandas 的 to_excel 要做到表头加底纹、调整列宽、插图片代码会绕很多。4.3 文件命名与路径处理最后保存文件时我加了一个时间戳from datetime import datetime filename fsales_report_{datetime.now().strftime(%Y%m%d_%H%M%S)}.xlsx wb.save(filename) print(f报表已生成{filename})加时间戳的原因很简单同一个自动化脚本可能每天都要跑如果不加时间戳之前生成的文件会被覆盖。而且文件名里带上时间后续查找历史文件会非常方便。这也是实际工作中很常见的一个习惯。路径处理上我踩了个小坑为图省事直接用了相对路径。如果脚本的执行目录和保存图片的目录不是同一个openpyxl 插入图片时会找不到文件。所以后来我改成用 os.path.join 和绝对路径或者至少在插入图片前检查一下文件是否存在import os if not os.path.exists(region_sales.png): print(图片不存在请检查绘图步骤) else: img XLImage(region_sales.png)这个检查虽然简单但能避免生成一个“看似成功、打开却发现没图”的坏文件。5. 我踩过的坑希望你一次避开5.1 坑1日期格式就像开盲盒我的原始数据里有“2024/01/05”“20240105”“2024-01-05”三种日期格式。第一次转换时我没加 errorscoerce程序直接报了 ParserError 中断。这其实不算坏事但如果你数据量大一个坏值就让整个脚本停下来体验非常差。后来我改成 errorscoerce再用 isna() 查询哪些行没转换成功对质量就有数了。处理日期还有一个心得不要一上来就用字符串切片去拼格式“20240105”这种字符串看着简单但写正则或者切片很容易漏掉边界情况比如月份补零。pandas 的 to_datetime 已经能处理大部分常见格式优先相信它。5.2 坑2中文变方块负号变方块这个前面提到过是我当天遇到的第二个问题。第一次画图标题、横轴纵轴全是方块我以为是缺字体到处装字体折腾了一个多小时。后来才发现只要在数据可视化之前把 rcParams 配置好就行。加上这段配置plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False注意顺序先设置字体再设置负号。如果只设字体负数可能变成一个个方块如果只设负号中文还是方块。两个都得写。另外如果你的系统没有“Microsoft YaHei”这个字体名可以换成你系统列表里的中文字体名用下面代码可以查看系统支持哪些字体import matplotlib.font_manager as fm font_list [f.name for f in fm.fontManager.ttflist if CJK in f.name or Hei in f.name] print(font_list)5.3 坑3去重没生效的原因是一颗空格这个问题想单独拿出来说因为它非常隐蔽。我明明用了 drop_duplicates结果重复行还在。检查后才发现区域列里“华南区”和“华南区 ”就差末尾一个空格pandas 认为它们是两个不同字符串所以不去重。解决办法是在清洗的时候对文本列统一做 stripdf[区域] df[区域].str.strip()清理操作要放在去重之前。这个坑也提醒我一个通用原则对文本列做比较、分组、去重之前先做一次 strip成本很低收益很大。如果有复杂的不可见字符还可以用正则替换把它们清掉。5.4 坑4Excel图片“不显示”其实根本没插进去报表生成完了打开一看图片位置是空的。第一反应是 openpyxl 的 bug后来折腾了一阵才发现问题出在绘图后我把脚本跑到一半换了个工作目录然后 Excel 文件保存到了新目录但图片还是用相对路径读取的。openpyxl 插入图片时如果找不到图片文件并不会报严重错误而是默默生成没有图的表格所以排查起来特别迷惑。我的解决办法是在插入图片前用 os.path.exists 检查文件路径发现不存在就打印提示。另外图片路径最好用绝对路径或者确保整个项目的路径从始至终是统一的。把路径常量定义在脚本开头后面都用 os.path.join 拼接可以避免很多类似问题。6. 下一步怎么继续学6.1 这49天证明了什么很多人学编程会陷入“一直学、一直看”的循环我自己就是典型。直到第49天完整跑通这个项目我才真正体会到什么叫“会用”。之前总觉得自己基础不牢不敢动手实际做完才发现项目里用到的东西80%都是基础语法加三个库的常用函数根本没有想象中的高深。真正难的是流程思路先读数据、看结构、清洗、检查、汇总、输出这个思路一旦建立后面学爬虫、学数据分析、学自动化都会轻松很多。这次项目也让我对“解决问题”有了新的理解。以前遇到报错就去搜索引擎复制代码现在我会先看报错信息再看数据长什么样。数据的问题占了项目里一半以上的时间但也是最值得花时间的部分。数据干净了后面的统计和报表就是顺水推舟的事。6.2 明天Day50我准备做什么Day49 的脚本虽然能跑但目前还是一次性的命令行代码。第50天我打算把这个脚本重构成一个类把清洗、汇总、绘图、输出封装成不同方法以后只要改一下输入文件路径就能跑别的数据。再往后我想加上自动读取文件夹里所有 csv 文件的功能或者用定时任务每天自动跑一遍。如果你也在学Python我建议你和我一样别再往教程列表里加东西了选一个自己工作/生活中真实存在的数据处理需求哪怕数据只有几十行把它做成自动化报表。做完你就会发现坚持50天换来的是真正能用的能力。这种成就感比看完第100个视频强得多。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑