groupby + agg:数据分析 80% 的活就这两招
📅 2026/7/5 15:00:55
👁️ 阅读次数
📝 编程学习
groupby + agg:数据分析 80% 的活就这两招
“各品类销售额多少?” “每个月的 GMV 趋势?” “各部门绩效排名?”
这些问题的答案,都是 groupby + 聚合。
Excel 里你要拉透视表、写 SUMIF,Pandas 里就两行。
groupby 的本质:分—算—合
importpandasaspdimportnumpyasnp df=pd.DataFrame({"部门":["技术","销售","技术","销售","技术","销售","市场","市场"],"姓名":["张三","李四","王五","赵六","孙七","周八","吴九","郑十"],"薪资":[15000,12000,18000,14000,20000,13000,11000,10000],"绩效":[85,92,78,88,95,80,90,85],})# 各部门平均薪资print(df.groupby("部门")["薪资"].mean())# 部门# 技术 17666.67# 市场 10500.00# 销售 13000.00三步骤:按"部门"分组 → 对"薪资"求均值 → 合并输出。
常用聚合函数
grouped=df.groupby("部门")print(grouped["薪资"].sum())# 求和print(grouped["薪资"].mean())# 均值print(grouped["薪资"].median())# 中位数print(grouped["薪资"].max())# 最大值print(grouped["薪资"].min())# 最小值print(grouped["薪资"].std())# 标准差print(grouped["薪资"].count())# 计数print(grouped["薪资"].nunique())# 唯一值个数agg:一次算多个指标
# 对薪资同时算均值和总和result=df.groupby("部门")["薪资"].agg(["mean","sum","count"])result.columns=["平均薪资","总薪资","人数"]print(result)# 对不同列算不同指标result=df.groupby("部门").agg({"薪资":["sum","mean"],"绩效":["mean","max","min"],})print(result)# 自定义聚合函数defrange_func(x):returnx.max()-x.min()result=df.groupby("部门").agg({"薪资":range_func})print(result)多级分组
# 模拟更大数据集np.random.seed(42)sales=pd.DataFrame({"year":np.random.choice([2024,2025,2026],100),"quarter":np.random.choice(["Q1","Q2","Q3","Q4"],100),"category":np.random.choice(["手机","电脑","耳机"],100),"amount":np.random.randint(1000,10000,100)})# 多列 groupbyresult=sales.groupby(["year","category"])["amount"].sum()print(result)# unstack 转成透视表格式pivot=result.unstack()print(pivot)# 透视表一步到位pivot=pd.pivot_table(sales,values="amount",index="year",columns="category",aggfunc="sum",fill_value=0)print(pivot)transform:保持原形状
# transform 返回和原始数据一样长的结果df=pd.DataFrame({"部门":["技术","销售","技术","销售","技术"],"薪资":[15000,12000,18000,14000,20000]})# 每人薪资 vs 部门平均df["部门均值"]=df.groupby("部门")["薪资"].transform("mean")df["与均值差"]=df["薪资"]-df["部门均值"]print(df)agg返回的是分组后的汇总值(行数变少),transform返回的是和原始数据一样长的值。
apply:最灵活
# 每个部门薪资最高的那个人deftop_earner(group):returngroup.nlargest(1,"薪资")result=df.groupby("部门",group_keys=False).apply(top_earner)print(result)# 给每个部门的薪资排序(组内排名)df["组内排名"]=df.groupby("部门")["薪资"].rank(ascending=False)print(df)实战:销售数据分析
np.random.seed(123)dates=pd.date_range("2026-01-01","2026-06-30",freq="D")sales=pd.DataFrame({"date":np.random.choice(dates,500),"product":np.random.choice(["手机","电脑","耳机","平板"],500),"city":np.random.choice(["北京","上海","广州","深圳"],500),"amount":np.random.randint(500,15000,500),})# 各产品总销售额print("=== 产品销售额排名 ===")print(sales.groupby("product")["amount"].sum().sort_values(ascending=False))# 每月销售额趋势sales["month"]=sales["date"].dt.to_period("M")monthly=sales.groupby("month")["amount"].sum()print(f"\n=== 月度销售额 ===\n{monthly}")# 每城市最畅销产品city_product=sales.groupby(["city","product"])["amount"].sum()print(f"\n=== 深圳最畅销 ===\n{city_product.loc['深圳'].sort_values(ascending=False)}")# 各产品的客单价和订单数stats=sales.groupby("product").agg(总销售额=("amount","sum"),订单数=("amount","count"),客单价=("amount","mean"),最高单=("amount","max")).round(1)print(f"\n=== 综合统计 ===\n{stats}")新手常见坑
坑1:groupby 结果索引
# groupby 结果可能有多级索引result=sales.groupby(["city","product"])["amount"].sum()# 用 reset_index 展平result=result.reset_index()坑2:NaN 被分组忽略
# 如果分组列有 NaN,那行不会被计入任何组# 先 fillna 再 groupbydf["city"]=df["city"].fillna("未知")坑3:agg 里写错函数名
# ❌ 函数名是字符串# df.groupby("x").agg("average") # 没有这个# ✅ 正确的 Pandas 聚合函数名df.groupby("x").agg("mean")动手试试
- 按"部门"分组,计算薪资的总和、均值、最大值、人数
- 用 pivot_table 做一个按"年份"和"季度"交叉的销售额表
- 用 transform 给每个员工加上"组内排名"
写在最后
groupby + agg 就是 Pandas 的透视表引擎。80% 的数据分析问题能用这两招解决。多练、多试,手感到了就熟了。
下一篇讲 DataFrame 的合并——merge、concat、join,多张表怎么优雅地拼在一起。
编程学习
技术分享
实战经验