Python实战:利用pandas与openpyxl实现Excel与字典的高效互转
1. 为什么你需要掌握Excel与字典的互转?
如果你经常和Excel打交道,尤其是需要把表格数据拿到Python里处理,或者反过来,把Python里计算好的结果再写回Excel,那你肯定遇到过这样的场景:面对一个几十列、几百行的Excel文件,手动复制粘贴不仅效率低下,还容易出错。这时候,用Python来自动化处理就成了刚需。而在这个过程中,Excel表格和Python的字典(dict) 这两种数据结构之间的转换,可以说是最核心、最高频的操作之一。
我刚开始做数据分析的时候,也总在这件事上踩坑。比如,从Excel读出来的数据,怎么快速变成我熟悉的字典格式,方便后续用键(key)来访问值(value)?又比如,我有一堆字典形式的数据,怎么优雅地、格式漂亮地写进一个新的Excel文件,而不是生成一堆乱七八糟的文本?这些问题,用对了工具和方法,其实几分钟就能搞定。
今天要聊的,就是利用Python里两个非常强大的库——pandas和openpyxl——来解决这个痛点。pandas大家可能比较熟,它读Excel、做数据分析是一把好手;而openpyxl则更专注于Excel文件(尤其是.xlsx格式)的读写和样式编辑,控制力更强。把它们俩结合起来用,一个负责高效读取和初步转换,另一个负责精细化的写入和格式控制,就能实现从Excel到字典,再从字典到Excel的完整、高效的闭环。无论你是要做数据清洗、自动化报表生成,还是搭建一个小型的数据处理流水线,这套组合拳都能让你事半功倍。接下来,我就带你一步步拆解,看看具体怎么操作。
2. 环境准备与工具安装:万事开头易
工欲善其事,必先利其器。在开始写代码之前,我们得先把“厨房”收拾好,把需要的“厨具”备齐。整个过程非常简单,哪怕你是刚接触Python的新手,跟着做也能轻松搞定。
2.1 安装必备的Python库
我们需要安装两个核心库:pandas和openpyxl。打开你的命令行终端(Windows上是CMD或PowerShell,Mac或Linux上是Terminal),输入以下命令:
pip install pandas openpyxl
如果你用的是Anaconda环境,也可以用conda来安装:
conda install pandas openpyxl
这里简单解释一下这两个库的分工。pandas是一个功能极其强大的数据分析库,它内置的read_excel函数可以非常智能地读取Excel文件,并将其转换为DataFrame——这是一种类似表格的二维数据结构,处理起来非常方便。而openpyxl则是一个专门用于读写Excel 2010 xlsx/xlsm/xltx/xltm文件的库,它对Excel文件的支持非常底层和全面,可以精确控制单元格格式、公式、图表等。在我们的场景里,用pandas来读(因为它简单),用openpyxl来写(因为它灵活),算是各取所长。
安装过程通常很快。安装完成后,你可以在Python环境中导入它们试试,不报错就说明成功了:
import pandas as pd
from openpyxl import Workbook
print("库导入成功!")
2.2 准备一个示例Excel文件
为了让大家有更直观的感受,我建议你自己创建一个简单的Excel文件来跟着操作。你可以打开Excel或者WPS,创建一个包含以下几列数据的表格,并保存为sample_data.xlsx:
| 序号 | 产品名称 | 销售额 | 成本 |
|---|---|---|---|
| 1 | 产品A | 15000 | 8000 |
| 2 | 产品B | 22000 | 12000 |
| 3 | 产品C | 9500 | 6000 |
| 4 | 产品D | 18000 | 10000 |
第一行是表头,下面四行是具体数据。把这个文件放在你方便找到的目录下,比如和你的Python脚本放在同一个文件夹里。记住这个文件路径,我们待会儿会用到。当然,你也可以直接用我后面代码里演示的路径,但最好自己动手创建一个,这样理解会更深刻。
3. 从Excel到字典:用pandas轻松读取与转换
现在,我们进入正题的第一部分:如何把Excel表格里的数据,变成Python里方便操作的字典。原始文章里给出的方法是一个基础循环,但用pandas,我们有更高效、更“Pythonic”的做法。
3.1 使用pandas读取Excel文件
首先,我们用pandas的read_excel函数把文件读进来。这个函数非常强大,参数也很多,但我们先从最常用的开始。
import pandas as pd
# 指定你的Excel文件路径
file_path = './sample_data.xlsx' # 假设文件在当前目录下
# 读取Excel,header=0表示第一行作为列名(表头)
raw_data = pd.read_excel(file_path, header=0)
# 看看读进来的是什么
print("读取的DataFrame内容:")
print(raw_data)
print(f"\n数据类型:{type(raw_data)}")
运行这段代码,你会看到类似这样的输出:
读取的DataFrame内容:
序号 产品名称 销售额 成本
0 1 产品A 15000 8000
1 2 产品B 22000 12000
2 3 产品C 9500 6000
3 4 产品D 18000 10000
数据类型:<class 'pandas.core.frame.DataFrame'>
看,pandas不仅把数据读进来了,还自动把第一行“序号”、“产品名称”等识别成了列名,并且给每一行加了一个从0开始的索引(最左边那列)。这个raw_data是一个DataFrame对象,你可以把它想象成一个增强版的、带标签的二维表格,是pandas进行所有数据分析的基石。
3.2 将DataFrame转换为字典的几种高效方法
原始文章里通过循环raw_data.values来构建字典,方法可行,但不够简洁。pandas的DataFrame本身提供了好几种直接转换成字典的方法,更推荐使用。
方法一:to_dict()方法,按行转换为记录列表
这是最常用的一种转换,得到的字典列表(list of dicts)格式,非常符合直觉,每一行数据变成一个字典。
# 使用‘records’参数,将每一行转换为一个字典,所有字典组成一个列表
dict_list = raw_data.to_dict(orient='records')
print("转换后的字典列表:")
print(dict_list)
输出会是:
转换后的字典列表:
[{'序号': 1, '产品名称': '产品A', '销售额': 15000, '成本': 8000},
{'序号': 2, '产品名称': '产品B', '销售额': 22000, '成本': 12000},
{'序号': 3, '产品名称': '产品C', '销售额': 9500, '成本': 6000},
{'序号': 4, '产品名称': '产品D', '销售额': 18000, '成本': 10000}]
这种格式特别适合后续进行逐行处理,比如用for item in dict_list:来遍历每一条记录。
方法二:to_dict()方法,按列转换为字典
有时候我们需要按列来组织数据,比如想快速获取所有“产品名称”的列表。
# 使用‘list’参数,将每一列转换为一个键值对,值是该列所有数据的列表
dict_by_column = raw_data.to_dict(orient='list')
print("\n按列转换的字典:")
print(dict_by_column)
输出:
按列转换的字典:
{'序号': [1, 2, 3, 4],
'产品名称': ['产品A', '产品B', '产品C', '产品D'],
'销售额': [15000, 22000, 9500, 18000],
'成本': [8000, 12000, 6000, 10000]}
方法三:构建自定义映射字典(类似原始文章) 如果你想像原始文章那样,用某一列的值作为键,另一列的值作为值,构建一个一对一的映射字典,可以这样做:
# 假设我们想以‘产品名称’为键,‘销售额’为值
mapping_dict = pd.Series(raw_data.销售额.values, index=raw_data.产品名称).to_dict()
print("\n自定义映射字典(产品->销售额):")
print(mapping_dict)
输出:
自定义映射字典(产品->销售额):
{'产品A': 15000, '产品B': 22000, '产品C': 9500, '产品D': 18000}
这里用到了pd.Series,你可以把它看作一个带索引的一维数组。我们把“产品名称”列设为索引,“销售额”列设为值,然后直接调用.to_dict()就得到了我们想要的映射关系。这种方法比写循环清晰多了。
提示:
to_dict()方法还有其他几种orient参数,比如‘index’、‘split’、‘tight’等,分别适用于不同的场景。当你需要把DataFrame和其他工具交换数据时,可以查阅官方文档选择最合适的格式。
3.3 处理读取时的常见问题与坑
在实际操作中,你可能会遇到原始文章没提到的一些问题,这里我分享几个踩过的坑和解决办法。
坑一:文件路径问题。 Windows下的路径反斜杠\在Python字符串里是转义字符,直接写C:\Users\data.xlsx可能会出错。有三种解决方法:
- 使用原始字符串:
file_path = r‘C:\Users\data.xlsx’ - 使用正斜杠:
file_path = ‘C:/Users/data.xlsx’(Windows也认) - 使用双反斜杠:
file_path = ‘C:\\Users\\data.xlsx’
坑二:表头不在第一行。 如果你的Excel文件第1行是空行或者说明,真正的表头在第3行,可以设置header=2(注意索引从0开始)。
坑三:读取指定工作表。 一个Excel文件可能有多个工作表(Sheet),read_excel默认读第一个。要读名为‘Sheet2’的工作表,可以加参数:pd.read_excel(file_path, sheet_name=‘Sheet2’)。
坑四:处理缺失值。 Excel里的空单元格,pandas读进来会变成NaN(Not a Number)。如果你后续的字典处理不接受NaN,可以在读取时或转换后进行处理,比如用fillna(0)填充为0。
把这些细节处理好,你的数据读取环节就会非常稳健。接下来,我们看看怎么把字典数据漂亮地写回Excel。
4. 从字典到Excel:用openpyxl进行精细化写入
数据在Python里处理完了,最终往往还是要以Excel的形式交付出去,因为这是业务方最熟悉的格式。原始文章介绍了用openpyxl写入的基本步骤,这里我会展开更多实用技巧,让你的输出文件不仅数据正确,而且格式美观、专业。
4.1 基础写入:从字典列表到Excel表格
我们先复现并深化原始文章的例子。假设我们有一个字典列表,每个字典代表一行数据。
from openpyxl import Workbook
# 我们的数据,一个字典列表
sales_data = [
{"月份": "一月", "产品A": 15000, "产品B": 9000, "产品C": 12000},
{"月份": "二月", "产品A": 18000, "产品B": 9500, "产品C": 11000},
{"月份": "三月", "产品A": 22000, "产品B": 12000, "产品C": 15000},
]
# 1. 创建一个工作簿
workbook = Workbook()
# 2. 获取默认的活动工作表
sheet = workbook.active
sheet.title = "季度销售报告" # 给工作表起个名字
# 3. 写入表头。我们需要从字典的键中提取表头,但要确保顺序。
# 假设我们想要‘月份’在第一列,然后是产品A、B、C。
headers = ["月份", "产品A", "产品B", "产品C"]
sheet.append(headers)
# 4. 逐行写入数据
for row_data in sales_data:
# 按照headers的顺序,从每个字典中取出对应的值,组成一个列表
row = [row_data[col] for col in headers]
sheet.append(row)
# 5. 保存工作簿到文件
output_path = "./季度销售报告.xlsx"
workbook.save(output_path)
print(f"文件已保存至:{output_path}")
执行这段代码,你就会在当前目录下得到一个名为“季度销售报告.xlsx”的文件,打开后数据整整齐齐。这里的关键点在于表头的顺序控制。字典本身是无序的(Python 3.7后插入有序,但显式指定顺序仍是好习惯),我们通过预先定义headers列表,确保了写入Excel时列的顺序符合我们的要求。
4.2 进阶技巧:样式美化与多工作表操作
如果只是导出数据,上面那样就够了。但如果你想生成一份可以直接拿去汇报的报表,加点样式会显得更专业。openpyxl的样式功能非常丰富。
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
from openpyxl.utils import get_column_letter
# ... 沿用之前创建workbook和sheet,并写入数据的代码 ...
# 6. 定义样式
# 表头字体加粗、居中、背景色
header_font = Font(bold=True, color="FFFFFF") # 白色加粗字体
header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid") # 蓝色填充
alignment_center = Alignment(horizontal="center", vertical="center")
thin_border = Border(left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin'))
# 7. 应用样式到表头行(第一行)
for col_num, header in enumerate(headers, start=1):
cell = sheet.cell(row=1, column=col_num)
cell.font = header_font
cell.fill = header_fill
cell.alignment = alignment_center
cell.border = thin_border
# 8. 应用样式和数据边框到数据行
for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row, min_col=1, max_col=sheet.max_column):
for cell in row:
cell.alignment = Alignment(horizontal="center") # 数据居中
cell.border = thin_border # 加上边框
# 9. 自动调整列宽(近似)
for column in sheet.columns:
max_length = 0
column_letter = get_column_letter(column[0].column) # 获取列字母
for cell in column:
try:
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
adjusted_width = (max_length + 2)
sheet.column_dimensions[column_letter].width = adjusted_width
# 保存
workbook.save("./美化后的季度报告.xlsx")
现在打开新生成的文件,你会发现表头有了醒目的蓝色背景和白色粗体字,所有单元格都居中对齐并带有细边框,列宽也根据内容自动调整了,看起来就像精心制作的报表一样。
多工作表操作也很常见。比如,你想把不同品类的数据放到同一个Excel文件的不同Sheet里。
# 假设我们有不同品类的数据
category_a_data = [...] # 品类A的数据,字典列表格式
category_b_data = [...] # 品类B的数据
workbook = Workbook()
# 默认Sheet写品类A
sheet_a = workbook.active
sheet_a.title = "品类A"
# ... 写入品类A数据及样式 ...
# 创建新的Sheet写品类B
sheet_b = workbook.create_sheet(title="品类B")
# ... 写入品类B数据及样式 ...
# 可以删除默认创建的多余Sheet(如果有的话)
if "Sheet" in workbook.sheetnames:
std_sheet = workbook["Sheet"]
workbook.remove(std_sheet)
workbook.save("./多品类报告.xlsx")
通过这些进阶操作,你基本上就能应对绝大部分数据导出的需求了,从简单的数据转储到复杂的报表生成,都能胜任。
5. 实战案例:构建一个自动化数据处理小脚本
光说不练假把式。我们把前面学到的知识串起来,设计一个完整的、有点实用价值的小案例。假设你是某电商的数据员,每天会收到一份“原始订单.xlsx”,你需要做两件事:1. 统计每个客户的累计消费金额;2. 生成一份格式清晰的“客户消费统计.xlsx”报表。
步骤1:读取并处理原始数据 假设“原始订单.xlsx”文件格式如下:
| 订单ID | 客户名 | 消费金额 | 日期 |
|---|
我们用pandas读取并处理。
import pandas as pd
# 读取原始订单数据
orders_df = pd.read_excel('./原始订单.xlsx')
# 看看数据
print("原始订单数据预览:")
print(orders_df.head())
# 按‘客户名’分组,汇总‘消费金额’
customer_summary = orders_df.groupby('客户名')['消费金额'].sum().reset_index()
customer_summary.columns = ['客户名', '累计消费金额'] # 重命名列
# 按消费金额降序排列
customer_summary = customer_summary.sort_values(by='累计消费金额', ascending=False)
# 转换为字典列表格式,方便后续openpyxl处理
summary_dict_list = customer_summary.to_dict(orient='records')
print("\n客户消费统计:")
print(customer_summary)
步骤2:用openpyxl生成美化报表
现在我们把summary_dict_list这个字典列表,写入一个新的Excel文件,并加上排名、百分比等列。
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill, numbers
# 创建新工作簿
wb = Workbook()
ws = wb.active
ws.title = "客户消费排名"
# 定义更详细的表头
headers = ["排名", "客户名", "累计消费金额", "占比(%)", "等级"]
# 写入表头
ws.append(headers)
# 计算总金额,用于后续计算占比
total_amount = customer_summary['累计消费金额'].sum()
# 写入数据行,并计算排名和占比
for idx, record in enumerate(summary_dict_list, start=1):
customer_name = record['客户名']
amount = record['累计消费金额']
percentage = (amount / total_amount) * 100
# 简单分级逻辑
if percentage > 20:
level = "VIP"
elif percentage > 5:
level = "重要"
else:
level = "普通"
row = [idx, customer_name, amount, percentage, level]
ws.append(row)
# --- 应用样式(精简版示例)---
# 表头样式
header_fill = PatternFill(start_color="C5D9F1", end_color="C5D9F1", fill_type="solid") # 浅蓝填充
for col in range(1, len(headers) + 1):
cell = ws.cell(row=1, column=col)
cell.font = Font(bold=True)
cell.fill = header_fill
cell.alignment = Alignment(horizontal="center")
# 设置金额和百分比列的格式
for row in ws.iter_rows(min_row=2, max_row=ws.max_row, min_col=3, max_col=4):
for cell in row:
cell.number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1 if cell.column == 3 else numbers.FORMAT_PERCENTAGE_00
# 自动调整列宽
for column_cells in ws.columns:
length = max(len(str(cell.value)) for cell in column_cells)
ws.column_dimensions[column_cells[0].column_letter].width = length + 2
# 保存文件
output_file = "./客户消费统计.xlsx"
wb.save(output_file)
print(f"\n报表已生成:{output_file}")
运行这个脚本,你就能一键完成从原始数据到分析报表的全过程。你可以把这个脚本设置为定时任务(比如用Windows的任务计划或Linux的cron),实现真正的日报自动化。这个案例融合了pandas的数据分组聚合能力和openpyxl的格式化输出能力,体现了二者结合的优势。
6. 性能考量与最佳实践
当数据量变大时,比如要处理几万甚至几十万行数据,我们就需要考虑效率和内存问题了。这里分享一些我积累的经验。
关于读取性能:
pandas的read_excel在读取非常大的Excel文件时,可能会比较慢且耗内存。你可以尝试以下方法:
- 指定列:如果只需要其中几列,使用
usecols参数,例如pd.read_excel(file, usecols=[‘A’, ‘C’, ‘E’])或usecols=‘A:C,E’,能显著减少内存占用和读取时间。 - 分块读取:对于超大型文件,pandas本身没有很好的分块读取Excel功能。一个变通方法是先借助
openpyxl进行一些预处理,或者考虑将Excel文件转换为CSV再用pandas的chunksize读取。但对于日常几兆到几十兆的Excel文件,read_excel直接读通常没问题。 - 引擎选择:
read_excel默认可能使用openpyxl或xlrd引擎。对于.xlsx文件,确保安装并使用了openpyxl。
关于写入性能:
用openpyxl的append方法逐行写入,对于几万行数据是很快的。但如果数据量极大(数十万行),连续调用append也可能变慢。这时可以考虑:
- 批量操作单元格:对于超大数据,可以先将数据组装成一个大的列表,然后直接赋值给一片单元格区域,但这需要更精细的坐标计算。对于绝大多数场景,
append足够了。 - 内存模式:openpyxl提供了只写模式(
write_only=True),在创建Workbook时指定。这种模式下,数据是流式写入磁盘的,内存占用极小,非常适合生成超大型文件。但代价是不能回头修改已写入的内容,也不能使用很多样式功能。除非你确定要生成一个上百万行的、无复杂格式的文件,否则一般用默认模式就好。
from openpyxl import Workbook
wb = Workbook(write_only=True) # 启用只写模式
ws = wb.create_sheet()
# 然后只能使用 ws.append(row) 来添加行,不能使用cell赋值或样式
最佳实践总结:
- 明确分工:pandas主内(数据处理与分析),openpyxl主外(格式控制与写入)。这是核心思路。复杂的计算、筛选、分组用pandas;对单元格样式、公式、多Sheet有严格要求时用openpyxl。
- 善用
to_dict:在pandas内部完成数据到字典的转换,比手动循环高效且不易错。 - 样式模板化:如果你经常要生成格式固定的报表,可以把样式设置代码封装成函数,甚至将带有格式的Excel文件作为模板,用openpyxl加载模板后只填充数据,这样效率更高。
- 路径管理:将输入输出路径、Sheet名称等配置信息放在脚本开头或单独的配置文件中,方便修改和维护。
- 异常处理:在实际脚本中,记得用
try...except包裹文件读写操作,并给出友好的错误提示,比如文件不存在、格式错误等。
掌握了这些,你就能游刃有余地处理日常工作中大部分与Excel相关的数据搬运和报表生成任务了。这套方法的关键在于理解每个工具最适合做什么,然后把它们组合起来,形成一条流畅的自动化流水线。
更多推荐



所有评论(0)