Pandas 分组操作(groupby)
groupby 是 Pandas 最强大的功能之一,允许按照一个或多个列对数据进行分组,然后对每个分组进行聚合、转换或过滤操作。
groupby 基本用法
单列分组
实例
import pandas as pd
# 创建示例数据
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售", "技术"],
"姓名": ["张三", "李四", "王五", "赵六", "钱七", "孙八"],
"薪资": [12000, 15000, 11000, 18000, 14000, 13000]
})
print("原始数据:")
print(df)
print()
# 按部门分组
grouped = df.groupby("部门")
print(f"分组对象: {type(grouped)}")
print(f"分组数量: {len(grouped)}")
print()
# 查看分组
print("各分组数据:")
for name, group in grouped:
print(f"\n部门: {name}")
print(group)
# 创建示例数据
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售", "技术"],
"姓名": ["张三", "李四", "王五", "赵六", "钱七", "孙八"],
"薪资": [12000, 15000, 11000, 18000, 14000, 13000]
})
print("原始数据:")
print(df)
print()
# 按部门分组
grouped = df.groupby("部门")
print(f"分组对象: {type(grouped)}")
print(f"分组数量: {len(grouped)}")
print()
# 查看分组
print("各分组数据:")
for name, group in grouped:
print(f"\n部门: {name}")
print(group)
分组并聚合
实例
import pandas as pd
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售"],
"薪资": [12000, 15000, 11000, 18000, 14000]
})
print("按部门分组求平均薪资:")
print(df.groupby("部门")["薪资"].mean())
print()
print("按部门分组求和:")
print(df.groupby("部门")["薪资"].sum())
print()
print("按部门分组计数:")
print(df.groupby("部门").size())
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售"],
"薪资": [12000, 15000, 11000, 18000, 14000]
})
print("按部门分组求平均薪资:")
print(df.groupby("部门")["薪资"].mean())
print()
print("按部门分组求和:")
print(df.groupby("部门")["薪资"].sum())
print()
print("按部门分组计数:")
print(df.groupby("部门").size())
多列分组
实例
import pandas as pd
df = pd.DataFrame({
"年份": ["2023", "2023", "2024", "2024"],
"部门": ["技术", "销售", "技术", "销售"],
"薪资": [12000, 15000, 13000, 16000]
})
print("按年份和部门分组:")
print(df.groupby(["年份", "部门"])["薪资"].sum())
print()
# 作为 DataFrame 输出
result = df.groupby(["年份", "部门"]).agg({
"薪资": "sum"
}).reset_index()
print("结果 DataFrame:")
print(result)
df = pd.DataFrame({
"年份": ["2023", "2023", "2024", "2024"],
"部门": ["技术", "销售", "技术", "销售"],
"薪资": [12000, 15000, 13000, 16000]
})
print("按年份和部门分组:")
print(df.groupby(["年份", "部门"])["薪资"].sum())
print()
# 作为 DataFrame 输出
result = df.groupby(["年份", "部门"]).agg({
"薪资": "sum"
}).reset_index()
print("结果 DataFrame:")
print(result)
常用聚合函数
单一聚合
| 函数 | 说明 |
|---|---|
sum() |
求和 |
mean() |
求平均 |
median() |
求中位数 |
std() |
标准差 |
min() / max() |
最小/最大值 |
count() |
计数 |
first() / last() |
首/末值 |
实例
import pandas as pd
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营"],
"薪资": [12000, 15000, 11000, 18000]
})
# 链式调用多个聚合
print("链式聚合:")
print(df.groupby("部门")["薪资"].agg(["sum", "mean", "max", "min"]))
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营"],
"薪资": [12000, 15000, 11000, 18000]
})
# 链式调用多个聚合
print("链式聚合:")
print(df.groupby("部门")["薪资"].agg(["sum", "mean", "max", "min"]))
自定义聚合
实例
import pandas as pd
import numpy as np
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营"],
"薪资": [12000, 15000, 11000, 18000]
})
# 自定义聚合函数
def range_func(x):
return x.max() - x.min()
print("使用自定义函数:")
print(df.groupby("部门")["薪资"].agg(range_func))
print()
# 命名聚合(推荐)
print("命名聚合:")
print(df.groupby("部门").agg(
最低薪资=("薪资", "min"),
最高薪资=("薪资", "max"),
平均薪资=("薪资", "mean")
))
import numpy as np
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营"],
"薪资": [12000, 15000, 11000, 18000]
})
# 自定义聚合函数
def range_func(x):
return x.max() - x.min()
print("使用自定义函数:")
print(df.groupby("部门")["薪资"].agg(range_func))
print()
# 命名聚合(推荐)
print("命名聚合:")
print(df.groupby("部门").agg(
最低薪资=("薪资", "min"),
最高薪资=("薪资", "max"),
平均薪资=("薪资", "mean")
))
transform
transform 可以在保持原数据形状的同时,对每个分组进行计算并返回与原数据相同形状的结果。
实例
import pandas as pd
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售"],
"薪资": [12000, 15000, 11000, 18000, 14000]
})
print("原始数据:")
print(df)
print()
# 计算每个部门的平均薪资,并广播到每行
df["部门平均薪资"] = df.groupby("部门")["薪资"].transform("mean")
print("添加部门平均薪资:")
print(df)
print()
# 计算每人的薪资占部门比例
df["薪资占比"] = df["薪资"] / df["部门平均薪资"]
print("薪资占比:")
print(df)
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售"],
"薪资": [12000, 15000, 11000, 18000, 14000]
})
print("原始数据:")
print(df)
print()
# 计算每个部门的平均薪资,并广播到每行
df["部门平均薪资"] = df.groupby("部门")["薪资"].transform("mean")
print("添加部门平均薪资:")
print(df)
print()
# 计算每人的薪资占部门比例
df["薪资占比"] = df["薪资"] / df["部门平均薪资"]
print("薪资占比:")
print(df)
filter 过滤
filter 可以根据分组条件过滤数据。
实例
import pandas as pd
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售", "技术"],
"薪资": [12000, 15000, 11000, 18000, 14000, 13000]
})
print("原始数据:")
print(df)
print()
# 过滤部门平均薪资大于13000的部门
print("部门平均薪资 > 13000:")
filtered = df.groupby("部门").filter(lambda x: x["薪资"].mean() > 13000)
print(filtered)
print()
# 过滤数量大于2的组
print("成员数 > 2:")
filtered2 = df.groupby("部门").filter(lambda x: len(x) > 2)
print(filtered2)
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营", "销售", "技术"],
"薪资": [12000, 15000, 11000, 18000, 14000, 13000]
})
print("原始数据:")
print(df)
print()
# 过滤部门平均薪资大于13000的部门
print("部门平均薪资 > 13000:")
filtered = df.groupby("部门").filter(lambda x: x["薪资"].mean() > 13000)
print(filtered)
print()
# 过滤数量大于2的组
print("成员数 > 2:")
filtered2 = df.groupby("部门").filter(lambda x: len(x) > 2)
print(filtered2)
apply 自定义函数
apply 允许对每个分组应用自定义函数。
实例
import pandas as pd
import numpy as np
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营"],
"薪资": [12000, 15000, 11000, 18000]
})
# 对每个分组应用自定义函数
result = df.groupby("部门").apply(
lambda x: pd.Series({
"总和": x["薪资"].sum(),
"均值": x["薪资"].mean()
})
)
print("自定义聚合结果:")
print(result)
import numpy as np
df = pd.DataFrame({
"部门": ["技术", "销售", "技术", "运营"],
"薪资": [12000, 15000, 11000, 18000]
})
# 对每个分组应用自定义函数
result = df.groupby("部门").apply(
lambda x: pd.Series({
"总和": x["薪资"].sum(),
"均值": x["薪资"].mean()
})
)
print("自定义聚合结果:")
print(result)
实战:销售数据分析
实例
import pandas as pd
# 模拟销售数据
sales = pd.DataFrame({
"日期": pd.date_range("2024-01-01", periods=30, freq="D"),
"产品": ["手机", "电脑", "平板"] * 10,
"渠道": ["线上"] * 15 + ["线下"] * 15,
"销售额": [1000, 2000, 1500] * 10
})
print("=== 销售数据分析 ===\n")
# 1. 按产品统计
print("1. 按产品统计:")
product_summary = sales.groupby("产品")["销售额"].agg(["sum", "mean", "count"])
print(product_summary)
print()
# 2. 按渠道统计
print("2. 按渠道统计:")
channel_summary = sales.groupby("渠道")["销售额"].sum()
print(channel_summary)
print()
# 3. 按产品和渠道交叉统计
print("3. 产品×渠道交叉统计:")
cross_summary = sales.groupby(["产品", "渠道"])["销售额"].sum().unstack()
print(cross_summary)
print()
# 4. 计算各产品销售额占比
print("4. 销售额占比:")
total = sales["销售额"].sum()
product_pct = sales.groupby("产品")["销售额"].sum() / total * 100
print(product_pct.round(2))
# 模拟销售数据
sales = pd.DataFrame({
"日期": pd.date_range("2024-01-01", periods=30, freq="D"),
"产品": ["手机", "电脑", "平板"] * 10,
"渠道": ["线上"] * 15 + ["线下"] * 15,
"销售额": [1000, 2000, 1500] * 10
})
print("=== 销售数据分析 ===\n")
# 1. 按产品统计
print("1. 按产品统计:")
product_summary = sales.groupby("产品")["销售额"].agg(["sum", "mean", "count"])
print(product_summary)
print()
# 2. 按渠道统计
print("2. 按渠道统计:")
channel_summary = sales.groupby("渠道")["销售额"].sum()
print(channel_summary)
print()
# 3. 按产品和渠道交叉统计
print("3. 产品×渠道交叉统计:")
cross_summary = sales.groupby(["产品", "渠道"])["销售额"].sum().unstack()
print(cross_summary)
print()
# 4. 计算各产品销售额占比
print("4. 销售额占比:")
total = sales["销售额"].sum()
product_pct = sales.groupby("产品")["销售额"].sum() / total * 100
print(product_pct.round(2))
groupby 是数据分析的核心操作,熟练掌握可以高效完成各种统计分析任务。
