1. 为什么需要Python处理Excel数据对比
在日常办公和数据处理中,Excel表格的两列数据对比是个高频需求场景。最常见的比如:
- 财务对账时核对两期数据差异
- 库存管理中比对系统记录与实际盘点
- 人力资源核对员工信息变更
- 销售数据月度环比分析
传统手工操作是使用Excel的"条件格式"或VLOOKUP函数,但当数据量超过万行时,Excel会明显卡顿,且操作步骤繁琐容易出错。而用Python处理这类问题有三大优势:
- 性能优势:实测在对比10万行数据时,Python的pandas库比Excel快20倍以上
- 灵活性:可以自定义各种对比规则(模糊匹配、容错阈值等)
- 自动化:代码可保存复用,特别适合定期执行的对比任务
我最近帮财务部优化了一个月度对账流程:原本需要2小时手工核对的数据,用Python脚本3分钟就能完成,准确率还更高。下面分享具体实现方法。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础数据读取
2.1 必备工具安装
推荐使用Anaconda发行版,它已经包含了我们需要的所有库:
bash复制conda install pandas openpyxl xlrd -y
关键库说明:
- pandas:数据处理核心库
- openpyxl:处理.xlsx格式文件
- xlrd:兼容旧版.xls格式
注意:如果遇到编码问题,可以额外安装chardet库自动检测文件编码
2.2 读取Excel数据
假设我们有两个要对比的Excel文件:
- 旧数据:old_data.xlsx
- 新数据:new_data.xlsx
读取代码示例:
python复制import pandas as pd
# 读取第一个Sheet的数据
df_old = pd.read_excel('old_data.xlsx', sheet_name=0)
df_new = pd.read_excel('new_data.xlsx', sheet_name=0)
# 查看数据结构
print(df_old.head(3))
print(df_new.info())
常见问题处理:
- 编码问题:如果遇到中文乱码,可指定encoding参数
python复制df = pd.read_excel('data.xlsx', encoding='gbk') - 大文件优化:对于超过50MB的文件,建议分块读取
python复制chunksize = 10000 for chunk in pd.read_excel('large.xlsx', chunksize=chunksize): process(chunk)
3. 核心对比方法实现
3.1 基础列对比(完全匹配)
假设要比对"订单号"列:
python复制# 找出新增的订单
new_orders = set(df_new['订单号']) - set(df_old['订单号'])
# 找出已取消的订单
canceled_orders = set(df_old['订单号']) - set(df_new['订单号'])
print(f"新增订单数:{len(new_orders)}")
print(f"取消订单数:{len(canceled_orders)}")
3.2 带条件的复杂对比
比如对比金额变化超过10%的记录:
python复制merged = pd.merge(df_old, df_new, on='订单号', suffixes=('_old', '_new'))
# 计算变化率
merged['变化率'] = (merged['金额_new'] - merged['金额_old']) / merged['金额_old']
# 筛选显著变化
significant_changes = merged[abs(merged['变化率']) > 0.1]
print(significant_changes[['订单号', '金额_old', '金额_new', '变化率']])
3.3 模糊匹配对比
当关键列可能存在拼写差异时:
python复制from fuzzywuzzy import fuzz
def fuzzy_match(str1, str2):
return fuzz.ratio(str1, str2) > 80 # 相似度阈值设为80%
# 示例:比对客户名称列
for _, new_row in df_new.iterrows():
for _, old_row in df_old.iterrows():
if fuzzy_match(new_row['客户名'], old_row['客户名']):
print(f"可能匹配:{new_row['客户名']} | {old_row['客户名']}")
4. 结果输出与可视化
4.1 差异结果导出
将对比结果保存到新Excel:
python复制with pd.ExcelWriter('对比结果.xlsx') as writer:
significant_changes.to_excel(writer, sheet_name='重大变化')
pd.DataFrame(new_orders, columns=['新增订单']).to_excel(
writer, sheet_name='新增数据')
4.2 自动生成对比报告
使用Matplotlib可视化:
python复制import matplotlib.pyplot as plt
# 绘制金额变化分布
plt.figure(figsize=(10,6))
merged['变化率'].hist(bins=50)
plt.title('金额变化分布')
plt.savefig('金额变化分析.png')
5. 实战经验与性能优化
5.1 大型文件处理技巧
当处理百万行级数据时:
- 使用dtype参数指定列类型减少内存占用
python复制dtypes = {'订单号': 'str', '金额': 'float32'} df = pd.read_excel('large.xlsx', dtype=dtypes) - 禁用不必要的列:
python复制usecols = ['订单号', '金额'] # 只读取需要的列
5.2 常见报错处理
- 日期格式问题:
python复制df['日期'] = pd.to_datetime(df['日期'], errors='coerce') - 浮点数精度问题:
python复制# 使用round函数或numpy的isclose方法 import numpy as np np.isclose(df1['值'], df2['值'], atol=0.01) # 允许0.01的误差
5.3 扩展应用场景
- 定时自动对比:
python复制import schedule import time def daily_compare(): # 对比逻辑... print(f"{time.ctime()} 对比完成") schedule.every().day.at("09:00").do(daily_compare) while True: schedule.run_pending() time.sleep(60) - 数据库对比:
python复制import sqlalchemy engine = sqlalchemy.create_engine('mysql://user:pass@host/db') df_db = pd.read_sql('SELECT * FROM orders', engine)
6. 完整案例演示
假设我们要对比两个月份的销售数据:
python复制# 数据准备
oct_sales = pd.read_excel('2023-10_sales.xlsx')
nov_sales = pd.read_excel('2023-11_sales.xlsx')
# 合并数据
merged = pd.merge(
oct_sales, nov_sales,
on='product_id',
how='outer',
suffixes=('_oct', '_nov')
)
# 标记变化状态
conditions = [
merged['sales_nov'].isna(),
merged['sales_oct'].isna(),
merged['sales_nov'] > merged['sales_oct'],
merged['sales_nov'] < merged['sales_oct'],
merged['sales_nov'] == merged['sales_oct']
]
choices = ['下架', '新品', '增长', '下降', '持平']
merged['status'] = np.select(conditions, choices)
# 保存结果
merged.to_excel('sales_comparison.xlsx', index=False)
# 生成统计报告
report = merged['status'].value_counts()
print(report)
这个脚本会输出类似这样的统计:
code复制增长 156
持平 89
下降 42
新品 23
下架 15
7. 进阶技巧分享
-
多列联合对比:
python复制# 使用多个列作为对比键 keys = ['order_id', 'customer_id'] merged = pd.merge(df1, df2, on=keys) -
自定义对比函数:
python复制def custom_compare(row): if row['value_old'] == 0: return 'N/A' change = (row['value_new'] - row['value_old'])/row['value_old'] return f"{change:.1%}" merged['change'] = merged.apply(custom_compare, axis=1) -
处理海量数据:
- 使用Dask替代pandas
- 考虑将数据存入SQLite临时数据库
- 使用多进程处理:
python复制from multiprocessing import Pool def compare_chunk(args): # 分块处理逻辑 pass with Pool(4) as p: # 4个进程 results = p.map(compare_chunk, chunks)
在实际项目中,我发现最常遇到的坑是数据类型不一致问题。比如一个文件中的订单号是字符串,另一个文件中却是数字,会导致匹配失败。最佳实践是在读取数据后就统一数据类型:
python复制df['order_id'] = df['order_id'].astype(str).str.strip()
另一个实用技巧是使用progress_apply代替apply显示处理进度:
python复制from tqdm import tqdm
tqdm.pandas()
df['new_col'] = df.progress_apply(process_row, axis=1)
