本文目录导读:

我来详细介绍Python中使用Pandas进行数据分组转换的几种常见方法。
基础分组与转换
准备示例数据
import pandas as pd
import numpy as np
# 创建示例数据
data = {
'部门': ['技术部', '技术部', '技术部', '市场部', '市场部', '市场部', '销售部', '销售部'],
'员工': ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十'],
'薪资': [15000, 18000, 20000, 12000, 14000, 16000, 13000, 17000],
'工龄': [3, 5, 7, 2, 4, 6, 3, 5]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
groupby + transform() 方法
计算组内统计量
# 计算每个部门薪资的平均值
df['部门平均薪资'] = df.groupby('部门')['薪资'].transform('mean')
# 计算每个部门薪资的最大值
df['部门最高薪资'] = df.groupby('部门')['薪资'].transform('max')
# 计算薪资占部门百分比
df['薪资占比'] = df.groupby('部门')['薪资'].transform(lambda x: x / x.sum() * 100)
print("转换后的数据:")
print(df)
填充组内缺失值
# 创建包含缺失值的数据
df_missing = df.copy()
df_missing.loc[0, '薪资'] = np.nan
df_missing.loc[3, '薪资'] = np.nan
# 用组内平均值填充缺失值
df_missing['薪资'] = df_missing.groupby('部门')['薪资'].transform(lambda x: x.fillna(x.mean()))
print("填充缺失值后的数据:")
print(df_missing)
自定义转换函数
def normalize_salary(group):
"""对组内薪资进行标准化"""
return (group - group.mean()) / group.std()
def rank_within_group(group):
"""计算组内排名"""
return group.rank(ascending=False)
# 应用自定义函数
df['标准化薪资'] = df.groupby('部门')['薪资'].transform(normalize_salary)
df['组内排名'] = df.groupby('部门')['薪资'].transform(rank_within_group)
print("自定义转换后的数据:")
print(df[['部门', '员工', '薪资', '标准化薪资', '组内排名']])
多列分组转换
# 多列分组求平均值
df['部门_工龄平均薪资'] = df.groupby(['部门', '工龄'])['薪资'].transform('mean')
# 多列分组计算累积值
df['累计薪资'] = df.groupby('部门')['薪资'].transform('cumsum')
# 多列分组后求差值
df['薪资提升'] = df.groupby('部门')['薪资'].transform('diff')
print("多列分组转换:")
print(df[['部门', '员工', '薪资', '工龄', '部门_工龄平均薪资', '累计薪资', '薪资提升']])
实际应用案例
案例1:销售数据分析
# 创建销售数据
sales_data = {
'地区': ['华北', '华北', '华北', '华东', '华东', '华东', '华南', '华南'],
'月份': ['1月', '2月', '3月', '1月', '2月', '3月', '1月', '2月'],
'销售额': [100000, 120000, 150000, 200000, 180000, 220000, 160000, 140000],
'目标额': [110000, 130000, 140000, 190000, 200000, 210000, 150000, 160000]
}
sales_df = pd.DataFrame(sales_data)
# 计算各地区销售额与目标的差异
sales_df['达标率'] = (sales_df['销售额'] / sales_df['目标额']) * 100
# 计算各地区月度增长率
sales_df['月度增长率'] = sales_df.groupby('地区')['销售额'].transform(lambda x: x.pct_change() * 100)
print("销售数据分析:")
print(sales_df)
案例2:学生成绩分析
# 创建学生成绩数据
student_data = {
'班级': ['A班', 'A班', 'A班', 'B班', 'B班', 'B班', 'C班', 'C班'],
'学生': ['小明', '小红', '小刚', '小华', '小李', '小美', '小强', '小丽'],
'语文': [85, 92, 78, 88, 95, 72, 80, 90],
'数学': [90, 85, 95, 78, 88, 92, 85, 95],
'英语': [88, 90, 82, 85, 92, 78, 88, 86]
}
student_df = pd.DataFrame(student_data)
# 计算总分
student_df['总分'] = student_df[['语文', '数学', '英语']].sum(axis=1)
# 计算班级内排名
student_df['班级排名'] = student_df.groupby('班级')['总分'].rank(ascending=False, method='min')
# 计算各科成绩与班级平均分的差异
for subject in ['语文', '数学', '英语']:
col_name = f'{subject}与班级均分差'
student_df[col_name] = student_df[subject] - student_df.groupby('班级')[subject].transform('mean')
print("学生成绩分析:")
print(student_df)
高级分组转换技巧
使用agg()函数同时处理多列
# 按部门分组,同时对多个列应用不同转换
transformed = df.groupby('部门').agg({
'薪资': ['mean', 'std', 'min', 'max'],
'工龄': 'mean'
})
print("多列聚合结果:")
print(transformed)
条件分组转换
# 根据条件创建新分组
df['薪资等级'] = pd.cut(df['薪资'], bins=[0, 15000, 18000, float('inf')],
labels=['低薪', '中薪', '高薪'])
# 按新分组进行转换
df['组内百分比'] = df.groupby('薪资等级')['薪资'].transform(
lambda x: x / x.sum() * 100
)
print("条件分组转换:")
print(df[['部门', '员工', '薪资', '薪资等级', '组内百分比']])
性能优化建议
import time
# 创建大数据集
large_data = pd.DataFrame({
'group': np.random.choice(['A', 'B', 'C', 'D'], 100000),
'value': np.random.randn(100000)
})
# 方法1: 使用transform(推荐)
start = time.time()
result1 = large_data.groupby('group')['value'].transform('mean')
print(f"transform方法耗时: {time.time() - start:.4f}秒")
# 方法2: 使用merge(较慢)
start = time.time()
group_means = large_data.groupby('group')['value'].mean().rename('mean')
result2 = large_data.merge(group_means, left_on='group', right_index=True)
print(f"merge方法耗时: {time.time() - start:.4f}秒")
# 验证结果是否相同
print(f"结果是否一致: {all(result1 == result2['mean'])}")
Pandas的分组转换提供了强大的数据处理能力:
- transform():最常用的分组转换方法,保持原DataFrame的形状
- 自定义函数:可以定义复杂的转换逻辑
- 实际应用:适合销售分析、成绩统计等场景
- 性能优化:transform通常比merge方法更快
掌握这些技巧可以大大提高数据处理的效率和灵活性。