Pandas如何实现DataFrame按双列在双轴上的groupby分组
pandas双轴分组聚合高效实现方案
需求说明
需要对pandas DataFrame基于两个不同列、在两个轴方向上完成groupby分组聚合,替代低效的手动循环实现,解决直接调用.resample方法丢失非时间维度分组信息的问题。
测试数据构造
import numpy as np import pandas as pd x = pd.date_range("2022-01-01", "2022-06-01", freq="D") y = np.arange(0, x.shape[0]) z = np.random.choice(["Jack", "Jul", "John"], size=x.shape[0]) df = pd.DataFrame({"Date": x, "numbers": y, "names": z})
原有循环实现及存在的问题
原有实现通过手动遍历周次、逐次分组拼接得到结果,存在效率低、代码冗余的问题,且无法直接通过.resample实现——单独调用.resample会丢失names维度的分组信息:
min_ = x.min() max_ = x.max() dt_range = pd.date_range(min_, max_, freq="W") list_ = [] for date in dt_range: temp_df = df[df["Date"].dt.week == date.week] temp_df = temp_df.groupby("names").sum() list_.append(temp_df) pd.concat(list_, axis=1)
该实现的输出结构如下(行索引为姓名,列索引为各周的numbers求和结果):
numbers numbers numbers numbers numbers numbers ... numbers numbers numbers numbers numbers numbers names ... Jack 0.0 7 36.0 39 53 99 ... 113 237 247 260 416 NaN John 1.0 16 48.0 54 78 68 ... 436 233 250 262 139 726.0 Jul NaN 12 NaN 40 51 64 ... 221 349 371 395 411 289.0
规范高效实现方式
使用pd.Grouper同时指定时间采样规则和普通分组键,一次完成双维度聚合,再通过unstack调整轴结构即可得到和原有逻辑完全一致的输出,全程为pandas矢量化操作,无手动循环,性能更高、代码更简洁:
# 同时按周采样时间、姓名两个维度分组求和,再将周维度转为列索引 result = df.groupby( [pd.Grouper(key="Date", freq="W"), "names"] )["numbers"].sum().unstack(level=0)
实现说明
pd.Grouper(key="Date", freq="W")指定Date列按周频率分组,在groupby阶段完成时间重采样,不会丢失names维度的分组信息- 双维度分组后得到双层索引的Series,第一层为周次时间、第二层为姓名,调用
unstack(level=0)将周次维度转到列方向,输出结构和原有循环逻辑完全一致 - 该实现为pandas原生矢量化操作,避免了手动循环、逐次切片拼接的开销,数据量越大性能优势越明显
- 若需要更清晰的列名,可在聚合完成后重命名列,例如:
result.columns = [f"Week_{c.isocalendar().week}" for c in result.columns]
内容的提问来源于stack exchange,提问作者Akmal Soliev
相关产品推荐
相关产品推荐

