|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在当今数据驱动的世界中,数据处理和分析已成为各行各业不可或缺的技能。Python的pandas库作为数据科学领域最强大的工具之一,提供了丰富的数据操作和分析功能。而Excel作为最广泛使用的数据展示和分享工具,在商业环境中占据着重要地位。将这两者结合,可以极大地提高数据处理的效率和成果的可分享性。本指南将全面介绍如何使用pandas将数据输出到Excel文件,从基础操作到高级技巧,帮助您解决实际工作中的数据保存与分享问题。
基础操作
安装必要的库
在开始之前,我们需要确保安装了必要的库。pandas本身不包含写入Excel文件的功能,需要依赖其他库来实现:
- # 安装pandas和Excel写入引擎
- pip install pandas openpyxl xlsxwriter
复制代码
• pandas: 核心数据处理库
• openpyxl: 用于读写Excel 2010及以上版本的.xlsx文件
• xlsxwriter: 另一个Excel写入引擎,提供更多格式化选项
创建DataFrame并导出到Excel
让我们从最基本的操作开始:创建一个DataFrame并将其导出到Excel文件。
- import pandas as pd
- # 创建一个简单的DataFrame
- data = {
- '姓名': ['张三', '李四', '王五', '赵六'],
- '年龄': [25, 30, 35, 28],
- '城市': ['北京', '上海', '广州', '深圳'],
- '薪资': [8000, 12000, 15000, 10000]
- }
- df = pd.DataFrame(data)
- # 将DataFrame导出到Excel文件
- df.to_excel('员工信息.xlsx', index=False) # index=False表示不写入行索引
复制代码
to_excel()方法是最基本的导出函数,它有几个常用参数:
• excel_writer: 文件路径或ExcelWriter对象
• sheet_name: 工作表名称,默认为’Sheet1’
• na_rep: 用于替换缺失值的字符串,默认为空字符串
• float_format: 浮点数格式字符串,例如’%.2f’表示保留两位小数
• columns: 要写入的列列表
• header: 是否写入列名,默认为True
• index: 是否写入行索引,默认为True
• index_label: 索引列的列标签
控制导出格式
我们可以通过调整参数来控制导出的格式:
- # 导出时控制格式
- df.to_excel(
- '员工信息_格式化.xlsx',
- sheet_name='员工数据', # 设置工作表名称
- na_rep='NULL', # 缺失值替换为NULL
- float_format='%.2f', # 浮点数保留两位小数
- columns=['姓名', '年龄', '城市'], # 只导出指定列
- header=True, # 包含列名
- index=False, # 不包含行索引
- encoding='utf-8' # 设置编码
- )
复制代码
中级技巧
多工作表操作
在实际工作中,我们经常需要将多个DataFrame导出到同一个Excel文件的不同工作表中。这时,我们需要使用ExcelWriter对象:
- import pandas as pd
- # 创建两个DataFrame
- data1 = {
- '产品ID': ['P001', 'P002', 'P003'],
- '产品名称': ['笔记本电脑', '平板电脑', '智能手机'],
- '价格': [5999, 2999, 3999]
- }
- df1 = pd.DataFrame(data1)
- data2 = {
- '订单ID': ['O001', 'O002', 'O003'],
- '产品ID': ['P001', 'P002', 'P003'],
- '数量': [2, 5, 3],
- '日期': ['2023-01-01', '2023-01-02', '2023-01-03']
- }
- df2 = pd.DataFrame(data2)
- # 使用ExcelWriter将多个DataFrame写入同一个Excel文件
- with pd.ExcelWriter('产品与订单.xlsx', engine='openpyxl') as writer:
- df1.to_excel(writer, sheet_name='产品信息', index=False)
- df2.to_excel(writer, sheet_name='订单信息', index=False)
复制代码
设置单元格样式
使用openpyxl引擎,我们可以对Excel文件进行更精细的样式设置:
- import pandas as pd
- from openpyxl import load_workbook
- from openpyxl.styles import Font, PatternFill, Alignment
- # 创建DataFrame
- data = {
- '学生姓名': ['张三', '李四', '王五', '赵六'],
- '语文': [85, 92, 78, 88],
- '数学': [90, 88, 85, 92],
- '英语': [78, 85, 90, 80]
- }
- df = pd.DataFrame(data)
- # 先导出到Excel
- df.to_excel('学生成绩.xlsx', index=False)
- # 然后使用openpyxl加载并修改样式
- book = load_workbook('学生成绩.xlsx')
- sheet = book.active
- # 设置标题行样式
- header_font = Font(name='Arial', bold=True, color='FFFFFF')
- header_fill = PatternFill(start_color='4F81BD', end_color='4F81BD', fill_type='solid')
- header_alignment = Alignment(horizontal='center', vertical='center')
- for cell in sheet[1]: # 第一行是标题
- cell.font = header_font
- cell.fill = header_fill
- cell.alignment = header_alignment
- # 设置数据行样式
- data_font = Font(name='Arial')
- data_alignment = Alignment(horizontal='center', vertical='center')
- for row in sheet.iter_rows(min_row=2): # 从第二行开始是数据
- for cell in row:
- cell.font = data_font
- cell.alignment = data_alignment
- # 调整列宽
- sheet.column_dimensions['A'].width = 12 # 学生姓名列
- for col in ['B', 'C', 'D']: # 成绩列
- sheet.column_dimensions[col].width = 10
- # 保存修改
- book.save('学生成绩_样式化.xlsx')
复制代码
处理日期时间格式
在处理日期时间数据时,我们需要特别注意格式:
- import pandas as pd
- from datetime import datetime, timedelta
- # 创建包含日期的DataFrame
- data = {
- '事件': ['项目启动', '第一阶段完成', '中期评审', '项目完成'],
- '开始日期': [
- datetime(2023, 1, 1),
- datetime(2023, 2, 15),
- datetime(2023, 4, 1),
- datetime(2023, 6, 30)
- ],
- '持续天数': [45, 30, 15, 0]
- }
- df = pd.DataFrame(data)
- # 导出到Excel,并设置日期格式
- with pd.ExcelWriter('项目时间表.xlsx', engine='xlsxwriter', datetime_format='yyyy-mm-dd') as writer:
- df.to_excel(writer, sheet_name='项目进度', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['项目进度']
-
- # 设置列宽
- worksheet.set_column('A:A', 15) # 事件列
- worksheet.set_column('B:B', 12) # 开始日期列
- worksheet.set_column('C:C', 10) # 持续天数列
复制代码
高级应用
添加条件格式
条件格式可以帮助我们突出显示满足特定条件的数据:
- import pandas as pd
- # 创建销售数据DataFrame
- data = {
- '销售员': ['张三', '李四', '王五', '赵六', '钱七'],
- '一月': [12000, 15000, 9000, 18000, 11000],
- '二月': [13000, 14000, 9500, 17000, 12000],
- '三月': [12500, 16000, 10000, 17500, 11500]
- }
- df = pd.DataFrame(data)
- # 计算季度总额
- df['季度总额'] = df[['一月', '二月', '三月']].sum(axis=1)
- # 导出到Excel并添加条件格式
- with pd.ExcelWriter('销售数据_条件格式.xlsx', engine='xlsxwriter') as writer:
- df.to_excel(writer, sheet_name='销售数据', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['销售数据']
-
- # 添加条件格式:销售额大于15000的单元格背景设为绿色
- green_format = workbook.add_format({'bg_color': '#C6EFCE', 'font_color': '#006100'})
-
- # 为每个月的数据列添加条件格式
- for col in range(2, 5): # B, C, D列
- worksheet.conditional_format(
- 1, col, len(df), col, # 从第2行到最后一行
- {'type': 'cell', 'criteria': '>', 'value': 15000, 'format': green_format}
- )
-
- # 添加条件格式:季度总额最高的行设为蓝色
- blue_format = workbook.add_format({'bg_color': '#DBEEF4', 'font_color': '#0066CC'})
-
- # 找出季度总额最高的行索引
- max_index = df['季度总额'].idxmax()
-
- # 为该行添加蓝色背景
- for col in range(1, len(df.columns) + 1): # 所有列
- worksheet.conditional_format(
- max_index + 1, col - 1, max_index + 1, col - 1, # 特定行
- {'type': 'formula', 'criteria': 'TRUE', 'format': blue_format}
- )
复制代码
创建图表
Excel中的图表是数据可视化的重要工具,我们可以使用xlsxwriter创建各种图表:
- import pandas as pd
- import numpy as np
- # 创建销售数据
- np.random.seed(42)
- months = ['一月', '二月', '三月', '四月', '五月', '六月']
- products = ['产品A', '产品B', '产品C', '产品D']
- data = {
- '月份': months * 4,
- '产品': np.repeat(products, 6),
- '销售额': np.random.randint(5000, 20000, 24)
- }
- df = pd.DataFrame(data)
- # 透视表数据,便于图表展示
- pivot_df = df.pivot(index='月份', columns='产品', values='销售额')
- # 导出到Excel并创建图表
- with pd.ExcelWriter('销售数据_图表.xlsx', engine='xlsxwriter') as writer:
- pivot_df.to_excel(writer, sheet_name='销售数据')
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['销售数据']
-
- # 创建图表对象
- chart = workbook.add_chart({'type': 'column'})
-
- # 配置图表数据系列
- for i, product in enumerate(products):
- chart.add_series({
- 'name': ['销售数据', 0, i + 1], # 系列名称
- 'categories': ['销售数据', 1, 0, len(months), 0], # X轴标签
- 'values': ['销售数据', 1, i + 1, len(months), i + 1], # Y轴值
- 'fill': {'color': ['#4472C4', '#ED7D31', '#A5A5A5', '#FFC000'][i]}, # 柱状图颜色
- })
-
- # 添加图表标题和轴标签
- chart.set_title({'name': '月度产品销售额'})
- chart.set_x_axis({'name': '月份'})
- chart.set_y_axis({'name': '销售额'})
-
- # 将图表插入工作表
- worksheet.insert_chart('G2', chart)
-
- # 创建第二个图表:饼图
- pie_chart = workbook.add_chart({'type': 'pie'})
-
- # 计算各产品总销售额
- total_sales = df.groupby('产品')['销售额'].sum().reset_index()
-
- # 添加饼图数据系列
- pie_chart.add_series({
- 'name': '产品销售额占比',
- 'categories': [f'销售数据', len(months) + 2, 1, len(months) + 2 + len(products) - 1, 1],
- 'values': [f'销售数据', len(months) + 2, 2, len(months) + 2 + len(products) - 1, 2],
- 'data_labels': {'percentage': True},
- })
-
- # 设置饼图标题
- pie_chart.set_title({'name': '产品销售额占比'})
-
- # 将饼图插入工作表
- worksheet.insert_chart('G20', pie_chart)
复制代码
添加数据验证
数据验证可以帮助确保输入数据的准确性:
- import pandas as pd
- # 创建一个简单的员工信息表
- data = {
- '员工ID': ['E001', 'E002', 'E003', 'E004'],
- '姓名': ['张三', '李四', '王五', '赵六'],
- '部门': ['技术部', '市场部', '财务部', '技术部'],
- '职级': ['P3', 'P2', 'P4', 'P3'],
- '入职日期': ['2020-01-15', '2019-05-20', '2021-03-10', '2022-06-01']
- }
- df = pd.DataFrame(data)
- # 导出到Excel并添加数据验证
- with pd.ExcelWriter('员工信息_数据验证.xlsx', engine='xlsxwriter') as writer:
- df.to_excel(writer, sheet_name='员工信息', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['员工信息']
-
- # 添加部门下拉列表验证
- department_list = ['技术部', '市场部', '财务部', '人力资源部', '运营部']
- worksheet.data_validation(
- 'C2:C100', # 应用验证的单元格范围
- {
- 'validate': 'list',
- 'source': department_list,
- 'input_title': '选择部门:',
- 'input_message': '请从下拉列表中选择部门',
- }
- )
-
- # 添加职级下拉列表验证
- level_list = ['P1', 'P2', 'P3', 'P4', 'P5', 'M1', 'M2', 'M3']
- worksheet.data_validation(
- 'D2:D100', # 应用验证的单元格范围
- {
- 'validate': 'list',
- 'source': level_list,
- 'input_title': '选择职级:',
- 'input_message': '请从下拉列表中选择职级',
- }
- )
-
- # 添加入职日期验证(不能晚于今天)
- worksheet.data_validation(
- 'E2:E100', # 应用验证的单元格范围
- {
- 'validate': 'date',
- 'criteria': 'less than or equal to',
- 'value': '=TODAY()',
- 'input_title': '入职日期:',
- 'input_message': '请输入有效的入职日期(不能晚于今天)',
- 'error_title': '输入错误',
- 'error_message': '入职日期不能晚于今天'
- }
- )
复制代码
添加公式
我们可以在Excel中添加公式,使数据更加动态和有用:
- import pandas as pd
- # 创建销售数据
- data = {
- '产品': ['产品A', '产品B', '产品C', '产品D'],
- '单价': [100, 150, 200, 120],
- '数量': [50, 30, 25, 40],
- '折扣率': [0.9, 0.85, 0.95, 0.88]
- }
- df = pd.DataFrame(data)
- # 导出到Excel并添加公式
- with pd.ExcelWriter('销售数据_公式.xlsx', engine='xlsxwriter') as writer:
- df.to_excel(writer, sheet_name='销售数据', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['销售数据']
-
- # 添加表头
- worksheet.write(0, 4, '折扣后单价') # E列
- worksheet.write(0, 5, '小计') # F列
- worksheet.write(0, 6, '税率') # G列
- worksheet.write(0, 7, '税额') # H列
- worksheet.write(0, 8, '总计') # I列
-
- # 设置税率(所有行相同)
- tax_rate = 0.13
- for row in range(1, len(df) + 1):
- worksheet.write(row, 6, tax_rate) # 税率列
-
- # 添加公式
- for row in range(1, len(df) + 1):
- # 折扣后单价 = 单价 * 折扣率
- worksheet.write_formula(
- row, 4, # E列
- f'=B{row+1}*D{row+1}',
- value=df['单价'][row-1] * df['折扣率'][row-1] # 计算值,用于Excel在未打开时显示
- )
-
- # 小计 = 折扣后单价 * 数量
- worksheet.write_formula(
- row, 5, # F列
- f'=E{row+1}*C{row+1}',
- value=(df['单价'][row-1] * df['折扣率'][row-1]) * df['数量'][row-1]
- )
-
- # 税额 = 小计 * 税率
- worksheet.write_formula(
- row, 7, # H列
- f'=F{row+1}*G{row+1}',
- value=((df['单价'][row-1] * df['折扣率'][row-1]) * df['数量'][row-1]) * tax_rate
- )
-
- # 总计 = 小计 + 税额
- worksheet.write_formula(
- row, 8, # I列
- f'=F{row+1}+H{row+1}',
- value=((df['单价'][row-1] * df['折扣率'][row-1]) * df['数量'][row-1]) +
- ((df['单价'][row-1] * df['折扣率'][row-1]) * df['数量'][row-1]) * tax_rate
- )
-
- # 添加总计行
- total_row = len(df) + 1
- worksheet.write(total_row, 0, '总计')
-
- # 添加总计公式
- for col in [2, 4, 5, 7, 8]: # 数量、折扣后单价、小计、税额、总计列
- col_letter = chr(65 + col) # A=65, B=66, ...
- worksheet.write_formula(
- total_row, col,
- f'=SUM({col_letter}2:{col_letter}{len(df)})'
- )
-
- # 添加平均单价行
- avg_row = len(df) + 2
- worksheet.write(avg_row, 0, '平均单价')
- worksheet.write_formula(
- avg_row, 1, # B列(单价列)
- f'=AVERAGE(B2:B{len(df)})'
- )
复制代码
性能优化
处理大数据量
当处理大量数据时,直接导出到Excel可能会遇到内存问题。以下是几种优化方法:
- import pandas as pd
- import numpy as np
- # 创建大型DataFrame(100万行)
- np.random.seed(42)
- large_df = pd.DataFrame({
- 'ID': range(1, 1000001),
- '值1': np.random.rand(1000000),
- '值2': np.random.randn(1000000),
- '类别': np.random.choice(['A', 'B', 'C', 'D'], 1000000)
- })
- # 方法1:分块写入
- def chunked_export(df, file_path, chunk_size=100000):
- """
- 将大型DataFrame分块写入Excel文件
-
- 参数:
- df: 要导出的DataFrame
- file_path: 输出文件路径
- chunk_size: 每块的行数
- """
- writer = pd.ExcelWriter(file_path, engine='openpyxl')
-
- # 写入第一块(包含表头)
- df.iloc[:chunk_size].to_excel(writer, sheet_name='大数据', index=False)
-
- # 追加剩余块
- for i in range(chunk_size, len(df), chunk_size):
- df.iloc[i:i+chunk_size].to_excel(
- writer,
- sheet_name='大数据',
- index=False,
- startrow=i+1, # +1 因为表头占了一行
- header=False # 不包含表头
- )
-
- writer.save()
- # 使用分块方法导出大型DataFrame
- chunked_export(large_df, '大型数据_分块.xlsx')
- # 方法2:使用csv格式作为中间格式(对于非常大的数据集)
- # 首先导出到CSV
- large_df.to_csv('大型数据_中间.csv', index=False)
- # 然后使用Excel的数据导入功能(这里用代码模拟)
- # 在实际应用中,可以手动在Excel中导入CSV文件,或者使用其他库如pyxlsb处理二进制Excel格式
- # 方法3:只导出必要的数据
- # 如果只需要部分数据,可以先筛选再导出
- filtered_df = large_df[large_df['类别'].isin(['A', 'B'])] # 只导出类别为A和B的数据
- filtered_df.to_excel('大型数据_筛选.xlsx', index=False)
复制代码
优化内存使用
在处理大型数据集时,优化内存使用非常重要:
- import pandas as pd
- import numpy as np
- # 创建大型DataFrame
- np.random.seed(42)
- large_df = pd.DataFrame({
- 'ID': range(1, 1000001),
- '值1': np.random.rand(1000000),
- '值2': np.random.randn(1000000),
- '类别': np.random.choice(['A', 'B', 'C', 'D'], 1000000),
- '日期': pd.date_range('2020-01-01', periods=1000000, freq='D')
- })
- # 优化数据类型以减少内存使用
- def optimize_memory(df):
- """
- 优化DataFrame的内存使用
-
- 参数:
- df: 要优化的DataFrame
-
- 返回:
- 优化后的DataFrame
- """
- optimized_df = df.copy()
-
- for col in optimized_df.columns:
- col_type = optimized_df[col].dtype
-
- if col_type == 'object':
- # 对象类型转换为类别类型(如果唯一值较少)
- num_unique_values = len(optimized_df[col].unique())
- num_total_values = len(optimized_df[col])
- if num_unique_values / num_total_values < 0.5:
- optimized_df[col] = optimized_df[col].astype('category')
-
- elif col_type == 'float64':
- # 64位浮点数转换为32位浮点数
- optimized_df[col] = pd.to_numeric(optimized_df[col], downcast='float')
-
- elif col_type == 'int64':
- # 64位整数转换为更小的整数类型
- optimized_df[col] = pd.to_numeric(optimized_df[col], downcast='integer')
-
- return optimized_df
- # 优化DataFrame
- optimized_df = optimize_memory(large_df)
- # 比较内存使用
- print(f"原始DataFrame内存使用: {large_df.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
- print(f"优化后DataFrame内存使用: {optimized_df.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
- # 导出优化后的DataFrame
- optimized_df.to_excel('大型数据_内存优化.xlsx', index=False)
复制代码
实际案例
案例1:销售报告自动化
假设我们需要每月生成销售报告,包含数据汇总、图表和格式化输出:
- import pandas as pd
- import numpy as np
- from datetime import datetime, timedelta
- # 模拟销售数据
- np.random.seed(42)
- date_range = pd.date_range('2023-01-01', '2023-06-30')
- products = ['产品A', '产品B', '产品C', '产品D']
- regions = ['华北', '华东', '华南', '华中', '西北', '西南', '东北']
- # 生成随机销售数据
- sales_data = []
- for _ in range(5000): # 5000条销售记录
- sales_data.append({
- '日期': np.random.choice(date_range),
- '产品': np.random.choice(products),
- '地区': np.random.choice(regions),
- '销售额': np.random.randint(1000, 50000),
- '数量': np.random.randint(1, 100)
- })
- sales_df = pd.DataFrame(sales_data)
- # 创建报告函数
- def create_sales_report(df, report_month, output_file):
- """
- 创建月度销售报告
-
- 参数:
- df: 包含销售数据的DataFrame
- report_month: 报告月份,格式为'YYYY-MM'
- output_file: 输出文件路径
- """
- # 筛选指定月份的数据
- df['月份'] = df['日期'].dt.strftime('%Y-%m')
- month_df = df[df['月份'] == report_month].copy()
-
- if month_df.empty:
- print(f"没有找到{report_month}的销售数据")
- return
-
- # 计算各种汇总数据
- product_sales = month_df.groupby('产品')['销售额'].sum().reset_index()
- region_sales = month_df.groupby('地区')['销售额'].sum().reset_index()
- daily_sales = month_df.groupby('日期')['销售额'].sum().reset_index()
-
- # 创建Excel写入器
- with pd.ExcelWriter(output_file, engine='xlsxwriter', datetime_format='yyyy-mm-dd') as writer:
- # 写入原始数据
- month_df.to_excel(writer, sheet_name='原始数据', index=False)
-
- # 写入产品销售汇总
- product_sales.to_excel(writer, sheet_name='产品销售汇总', index=False)
-
- # 写入地区销售汇总
- region_sales.to_excel(writer, sheet_name='地区销售汇总', index=False)
-
- # 写入每日销售趋势
- daily_sales.to_excel(writer, sheet_name='每日销售趋势', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['产品销售汇总']
-
- # 创建产品销售饼图
- pie_chart = workbook.add_chart({'type': 'pie'})
-
- pie_chart.add_series({
- 'name': '产品销售占比',
- 'categories': ['产品销售汇总', 1, 0, len(product_sales), 0],
- 'values': ['产品销售汇总', 1, 1, len(product_sales), 1],
- 'data_labels': {'percentage': True, 'category': True},
- })
-
- pie_chart.set_title({'name': f'{report_month} 产品销售占比'})
- worksheet.insert_chart('D2', pie_chart)
-
- # 创建地区销售条形图
- bar_chart = workbook.add_chart({'type': 'bar'})
-
- bar_chart.add_series({
- 'name': '地区销售额',
- 'categories': ['地区销售汇总', 1, 0, len(region_sales), 0],
- 'values': ['地区销售汇总', 1, 1, len(region_sales), 1],
- })
-
- bar_chart.set_title({'name': f'{report_month} 地区销售额'})
- bar_chart.set_x_axis({'name': '销售额'})
- worksheet = writer.sheets['地区销售汇总']
- worksheet.insert_chart('D2', bar_chart)
-
- # 创建每日销售折线图
- line_chart = workbook.add_chart({'type': 'line'})
-
- line_chart.add_series({
- 'name': '每日销售额',
- 'categories': ['每日销售趋势', 1, 0, len(daily_sales), 0],
- 'values': ['每日销售趋势', 1, 1, len(daily_sales), 1],
- 'marker': {'type': 'circle', 'size': 4, 'border': {'color': 'black'}, 'fill': {'color': 'red'}},
- })
-
- line_chart.set_title({'name': f'{report_month} 每日销售趋势'})
- line_chart.set_x_axis({'name': '日期'})
- line_chart.set_y_axis({'name': '销售额'})
- worksheet = writer.sheets['每日销售趋势']
- worksheet.insert_chart('D2', line_chart)
-
- # 创建汇总报告工作表
- summary_sheet = workbook.add_worksheet('汇总报告')
-
- # 添加报告标题
- title_format = workbook.add_format({
- 'bold': True,
- 'font_size': 16,
- 'align': 'center',
- 'valign': 'vcenter'
- })
- summary_sheet.merge_range('A1:D1', f'{report_month} 销售报告', title_format)
-
- # 添加关键指标
- metrics = [
- ['总销售额', month_df['销售额'].sum()],
- ['平均单笔销售额', month_df['销售额'].mean()],
- ['销售记录数', len(month_df)],
- ['销售产品数', month_df['产品'].nunique()],
- ['覆盖地区数', month_df['地区'].nunique()],
- ['最高单日销售额', daily_sales['销售额'].max()],
- ['最低单日销售额', daily_sales['销售额'].min()]
- ]
-
- # 写入指标
- header_format = workbook.add_format({
- 'bold': True,
- 'bg_color': '#4F81BD',
- 'font_color': 'white',
- 'border': 1
- })
-
- cell_format = workbook.add_format({
- 'border': 1,
- 'num_format': '#,##0.00'
- })
-
- summary_sheet.write(3, 0, '关键指标', header_format)
- summary_sheet.write(3, 1, '数值', header_format)
-
- for i, (metric, value) in enumerate(metrics):
- summary_sheet.write(4 + i, 0, metric, cell_format)
- summary_sheet.write(4 + i, 1, value, cell_format)
-
- # 设置列宽
- summary_sheet.set_column('A:A', 20)
- summary_sheet.set_column('B:B', 15)
- # 创建2023年6月的销售报告
- create_sales_report(sales_df, '2023-06', '2023年6月销售报告.xlsx')
复制代码
案例2:财务数据导出与分析
在财务工作中,经常需要将数据导出到Excel并进行进一步分析:
- import pandas as pd
- import numpy as np
- from datetime import datetime, timedelta
- # 模拟财务数据
- np.random.seed(42)
- date_range = pd.date_range('2023-01-01', '2023-06-30')
- accounts = ['现金', '应收账款', '存货', '固定资产', '应付账款', '短期借款', '长期借款', '实收资本', '未分配利润']
- departments = ['销售部', '市场部', '研发部', '行政部', '财务部']
- # 生成随机财务数据
- financial_data = []
- for date in date_range:
- for account in accounts:
- financial_data.append({
- '日期': date,
- '科目': account,
- '借方金额': np.random.uniform(0, 100000) if np.random.random() > 0.5 else 0,
- '贷方金额': np.random.uniform(0, 100000) if np.random.random() > 0.5 else 0,
- '部门': np.random.choice(departments),
- '备注': np.random.choice(['日常业务', '特殊业务', '调整业务', '期末处理'])
- })
- financial_df = pd.DataFrame(financial_data)
- # 创建财务分析报告
- def create_financial_report(df, start_date, end_date, output_file):
- """
- 创建财务分析报告
-
- 参数:
- df: 包含财务数据的DataFrame
- start_date: 开始日期,格式为'YYYY-MM-DD'
- end_date: 结束日期,格式为'YYYY-MM-DD'
- output_file: 输出文件路径
- """
- # 筛选日期范围
- mask = (df['日期'] >= start_date) & (df['日期'] <= end_date)
- period_df = df.loc[mask].copy()
-
- if period_df.empty:
- print(f"没有找到{start_date}至{end_date}的财务数据")
- return
-
- # 计算科目余额
- balance_df = period_df.groupby('科目').agg({
- '借方金额': 'sum',
- '贷方金额': 'sum'
- }).reset_index()
- balance_df['余额'] = balance_df['借方金额'] - balance_df['贷方金额']
-
- # 计算部门收支
- dept_df = period_df.groupby('部门').agg({
- '借方金额': 'sum',
- '贷方金额': 'sum'
- }).reset_index()
- dept_df['净额'] = dept_df['贷方金额'] - dept_df['借方金额']
-
- # 计算每日收支
- daily_df = period_df.groupby('日期').agg({
- '借方金额': 'sum',
- '贷方金额': 'sum'
- }).reset_index()
- daily_df['净额'] = daily_df['贷方金额'] - daily_df['借方金额']
-
- # 创建Excel写入器
- with pd.ExcelWriter(output_file, engine='xlsxwriter', datetime_format='yyyy-mm-dd') as writer:
- # 写入原始数据
- period_df.to_excel(writer, sheet_name='原始数据', index=False)
-
- # 写入科目余额
- balance_df.to_excel(writer, sheet_name='科目余额', index=False)
-
- # 写入部门收支
- dept_df.to_excel(writer, sheet_name='部门收支', index=False)
-
- # 写入每日收支
- daily_df.to_excel(writer, sheet_name='每日收支', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
-
- # 创建科目余额工作表格式
- worksheet = writer.sheets['科目余额']
-
- # 添加条件格式:借方余额设为红色,贷方余额设为绿色
- red_format = workbook.add_format({'bg_color': '#FFC7CE', 'font_color': '#9C0006'})
- green_format = workbook.add_format({'bg_color': '#C6EFCE', 'font_color': '#006100'})
-
- # 为余额列添加条件格式
- worksheet.conditional_format(
- 1, 3, len(balance_df), 3, # 余额列
- {'type': 'cell', 'criteria': '>', 'value': 0, 'format': red_format}
- )
- worksheet.conditional_format(
- 1, 3, len(balance_df), 3, # 余额列
- {'type': 'cell', 'criteria': '<', 'value': 0, 'format': green_format}
- )
-
- # 创建部门收支条形图
- bar_chart = workbook.add_chart({'type': 'column'})
-
- bar_chart.add_series({
- 'name': '支出',
- 'categories': ['部门收支', 1, 0, len(dept_df), 0],
- 'values': ['部门收支', 1, 1, len(dept_df), 1],
- 'fill': {'color': '#FF0000'},
- })
-
- bar_chart.add_series({
- 'name': '收入',
- 'categories': ['部门收支', 1, 0, len(dept_df), 0],
- 'values': ['部门收支', 1, 2, len(dept_df), 2],
- 'fill': {'color': '#00FF00'},
- })
-
- bar_chart.set_title({'name': f'{start_date} 至 {end_date} 部门收支对比'})
- bar_chart.set_x_axis({'name': '部门'})
- bar_chart.set_y_axis({'name': '金额'})
-
- worksheet = writer.sheets['部门收支']
- worksheet.insert_chart('F2', bar_chart)
-
- # 创建每日收支折线图
- line_chart = workbook.add_chart({'type': 'line'})
-
- line_chart.add_series({
- 'name': '支出',
- 'categories': ['每日收支', 1, 0, len(daily_df), 0],
- 'values': ['每日收支', 1, 1, len(daily_df), 1],
- 'line': {'color': '#FF0000'},
- 'marker': {'type': 'circle', 'size': 4, 'border': {'color': 'black'}, 'fill': {'color': 'red'}},
- })
-
- line_chart.add_series({
- 'name': '收入',
- 'categories': ['每日收支', 1, 0, len(daily_df), 0],
- 'values': ['每日收支', 1, 2, len(daily_df), 2],
- 'line': {'color': '#00FF00'},
- 'marker': {'type': 'square', 'size': 4, 'border': {'color': 'black'}, 'fill': {'color': 'green'}},
- })
-
- line_chart.add_series({
- 'name': '净额',
- 'categories': ['每日收支', 1, 0, len(daily_df), 0],
- 'values': ['每日收支', 1, 3, len(daily_df), 3],
- 'line': {'color': '#0000FF'},
- 'marker': {'type': 'triangle', 'size': 4, 'border': {'color': 'black'}, 'fill': {'color': 'blue'}},
- })
-
- line_chart.set_title({'name': f'{start_date} 至 {end_date} 每日收支趋势'})
- line_chart.set_x_axis({'name': '日期'})
- line_chart.set_y_axis({'name': '金额'})
-
- worksheet = writer.sheets['每日收支']
- worksheet.insert_chart('F2', line_chart)
-
- # 创建财务汇总工作表
- summary_sheet = workbook.add_worksheet('财务汇总')
-
- # 添加报告标题
- title_format = workbook.add_format({
- 'bold': True,
- 'font_size': 16,
- 'align': 'center',
- 'valign': 'vcenter'
- })
- summary_sheet.merge_range('A1:D1', f'{start_date} 至 {end_date} 财务汇总', title_format)
-
- # 添加财务指标
- metrics = [
- ['总收入', period_df['贷方金额'].sum()],
- ['总支出', period_df['借方金额'].sum()],
- ['净收支', period_df['贷方金额'].sum() - period_df['借方金额'].sum()],
- ['平均每日收入', daily_df['贷方金额'].mean()],
- ['平均每日支出', daily_df['借方金额'].mean()],
- ['最高单日收入', daily_df['贷方金额'].max()],
- ['最高单日支出', daily_df['借方金额'].max()],
- ['交易笔数', len(period_df)]
- ]
-
- # 写入指标
- header_format = workbook.add_format({
- 'bold': True,
- 'bg_color': '#4F81BD',
- 'font_color': 'white',
- 'border': 1
- })
-
- cell_format = workbook.add_format({
- 'border': 1,
- 'num_format': '#,##0.00'
- })
-
- summary_sheet.write(3, 0, '财务指标', header_format)
- summary_sheet.write(3, 1, '数值', header_format)
-
- for i, (metric, value) in enumerate(metrics):
- summary_sheet.write(4 + i, 0, metric, cell_format)
- summary_sheet.write(4 + i, 1, value, cell_format)
-
- # 设置列宽
- summary_sheet.set_column('A:A', 20)
- summary_sheet.set_column('B:B', 15)
-
- # 添加科目余额明细
- summary_sheet.write(3, 3, '科目余额明细', header_format)
- summary_sheet.write(4, 3, '科目', header_format)
- summary_sheet.write(4, 4, '余额', header_format)
-
- for i, (_, row) in enumerate(balance_df.iterrows()):
- summary_sheet.write(5 + i, 3, row['科目'], cell_format)
- summary_sheet.write(5 + i, 4, row['余额'], cell_format)
-
- summary_sheet.set_column('D:D', 15)
- summary_sheet.set_column('E:E', 15)
- # 创建2023年第二季度的财务报告
- create_financial_report(financial_df, '2023-04-01', '2023-06-30', '2023年Q2财务报告.xlsx')
复制代码
常见问题与解决方案
问题1:导出的Excel文件打不开或损坏
原因:可能是由于数据量过大、格式不兼容或写入过程中出错导致的。
解决方案:
- import pandas as pd
- # 创建一个简单的DataFrame
- data = {
- '姓名': ['张三', '李四', '王五'],
- '年龄': [25, 30, 35],
- '城市': ['北京', '上海', '广州']
- }
- df = pd.DataFrame(data)
- # 方法1:使用不同的引擎
- try:
- # 尝试使用openpyxl引擎
- df.to_excel('测试_openpyxl.xlsx', index=False, engine='openpyxl')
- print("使用openpyxl引擎导出成功")
- except Exception as e:
- print(f"openpyxl引擎导出失败: {e}")
-
- try:
- # 尝试使用xlsxwriter引擎
- df.to_excel('测试_xlsxwriter.xlsx', index=False, engine='xlsxwriter')
- print("使用xlsxwriter引擎导出成功")
- except Exception as e2:
- print(f"xlsxwriter引擎导出失败: {e2}")
- # 方法2:分块写入大数据
- def safe_export_large_data(df, file_path, chunk_size=10000):
- """
- 安全地导出大型DataFrame到Excel
-
- 参数:
- df: 要导出的DataFrame
- file_path: 输出文件路径
- chunk_size: 每块的行数
- """
- try:
- if len(df) <= chunk_size:
- # 如果数据量小,直接导出
- df.to_excel(file_path, index=False)
- else:
- # 如果数据量大,分块导出
- writer = pd.ExcelWriter(file_path, engine='openpyxl')
-
- # 写入第一块(包含表头)
- df.iloc[:chunk_size].to_excel(writer, sheet_name='数据', index=False)
-
- # 追加剩余块
- for i in range(chunk_size, len(df), chunk_size):
- df.iloc[i:i+chunk_size].to_excel(
- writer,
- sheet_name='数据',
- index=False,
- startrow=i+1, # +1 因为表头占了一行
- header=False # 不包含表头
- )
-
- writer.close()
-
- print(f"数据成功导出到 {file_path}")
- except Exception as e:
- print(f"导出失败: {e}")
-
- # 尝试使用CSV格式作为备选方案
- csv_path = file_path.replace('.xlsx', '.csv')
- try:
- df.to_csv(csv_path, index=False, encoding='utf-8-sig')
- print(f"已使用CSV格式导出到 {csv_path}")
- except Exception as e2:
- print(f"CSV导出也失败: {e2}")
- # 模拟大型DataFrame
- import numpy as np
- large_df = pd.DataFrame({
- 'ID': range(1, 100001),
- '值': np.random.rand(100000)
- })
- # 使用安全导出方法
- safe_export_large_data(large_df, '大型数据_安全导出.xlsx')
复制代码
问题2:日期时间格式不正确
原因:Excel和Python对日期时间的处理方式不同,可能导致格式显示不正确。
解决方案:
- import pandas as pd
- from datetime import datetime
- # 创建包含日期的DataFrame
- data = {
- '事件': ['项目启动', '第一阶段完成', '中期评审', '项目完成'],
- '日期': [
- datetime(2023, 1, 1),
- datetime(2023, 2, 15),
- datetime(2023, 4, 1),
- datetime(2023, 6, 30)
- ],
- '时间': [
- datetime(2023, 1, 1, 9, 30),
- datetime(2023, 2, 15, 14, 45),
- datetime(2023, 4, 1, 10, 15),
- datetime(2023, 6, 30, 16, 0)
- ]
- }
- df = pd.DataFrame(data)
- # 方法1:使用datetime_format参数
- with pd.ExcelWriter('日期时间_格式化1.xlsx', engine='xlsxwriter',
- datetime_format='yyyy-mm-dd') as writer:
- df.to_excel(writer, sheet_name='项目时间表', index=False)
- # 方法2:分别设置日期和时间格式
- with pd.ExcelWriter('日期时间_格式化2.xlsx', engine='xlsxwriter') as writer:
- df.to_excel(writer, sheet_name='项目时间表', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['项目时间表']
-
- # 设置日期格式
- date_format = workbook.add_format({'num_format': 'yyyy-mm-dd'})
- time_format = workbook.add_format({'num_format': 'hh:mm:ss'})
-
- # 应用日期格式
- for row in range(1, len(df) + 1):
- worksheet.write_datetime(row, 2, df['日期'][row-1], date_format)
- worksheet.write_datetime(row, 3, df['时间'][row-1], time_format)
- # 方法3:使用openpyxl设置格式
- df.to_excel('日期时间_格式化3.xlsx', index=False)
- from openpyxl import load_workbook
- from openpyxl.styles import numbers
- book = load_workbook('日期时间_格式化3.xlsx')
- sheet = book.active
- # 设置日期格式
- for row in range(2, len(df) + 2): # +2 因为第一行是表头,索引从1开始
- sheet.cell(row=row, column=3).number_format = 'YYYY-MM-DD' # 日期列
- sheet.cell(row=row, column=4).number_format = 'HH:MM:SS' # 时间列
- book.save('日期时间_格式化3.xlsx')
复制代码
问题3:中文显示乱码
原因:编码问题可能导致中文字符在Excel中显示为乱码。
解决方案:
- import pandas as pd
- # 创建包含中文的DataFrame
- data = {
- '姓名': ['张三', '李四', '王五', '赵六'],
- '部门': ['技术部', '市场部', '财务部', '人力资源部'],
- '备注': ['优秀员工', '表现良好', '需要改进', '新员工']
- }
- df = pd.DataFrame(data)
- # 方法1:使用utf-8-sig编码(适用于CSV)
- df.to_csv('中文数据.csv', index=False, encoding='utf-8-sig')
- # 方法2:使用openpyxl引擎(适用于xlsx)
- df.to_excel('中文数据_openpyxl.xlsx', index=False, engine='openpyxl')
- # 方法3:使用xlsxwriter引擎并设置字体
- with pd.ExcelWriter('中文数据_xlsxwriter.xlsx', engine='xlsxwriter') as writer:
- df.to_excel(writer, sheet_name='员工信息', index=False)
-
- # 获取xlsxwriter对象
- workbook = writer.book
- worksheet = writer.sheets['员工信息']
-
- # 添加支持中文的字体格式
- chinese_font = workbook.add_format({'font_name': 'Microsoft YaHei', 'font_size': 11})
-
- # 应用格式到所有单元格
- for row in range(len(df) + 1): # +1 包含表头
- for col in range(len(df.columns)):
- worksheet.write(row, col, df.iloc[row-1, col] if row > 0 else df.columns[col], chinese_font)
- # 方法4:使用openpyxl设置字体
- df.to_excel('中文数据_openpyxl_font.xlsx', index=False, engine='openpyxl')
- from openpyxl import load_workbook
- from openpyxl.styles import Font
- book = load_workbook('中文数据_openpyxl_font.xlsx')
- sheet = book.active
- # 设置支持中文的字体
- chinese_font = Font(name='Microsoft YaHei', size=11)
- # 应用字体到所有单元格
- for row in sheet.iter_rows():
- for cell in row:
- cell.font = chinese_font
- book.save('中文数据_openpyxl_font.xlsx')
复制代码
问题4:大数据量导出内存不足
原因:当处理大量数据时,可能会遇到内存不足的问题。
解决方案:
- import pandas as pd
- import numpy as np
- # 创建一个大型DataFrame(50万行)
- np.random.seed(42)
- large_df = pd.DataFrame({
- 'ID': range(1, 500001),
- '值1': np.random.rand(500000),
- '值2': np.random.randn(500000),
- '类别': np.random.choice(['A', 'B', 'C', 'D'], 500000)
- })
- # 方法1:分块处理
- def export_large_data_in_chunks(df, file_path, chunk_size=50000):
- """
- 分块导出大型DataFrame到Excel
-
- 参数:
- df: 要导出的DataFrame
- file_path: 输出文件路径
- chunk_size: 每块的行数
- """
- writer = pd.ExcelWriter(file_path, engine='openpyxl')
-
- # 写入第一块(包含表头)
- df.iloc[:chunk_size].to_excel(writer, sheet_name='大数据', index=False)
-
- # 追加剩余块
- for i in range(chunk_size, len(df), chunk_size):
- df.iloc[i:i+chunk_size].to_excel(
- writer,
- sheet_name='大数据',
- index=False,
- startrow=i+1, # +1 因为表头占了一行
- header=False # 不包含表头
- )
-
- writer.close()
- print(f"数据已分块导出到 {file_path}")
- # 使用分块方法导出
- export_large_data_in_chunks(large_df, '大型数据_分块导出.xlsx')
- # 方法2:使用CSV格式(对于非常大的数据集)
- def export_to_csv_with_compression(df, file_path, compression='gzip'):
- """
- 导出DataFrame到压缩的CSV文件
-
- 参数:
- df: 要导出的DataFrame
- file_path: 输出文件路径(不包括扩展名)
- compression: 压缩类型,可以是'gzip', 'bz2', 'zip', 'xz'
- """
- compressed_path = f"{file_path}.{compression}"
- df.to_csv(compressed_path, index=False, compression=compression)
- print(f"数据已压缩导出到 {compressed_path}")
- # 使用压缩CSV方法导出
- export_to_csv_with_compression(large_df, '大型数据_压缩')
- # 方法3:优化内存使用后导出
- def optimize_and_export(df, file_path):
- """
- 优化DataFrame内存使用后导出
-
- 参数:
- df: 要导出的DataFrame
- file_path: 输出文件路径
- """
- # 优化数据类型
- optimized_df = df.copy()
-
- for col in optimized_df.columns:
- col_type = optimized_df[col].dtype
-
- if col_type == 'object':
- # 对象类型转换为类别类型(如果唯一值较少)
- num_unique_values = len(optimized_df[col].unique())
- num_total_values = len(optimized_df[col])
- if num_unique_values / num_total_values < 0.5:
- optimized_df[col] = optimized_df[col].astype('category')
-
- elif col_type == 'float64':
- # 64位浮点数转换为32位浮点数
- optimized_df[col] = pd.to_numeric(optimized_df[col], downcast='float')
-
- elif col_type == 'int64':
- # 64位整数转换为更小的整数类型
- optimized_df[col] = pd.to_numeric(optimized_df[col], downcast='integer')
-
- # 比较内存使用
- original_memory = df.memory_usage(deep=True).sum() / 1024**2
- optimized_memory = optimized_df.memory_usage(deep=True).sum() / 1024**2
- print(f"原始DataFrame内存使用: {original_memory:.2f} MB")
- print(f"优化后DataFrame内存使用: {optimized_memory:.2f} MB")
- print(f"内存节省: {(1 - optimized_memory/original_memory)*100:.2f}%")
-
- # 导出优化后的DataFrame
- optimized_df.to_excel(file_path, index=False)
- print(f"优化后的数据已导出到 {file_path}")
- # 使用优化方法导出
- optimize_and_export(large_df, '大型数据_内存优化.xlsx')
- # 方法4:使用数据库作为中间存储
- def export_via_database(df, file_path, table_name='temp_data'):
- """
- 通过SQLite数据库导出大型DataFrame到Excel
-
- 参数:
- df: 要导出的DataFrame
- file_path: 输出文件路径
- table_name: 临时数据库表名
- """
- import sqlite3
- from sqlalchemy import create_engine
-
- # 创建SQLite数据库连接
- engine = create_engine('sqlite:///temp_db.sqlite')
-
- # 将DataFrame写入数据库
- df.to_sql(table_name, engine, index=False, if_exists='replace')
-
- # 分块从数据库读取并写入Excel
- writer = pd.ExcelWriter(file_path, engine='openpyxl')
-
- # 第一次读取(包含表头)
- chunk = pd.read_sql_table(table_name, engine, chunksize=50000)
- first_chunk = next(chunk)
- first_chunk.to_excel(writer, sheet_name='大数据', index=False)
-
- # 继续读取剩余数据
- for i, chunk in enumerate(chunk):
- chunk.to_excel(
- writer,
- sheet_name='大数据',
- index=False,
- startrow=len(first_chunk) + i*50000 + 1, # 计算正确的起始行
- header=False # 不包含表头
- )
-
- writer.close()
-
- # 关闭数据库连接
- engine.dispose()
-
- # 删除临时数据库文件
- import os
- if os.path.exists('temp_db.sqlite'):
- os.remove('temp_db.sqlite')
-
- print(f"数据已通过数据库导出到 {file_path}")
- # 使用数据库方法导出
- export_via_database(large_df, '大型数据_通过数据库.xlsx')
复制代码
总结
本指南全面介绍了如何使用pandas将数据输出到Excel文件,从基础操作到高级技巧,帮助您解决实际工作中的数据保存与分享问题。我们学习了:
1. 基础操作:如何安装必要的库,创建DataFrame并导出到Excel,以及如何控制导出格式。
2. 中级技巧:如何将多个DataFrame导出到同一个Excel文件的不同工作表中,如何设置单元格样式,以及如何处理日期时间格式。
3. 高级应用:如何添加条件格式,创建图表,添加数据验证,以及添加公式等高级Excel功能。
4. 性能优化:如何处理大数据量,优化内存使用,以及使用分块写入等技术。
5. 实际案例:通过销售报告自动化和财务数据导出与分析两个实际案例,展示了如何将所学知识应用到实际工作中。
6. 常见问题与解决方案:解决了导出的Excel文件打不开或损坏、日期时间格式不正确、中文显示乱码、大数据量导出内存不足等常见问题。
基础操作:如何安装必要的库,创建DataFrame并导出到Excel,以及如何控制导出格式。
中级技巧:如何将多个DataFrame导出到同一个Excel文件的不同工作表中,如何设置单元格样式,以及如何处理日期时间格式。
高级应用:如何添加条件格式,创建图表,添加数据验证,以及添加公式等高级Excel功能。
性能优化:如何处理大数据量,优化内存使用,以及使用分块写入等技术。
实际案例:通过销售报告自动化和财务数据导出与分析两个实际案例,展示了如何将所学知识应用到实际工作中。
常见问题与解决方案:解决了导出的Excel文件打不开或损坏、日期时间格式不正确、中文显示乱码、大数据量导出内存不足等常见问题。
通过掌握这些技巧,您可以更加高效地处理数据,并将结果以专业、美观的方式分享给他人。无论是简单的数据导出,还是复杂的报告生成,pandas与Excel的结合都能满足您的需求。
在实际应用中,请根据您的具体需求选择合适的方法和技巧,并注意性能优化,特别是在处理大数据量时。希望本指南能帮助您更好地利用pandas和Excel,提高工作效率。 |
|