AI编程(三十五):导出报表 — 让分析结果”装订成册”交出去

作者:

在

程序里算得再漂亮,print出来只是一屏黑底白字——老板要的是”能双击打开、能转发、能打印”的Excel文件。to_csv一行把表写成文件,to_excel加上列宽和加粗表头,ExcelWriter把好几个sheet分页装订——你的分析结果终于从”程序的输出”变成”能出门见人”的报表

一、老板的”最后一公里”

前几篇的剧情走到高潮:第31篇问总量,第32篇筛出”哪几行”,第33篇分组对比,第34篇把两张表拼成一张。你已经能回答老板的任何数据问题了。今天他把最后一个问题拍在桌上:

“别在你那个黑窗口里比划了,把结果发我邮箱——要Excel。”

你愣住了:结果确实在程序里算出来了,print出来是这样的:

    总销售额  订单数    平均单值
部门
华东   38300     2  19150.0
华南    8000     1   8000.0
华北    9500     1   9500.0

可这是”屏幕上的字”,不是”文件”。老板没法双击打开、没法转发给他的老板、没法打印签字。你总不能让他自己对着屏幕抄一遍吧?

这就是数据工作的最后一公里:分析结果得从程序里”搬”出来,变成一个实实在在的文件。Word叫”保存”,程序叫导出(export)——把内存里那张表,写到硬盘上变成 .xlsx 或 .csv 文件。Excel里你按Ctrl+S就完事,代码里这活儿叫 to_excel / to_csv,各一行。

今天学完,”读进程序→看清长相→按需提问”的三部曲就补上了收官的一环:问完了,把答案装订成册交出去。

今天的唯一一个新概念是:把内存里的表写成文件——to_csv存成通用文本表,to_excel存成Excel(还能多sheet分页、美化表头)。它是”导出/保存”这个动作的代码版,也是数据分析流水线的最后一块拼图。

二、to_csv:最朴素的”落盘”

先想清楚:它到底干了什么

to_csv(to + CSV,”存成CSV文件”)干的事跟”把屏幕上的表格抄到一张纸上”一模一样:内存里的表是”活的”,程序一关就没了;to_csv把它按行按列写进硬盘上的一个文件,从此文件在,结果就在——不管程序还开不开着。

先看有多简单:

import pandas as pd

# 第33篇的老朋友:按部门分组的销售报表
销售 = pd.DataFrame({
    "姓名": ["小李", "小王", "小张", "小赵", "小王"],
    "销售额": [8000, 12000, 15300, 9500, 11000],
    "部门": ["华南", "华东", "华东", "华北", "华东"],
})
报表 = 销售.groupby("部门")["销售额"].sum().reset_index()
报表.columns = ["部门", "总销售额"]

# 一行,把报表写进文件
报表.to_csv("部门销售报表.csv", index=False)
print("已导出:部门销售报表.csv")

运行完,程序所在的文件夹里多了一个 部门销售报表.csv——用Excel打开它,就是那张分组报表。to_csv("文件名") 里给的字符串就是文件名,写在哪儿?写在程序运行的文件夹里(想指定路径就写完整路径,比如 "D:/报表/部门销售报表.csv",斜杠用/或\)。

那 index=False 是什么?“别把行号写进文件”。pandas默认手痒,会把行号0、1、2也写成一列——文件里凭空多一列没名字的”序号列”,Excel里看着碍眼,下次读回来还多一列”Unnamed: 0″(无名列)。记住:导出报表几乎永远加 index=False,除非你真的需要那列行号。

CSV是什么?为什么两种导出格式都要会

CSV(Comma-Separated Values,”逗号分隔的值”)就是”纯表格文本”:一行一条记录,列与列之间用逗号隔开,没有任何格式(没有加粗、没有颜色、没有列宽)。它是表格界的”白开水”——谁都能喝:Excel能开、WPS能开、pandas能读、各种系统都能导,还是所有”导入数据”功能的通用语。

跟 to_excel 存出来的 .xlsx 怎么选?一句话:

  • 给人看(要好看、要多sheet、要转发)→ to_excel,出xlsx;
  • 给程序/系统用(再读回来、导入别的软件、当中间文件)→ to_csv,轻快通用。

三、to_excel:存成”真正的Excel”

给人看的报表,还是 .xlsx 有面子。to_excel(”存成Excel文件”)一行搞定:

报表.to_excel("部门销售报表.xlsx", index=False, sheet_name="部门汇总")

三个参数各管一事:"部门销售报表.xlsx" 是文件名(后缀得是 .xlsx);index=False 老规矩,别写行号;sheet_name="部门汇总" 给这个sheet(工作表,Excel底部那些可切换的”页签”)起个名字——老板打开文件,底部看到的是”部门汇总”而不是默认的”Sheet1″,专业感立刻不一样。

一张表一页:ExcelWriter”分页装订”

老板看完汇总,追问:”明细呢?两个我都要,装在一个文件里。”一个文件装两个表?Excel里就是两个sheet——对应到代码,得请出 ExcelWriter(”Excel写入器”,可以理解成”装订机”):一张表写一页,最后一起”装订”成一个文件:

明细 = 销售  # 第34篇的原始明细
汇总 = 销售.groupby("部门")["销售额"].sum().reset_index()
汇总.columns = ["部门", "总销售额"]

# 用ExcelWriter"装订"多页
with pd.ExcelWriter("销售报表.xlsx") as 装订机:
    汇总.to_excel(装订机, sheet_name="部门汇总", index=False)
    明细.to_excel(装订机, sheet_name="销售明细", index=False)

print("已导出:销售报表.xlsx(2个sheet)")

with pd.ExcelWriter("销售报表.xlsx") as 装订机: 这行念作”打开装订机(文件叫销售报表.xlsx)”,接下来缩进里的每一句 to_excel(装订机, ...) 都是”往里加一页”,缩进结束时自动”合上装订机”——文件落盘。打开 销售报表.xlsx,底部两个页签:”部门汇总”和”销售明细”,一页看结论、一页查依据,一份文件全齐。

(with 这个写法你在第9篇见过影子——它保证”不管中途出什么事,文件都正确关好”。今天照着用即可,知其然就够。)

给报表”化妆”:列宽和加粗表头

老板打开文件,第一句夸”挺全”,第二句皱眉:”列太窄了,’总销售额’三个字挤成一坨。”pandas导出的xlsx是”素颜”的——列宽默认、表头不加粗。好在xlsx本质是个可以”后期化妆”的文件,用 openpyxl(Excel的底层化妆盒)微调两笔:

from openpyxl import load_workbook
from openpyxl.styles import Font, Alignment

# 1. 先按老办法导出
汇总.to_excel("部门销售报表.xlsx", index=False, sheet_name="部门汇总")

# 2. 打开文件化妆
工作簿 = load_workbook("部门销售报表.xlsx")
页 = 工作簿["部门汇总"]

# 表头加粗 + 每列按内容自动调宽
for 格 in 页[1]:          # 第1行 = 表头
    格.font = Font(bold=True)
for 列 in 页.columns:
    最宽 = max(len(str(格.value or "")) for 格 in 列)
    页.column_dimensions[列[0].column_letter].width = 最宽 + 4

工作簿.save("部门销售报表.xlsx")
print("已导出并美化:部门销售报表.xlsx")

两个动作:表头加粗(Font(bold=True),”加粗字体”)和列宽自适应(量出每列最长的内容,宽度加4留白)。就这么两笔,文件从”裸数据”变成”像样的报表”。美化是锦上添花,先保证数据导对,再谈化妆——顺序别反了。

四、完整实战:从原始数据到成品报表

把五篇的功夫串成完整流水线——读数据→清洗→合并→分组→导出,这才是日常工作的真形态:

import pandas as pd

# 1. 读(第25、31篇)
销售 = pd.read_csv("销售明细.csv")
员工 = pd.read_excel("员工档案.xlsx")

# 2. 清洗(第29篇):去空格、去重
销售["姓名"] = 销售["姓名"].str.strip()
员工 = 员工.drop_duplicates("姓名")

# 3. 合并(第34篇):以销售为主,别丢行
宽表 = pd.merge(销售, 员工, on="姓名", how="left")
print("合并后行数:", len(宽表), "对不上部门的:", 宽表["部门"].isna().sum())

# 4. 分组提问(第33篇)
汇总 = 宽表.groupby("部门")["销售额"].agg(["sum", "count"])
汇总.columns = ["总销售额", "订单数"]
汇总 = 汇总.reset_index().sort_values("总销售额", ascending=False)

# 5. 导出(今天):一份文件,两页装订
with pd.ExcelWriter("月度销售报表.xlsx") as 装订机:
    汇总.to_excel(装订机, sheet_name="部门汇总", index=False)
    宽表.to_excel(装订机, sheet_name="合并明细", index=False)

print("月度销售报表.xlsx 已生成,发老板吧")

以后每个月的活儿就是重跑这一个程序:数据换新、结果出新——而不是从头再来一遍VLOOKUP。这就是”写下来的流程”比”手工做的流程”值钱的地方。

五、四个必踩的坑(先打疫苗)

坑1:忘了index=False,文件里凭空多一列”序号”。 这是导出第一坑——pandas默认把行号写进文件,Excel里多一列没名字的0、1、2,下次读回来还多一列”Unnamed: 0″,处理起来全是麻烦。疫苗:to_csv/to_excel永远默写index=False,写成肌肉记忆。万一已经导错了,读回来用pd.read_csv(..., index_col=0)把第一列当行号,或干脆重导。

坑2:中文CSV在Excel里打开是乱码。 程序导出好好的,双击用Excel一打开——”部门”变”閮ㄩ棬”。原因是CSV不带格式,Excel打开时按老编码(GBK)猜,而pandas默认写的是新编码(UTF-8),猜错就乱码。疫苗:给中文CSV加encoding="utf-8-sig":报表.to_csv("报表.csv", index=False, encoding="utf-8-sig")——这个”带BOM的UTF-8″是专门喂给Excel的通行证,Excel、WPS、程序全都能正确认。嫌麻烦就直接用to_excel存xlsx,xlsx自带编码信息,永不乱码。

坑3:文件正在Excel里开着,程序报错存不进去。 你导出一次,手动打开看了看,改了改数据重跑程序——报错 PermissionError(”文件被占用”)。因为Excel开着这个文件时会”锁住”它,程序写不进去。疫苗:导出前先把文件关了。这是新手最迷惑的报错之一:代码没改、上次还好好的,怎么就错了?——看看文件是不是还开在Excel里。

坑4:多次to_excel同一个文件,后面的把前面的覆盖了。 你先汇总.to_excel("报表.xlsx", sheet_name="汇总"),又明细.to_excel("报表.xlsx", sheet_name="明细")——打开一看只剩”明细”一页,”汇总”被冲掉了。因为直接to_excel是”重写整个文件”,不是”往里加一页”。疫苗:多页装订必须用with pd.ExcelWriter(...),本文第三节的写法照抄就行。另外xlsx还需要openpyxl这个化妆盒撑场,报 ImportError/”找不到openpyxl”就让AI告诉你安装命令(pip install openpyxl),装一次永久有效。

六、跟AI协作的正确姿势(导出特供)

  1. 用”交付语言”描述需求。说”把汇总表存成’月度报表.xlsx’,sheet名叫’部门汇总’,不要行号;明细存第二个sheet。表头加粗、列宽自适应“——交付格式(xlsx/csv)、文件名、sheet划分、要不要美化,四要素说全。AI最常漏的就是index=False,拿到代码先查这一处
  1. 让AI”先存小样再量产”。追加一句:”先导出前10行让我打开确认格式对,再导全量“。导出的错误(乱码、多列、sheet错位)是”打开文件才发现”的,先开小样验一眼,一分钟省掉一次返工
  1. 报错时把”文件状态”告诉AI。”PermissionError”直接说”文件可能在Excel里开着”(坑3);”乱码”直接说”是Excel打开的CSV”(坑2);”第二个sheet把第一个冲没了”直接说”我用了两次to_excel”(坑4)。导出的坑就这四个,对号入座,AI秒答

高频句式:”把DataFrame存成’某文件.xlsx’,index=False,sheet_name=’某某’,如果多个表就用ExcelWriter装订成多个sheet,表头加粗、列宽自适应。注意中文编码和覆盖问题“。

七、今日小练习

练习1:一式两份

把第33篇的分组报表同时导出成 报表.csv 和 报表.xlsx 两个文件,都不要行号,CSV要能在Excel里正常显示中文。(提示:同一个表连着写两行导出就行。CSV记得 encoding="utf-8-sig"(坑2),xlsx不用管编码。导完用Excel分别打开验货——文件在程序所在的文件夹里。)

练习2:双页报表

造一张”销售明细”表和一张按部门分组的”汇总”表,用ExcelWriter装订成一个 销售报告.xlsx:第一页”汇总”、第二页”明细”。(提示:本文第三节的代码骨架直接用——with pd.ExcelWriter("销售报告.xlsx") as 装订机:,里面写两句to_excel(装订机, sheet_name=..., index=False)。导完打开文件,看底部是不是两个页签。)

练习3:报表化妆师

写一个”导出并美化”的函数:接收表、文件名、sheet名,自动完成导出→表头加粗→列宽自适应→保存,并打印”已完成”。(提示:函数是第7篇的活儿,把第三节的化妆代码整体搬进函数体,参数替换成函数的参数。以后所有导出都喊它,一劳永逸——这就是”把自己的常用动作写成工具”。)

写在后面:从”算出来”到”交出去”

盘点今天:to_csv是落盘——写成通用文本表,给程序和系统用,中文记得utf-8-sig;to_excel是交货——写成xlsx给人看,sheet_name起名、ExcelWriter多页装订、openpyxl化妆加粗和列宽。加上 index=False 这条铁律,”导出”就全齐了。

更值钱的还是思路:分析的价值不在”算出来”,而在”交出去”。屏幕上的一行输出只有你能看见,一个xlsx文件却能被转发、打印、签字、进汇报材料——数据只有离开你的屏幕,才开始产生价值。而”读→问→导”这条流水线一旦写成代码,每个月的报表就是换个数据重跑一次的事。

下一篇,阶段大合练:把读数据、清洗、合并、分组、导出串成一条完整的数据分析流水线——一个程序,从原始数据到成品报表,一键出货。

下篇预告

第三十六篇:阶段项目:数据分析流水线——把第25到35篇的全部功夫串成一条线:原始数据进,成品报表出。一个程序跑完”读→清→合→问→导”全流程,你就是组里那个”报表一小时出、还从不出错”的人。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注