1221 words
6 minutes
Python 数据处理技巧:pandas 实战笔记
处理了几百个 Excel 文件,从每天加班到半小时搞定。pandas 用好了真能救命。
先说说背景
公司财务每个月都要汇总各部门的报表,几十个 Excel,格式还不统一。原来都是手工复制粘贴,一个人要干三天。
我用 pandas 写了个自动化脚本,现在半小时跑完,还能自动检查错误。
基础读取
读取单个文件
import pandas as pd
# 最简单的方式df = pd.read_excel('data.xlsx')
# 指定工作表df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# 跳过前几行(有些报表有标题)df = pd.read_excel('data.xlsx', skiprows=3)
# 指定列df = pd.read_excel('data.xlsx', usecols=['A', 'C', 'D'])批量读取
import globimport pandas as pd
# 读取目录下所有 xlsxfiles = glob.glob('data/*.xlsx')dfs = []
for file in files: df = pd.read_excel(file) df['来源文件'] = file # 添加来源标记 dfs.append(df)
# 合并result = pd.concat(dfs, ignore_index=True)数据清洗
处理缺失值
# 查看缺失值print(df.isnull().sum())
# 删除有缺失值的行df_clean = df.dropna()
# 填充缺失值df['金额'].fillna(0, inplace=True)df['备注'].fillna('无', inplace=True)
# 用平均值填充df['金额'].fillna(df['金额'].mean(), inplace=True)去重
# 查看重复print(df.duplicated().sum())
# 删除完全重复的行df = df.drop_duplicates()
# 按特定列去重df = df.drop_duplicates(subset=['姓名', '日期'], keep='first')类型转换
# 字符串转数字df['金额'] = pd.to_numeric(df['金额'], errors='coerce')
# 字符串转日期df['日期'] = pd.to_datetime(df['日期'], format='%Y-%m-%d')
# 转字符串df['编号'] = df['编号'].astype(str)errors='coerce' 很重要,转换失败会变成 NaN,不会报错。
数据处理
筛选数据
# 单条件df_large = df[df['金额'] > 1000]
# 多条件df_filtered = df[(df['金额'] > 1000) & (df['日期'] >= '2024-01-01')]
# isindf_depts = df[df['部门'].isin(['销售部', '市场部'])]
# 字符串匹配df_names = df[df['姓名'].str.contains('张', na=False)]分组统计
# 按部门汇总summary = df.groupby('部门')['金额'].sum()
# 多维度统计summary = df.groupby(['部门', '月份']).agg({ '金额': ['sum', 'mean', 'count'], '数量': 'sum'})
# 重置索引summary = summary.reset_index()数据透视表
# 类似 Excel 的数据透视表pivot = pd.pivot_table( df, values='金额', index='部门', columns='月份', aggfunc='sum', fill_value=0)合并数据
# 类似 SQL 的 joindf_merged = pd.merge( df_left, df_right, on='员工ID', how='left' # left, right, inner, outer)
# 多列关联df_merged = pd.merge( df_left, df_right, on=['部门', '月份'], how='inner')实用技巧
添加计算列
# 简单计算df['总额'] = df['单价'] * df['数量']
# 条件计算df['折扣'] = df['金额'].apply(lambda x: 0.9 if x > 1000 else 1.0)
# 复杂逻辑def calc_bonus(row): if row['业绩'] >= 100000: return row['业绩'] * 0.1 elif row['业绩'] >= 50000: return row['业绩'] * 0.05 else: return 0
df['奖金'] = df.apply(calc_bonus, axis=1)数据校验
# 检查异常值errors = df[df['金额'] < 0]if not errors.empty: print(f"发现 {len(errors)} 条金额异常数据") errors.to_excel('errors.xlsx', index=False)
# 检查必填项required_cols = ['姓名', '部门', '金额']for col in required_cols: missing = df[df[col].isnull()] if not missing.empty: print(f"{col} 有 {len(missing)} 条缺失")
# 数据一致性检查df['校验'] = df['明细合计'] == df['总金额']wrong = df[~df['校验']]格式化输出
# 设置显示选项pd.set_option('display.max_columns', None)pd.set_option('display.max_rows', 100)pd.set_option('display.float_format', '{:.2f}'.format)
# 导出 Excel,带格式with pd.ExcelWriter('output.xlsx', engine='openpyxl') as writer: df.to_excel(writer, sheet_name='数据', index=False)
# 获取工作表 worksheet = writer.sheets['数据']
# 调整列宽 for column in worksheet.columns: max_length = 0 column_letter = column[0].column_letter for cell in column: try: if len(str(cell.value)) > max_length: max_length = len(str(cell.value)) except: pass adjusted_width = min(max_length + 2, 50) worksheet.column_dimensions[column_letter].width = adjusted_width完整案例
月度报表汇总
import pandas as pdimport globfrom datetime import datetime
def process_monthly_report(): """汇总各部门月度报表"""
# 1. 读取所有文件 files = glob.glob('reports/2024-*-*.xlsx') print(f"找到 {len(files)} 个文件")
all_data = [] error_files = []
for file in files: try: # 读取数据 df = pd.read_excel(file)
# 标准化列名(有些文件列名不统一) df.columns = df.columns.str.strip()
# 添加来源信息 df['来源文件'] = file df['导入时间'] = datetime.now()
all_data.append(df)
except Exception as e: error_files.append({'file': file, 'error': str(e)})
# 2. 合并数据 if not all_data: print("没有成功读取的文件") return
combined = pd.concat(all_data, ignore_index=True) print(f"合并完成,共 {len(combined)} 条记录")
# 3. 数据清洗 # 删除空行 combined = combined.dropna(subset=['金额'])
# 金额转数值 combined['金额'] = pd.to_numeric(combined['金额'], errors='coerce') combined = combined.dropna(subset=['金额'])
# 日期格式化 combined['日期'] = pd.to_datetime(combined['日期'], errors='coerce')
# 4. 数据校验 # 检查负数金额 negative = combined[combined['金额'] < 0] if not negative.empty: print(f"警告:发现 {len(negative)} 条负数金额") negative.to_excel('negative_amounts.xlsx', index=False)
# 5. 生成汇总 summary = combined.groupby('部门').agg({ '金额': ['sum', 'mean', 'count'] }).round(2)
# 6. 导出结果 with pd.ExcelWriter('monthly_summary.xlsx', engine='openpyxl') as writer: combined.to_excel(writer, sheet_name='明细数据', index=False) summary.to_excel(writer, sheet_name='部门汇总')
if error_files: pd.DataFrame(error_files).to_excel(writer, sheet_name='错误文件', index=False)
print("处理完成,结果已导出到 monthly_summary.xlsx") return combined, summary
# 运行if __name__ == '__main__': process_monthly_report()最后说两句
pandas 功能很强大,但也容易把简单问题复杂化。
我的建议:
- 先想清楚要做什么,再写代码
- 小步测试,不要一次性处理太多数据
- 保存中间结果,方便排查问题
- 做好异常处理,真实数据总是乱七八糟的
还有,Excel 能做的事情不要硬上 pandas。有时候手动处理更快。
参考链接
2026-03-09 更新。pandas 版本 2.2.x。