groupby().agg()有两种常见的写法,它们在使用场景和灵活性上有所不同:
1. 两种写法对比
写法一:字典形式(推荐用于多个聚合)
# 对不同的列应用不同的聚合函数
df.groupby('group_col').agg({
'col1': 'sum',
'col2': ['mean', 'std'],
'col3': lambda x: x.max() - x.min()
})
写法二:命名参数形式(推荐用于单个聚合)
# 对多个列应用相同的聚合函数
df.groupby('group_col').agg(
total_sales=('sales', 'sum'),
avg_price=('price', 'mean'),
custom_metric=('value', lambda x: x.quantile(0.9))
)
2. 核心区别
字典形式的特点:
# 多级索引的列名(自动命名)
result = df.groupby('group').agg({
'A': ['sum', 'mean'],
'B': 'max'
})
# 输出列名会是:
# A B
# sum mean max
命名参数形式的特点:
# 单级索引的自定义列名
result = df.groupby('group').agg(
total_A=('A', 'sum'),
avg_A=('A', 'mean'),
max_B=('B', 'max')
)
# 输出列名是:
# total_A avg_A max_B
3. 实际使用中的选择建议
选择字典形式的情况:
- 需要多级列名(MultiIndex columns)
- 批量对多个列应用相同的函数
- 使用匿名函数或自定义函数
# 批量聚合示例
agg_dict = {
'sales': ['sum', 'mean', 'count'],
'profit': ['sum', 'mean'],
'quantity': 'sum'
}
df.groupby('date').agg(agg_dict)
选择命名参数形式的情况:
- 需要清晰的列名(业务可读性)
- 对少数几个列进行聚合
- 结果需要进一步处理(避免MultiIndex)
# 创建业务友好的列名
summary = df.groupby('department').agg(
total_revenue=('revenue', 'sum'),
avg_salary=('salary', 'mean'),
employee_count=('employee_id', 'nunique'),
top_performer=('performance_score', lambda x: x.nlargest(1).iloc[0])
)
4. 混合使用技巧
# 可以混合使用(Pandas 1.0+)
result = df.groupby('group').agg(
total=('value', 'sum'),
**{'value': ['mean', 'std']} # 保留原列名的多级索引
)
5. 性能考虑
两种写法在性能上差异不大,主要区别在于:
- 字典形式:更简洁,适合快速探索
- 命名参数形式:更明确,适合生产代码
# 性能对比(通常差异很小)
import time
start = time.time()
result1 = df.groupby('group').agg({'col': ['sum', 'mean']})
print(f"字典形式: {time.time()-start:.4f}s")
start = time.time()
result2 = df.groupby('group').agg(
sum_col=('col', 'sum'),
mean_col=('col', 'mean')
)
print(f"命名参数: {time.time()-start:.4f}s")
6. 最佳实践总结
| 场景 |
推荐写法 |
理由 |
|---|
| 探索性分析 |
字典形式 |
快速、简洁 |
| 生产代码 |
命名参数形式 |
列名清晰,易于维护 |
| 多列相同聚合 |
字典形式 |
{'col1':'mean', 'col2':'mean'} |
| 单个列多个聚合 |
字典形式 |
{'col': ['sum', 'mean', 'std']} |
| 需要自定义列名 |
命名参数形式 |
直接指定有意义的列名 |
最实用的建议:
- 临时分析用字典形式
- 要保留的代码用命名参数形式(更好的可读性)
- 根据具体需求灵活选择,两者可以互相转换