在实际工作中,经常要处理多个Excel文件。用Python批量读取特别方便:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import pandas as pd import os
def batch_read_excel(folder_path): # 存储所有数据框 all_data = []
# 遍历文件夹中的所有Excel文件 for file in os.listdir(folder_path): if file.endswith(('.xlsx', '.xls')): file_path = os.path.join(folder_path, file) # 读取文件并添加来源列 df = pd.read_excel(file_path) df['文件来源'] = file all_data.append(df)
# 合并所有数据框 return pd.concat(all_data, ignore_index=True)
# 使用示例 data = batch_read_excel('D:/工作/销售数据/') |
有时候Excel文件很大,但我们只需要某些工作表和列,这样可以节省内存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def smart_read_excel(filename): # 只读取需要的工作表和列 sheets_to_read = ['销售数据', '客户信息'] useful_columns = ['日期', '产品', '销量', '单价']
all_data = {} for sheet in sheets_to_read: df = pd.read_excel( filename, sheet_name=sheet, usecols=useful_columns, dtype={ '销量': 'int32', # 指定数据类型优化内存 '单价': 'float32' } ) all_data[sheet] = df
return all_data |
数据处理完还要调整格式?这个函数帮你一键搞定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
from openpyxl.styles import PatternFill, Font, Alignment from openpyxl.utils import get_column_letter
def style_excel(filename): # 读取Excel wb = load_workbook(filename) ws = wb.active
# 设置列宽 for col in range(1, ws.max_column + 1): ws.column_dimensions[get_column_letter(col)].width = 15
# 设置表头样式 header_fill = PatternFill(start_color='FF92D050', end_color='FF92D050', fill_type='solid') header_font = Font(bold=True, color='FFFFFF', size=12)
for cell in ws[1]: cell.fill = header_fill cell.font = header_font cell.alignment = Alignment(horizontal='center')
# 设置数据区域格式 for row in ws.iter_rows(min_row=2): for cell in row: cell.alignment = Alignment(horizontal='center') # 数字列右对齐 if isinstance(cell.value, (int, float)): cell.alignment = Alignment(horizontal='right')
wb.save(filename) |
数据清洗是最耗时的工作,这个函数能自动处理常见问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
def clean_excel_data(df): # 删除全空的行 df = df.dropna(how='all')
# 填充空值 numeric_columns = df.select_dtypes(include=['int64', 'float64']).columns df[numeric_columns] = df[numeric_columns].fillna(0)
# 处理日期列 date_columns = ['订单日期', '发货日期'] for col in date_columns: if col in df.columns: df[col] = pd.to_datetime(df[col], errors='coerce')
# 删除重复记录 df = df.drop_duplicates()
# 处理异常值 for col in numeric_columns: # 将超过3个标准差的值替换为均值 mean = df[col].mean() std = df[col].std() df.loc[abs(df[col] - mean) > 3*std, col] = mean
return df |
手动制作数据透 视表太麻烦?Python一行搞定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
def create_pivot_tables(df, filename): # 创建Excel写入器 writer = pd.ExcelWriter(filename, engine='openpyxl')
# 按产品类别统计销售额 pivot1 = pd.pivot_table( df, values='销售额', index='产品类别', columns='月份', aggfunc='sum', margins=True, margins_name='总计' )
# 按销售区域分析销量 pivot2 = pd.pivot_table( df, values=['销量', '销售额'], index='销售区域', columns='产品类别', aggfunc={ '销量': 'sum', '销售额': ['sum', 'mean'] } )
# 写入不同工作表 pivot1.to_excel(writer, sheet_name='产品类别分析') pivot2.to_excel(writer, sheet_name='区域分析')
writer.save() |
数据可视化也能自动化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import matplotlib.pyplot as plt import seaborn as sns
def create_sales_charts(df, save_path): # 设置中文字体 plt.rcParams['font.sans-serif'] = ['SimHei']
# 1. 销售趋势图 plt.figure(figsize=(12, 6)) df.groupby('日期')['销售额'].sum().plot(kind='line') plt.title('销售趋势分析') plt.tight_layout() plt.savefig(f'{save_path}/销售趋势.png')
# 2. 品类占比饼图 plt.figure(figsize=(8, 8)) df.groupby('产品类别')['销售额'].sum().plot(kind='pie', autopct='%1.1f%%') plt.title('产品类别销售占比') plt.savefig(f'{save_path}/品类占比.png')
# 3. 区域销售热力图 plt.figure(figsize=(10, 8)) pivot = df.pivot_table( values='销售额', index='销售区域', columns='产品类别', aggfunc='sum' ) sns.heatmap(pivot, annot=True, fmt='.0f', cmap='YlOrRd') plt.title('区域产品销售热力图') plt.tight_layout() plt.savefig(f'{save_path}/销售热力图.png') |
处理完数据后自动发送邮件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication
def send_excel_report(file_path, recipients): # 邮件设置 msg = MIMEMultipart() msg['Subject'] = '销售数据分析报告' msg['From'] = '你的邮箱' msg['To'] = ', '.join(recipients)
# 邮件正文 content = ''' 各位好:
附件是最新的销售数据分析报告,请查收。
以下是重要发现: 1. 本月销售额较上月增长15% 2. 华东区域表现最好,占比40% 3. 新品类增长迅速,环比增长50%
如有问题请及时反馈。 ''' msg.attach(MIMEText(content, 'plain', 'utf-8'))
# 添加附件 with open(file_path, 'rb') as f: attachment = MIMEApplication(f.read()) attachment.add_header( 'Content-Disposition', 'attachment', filename=os.path.basename(file_path) ) msg.attach(attachment)
# 发送邮件 with smtplib.SMTP('smtp.公司邮箱.com', 25) as server: server.login('你的邮箱', '密码') server.send_message(msg) |
把上面的功能集成起来,设置定时运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import schedule import time
def daily_report_job(): # 1. 读取数据 data = batch_read_excel('数据文件夹路径')
# 2. 清洗数据 clean_data = clean_excel_data(data)
# 3. 生成报表 create_pivot_tables(clean_data, '分析报告.xlsx')
# 4. 生成图表 create_sales_charts(clean_data, '图表文件夹路径')
# 5. 发送邮件 send_excel_report( '分析报告.xlsx', ['leader@company.com', 'team@company.com'] )
# 设置每天早上9点运行 schedule.every().day.at('09:00').do(daily_report_job)
while True: schedule.run_pending() time.sleep(60) |
经常要对比两个Excel文件的差异:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
def compare_excel_files(file1, file2): # 读取两个文件 df1 = pd.read_excel(file1) df2 = pd.read_excel(file2)
# 设置索引 key_columns = ['订单号', '产品编码'] df1.set_index(key_columns, inplace=True) df2.set_index(key_columns, inplace=True)
# 找出不同的行 diff_rows = df1.compare(df2)
# 找出file2中新增的行 new_rows = df2.loc[~df2.index.isin(df1.index)]
# 找出file2中删除的行 deleted_rows = df1.loc[~df1.index.isin(df2.index)]
# 保存结果 with pd.ExcelWriter('文件对比结果.xlsx') as writer: diff_rows.to_excel(writer, sheet_name='数据变化') new_rows.to_excel(writer, sheet_name='新增数据') deleted_rows.to_excel(writer, sheet_name='删除数据') |
处理大文件时的一些优化技巧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
def process_large_excel(filename): # 1. 分块读取 chunks = pd.read_excel( filename, chunksize=10000 # 每次读取1万行 )
results = [] for chunk in chunks: # 处理每个数据块 processed = process_chunk(chunk) results.append(processed)
# 合并结果 final_result = pd.concat(results)
# 2. 使用更小的数据类型 optimized_types = { 'int64': 'int32', 'float64': 'float32', 'object': 'category' # 对于重复值多的字符串列 }
for col in final_result.columns: if final_result[col].dtype.name in optimized_types: final_result[col] = final_result[col].astype(optimized_types[final_result[col].dtype.name])
return final_result |
这些代码都经过实际项目验证,复制就能用。还有一些使用小技巧: