Pandas-之 数据聚合与分组
数据聚合与分组
目录
- 基础分组操作
 - 分组聚合
 - 多级分组
 - 分组转换
 - 分组过滤
 - 分组应用自定义函数
 - 实际应用示例
 
基础分组操作
groupby 基础
import pandas as pddata = {'部门': ['销售', '销售', '技术', '技术', '销售', '技术'],'姓名': ['张三', '李四', '王五', '赵六', '孙七', '周八'],'工资': [8000, 10000, 12000, 11000, 9000, 13000],'年龄': [25, 30, 35, 28, 32, 40]
}
df = pd.DataFrame(data)# 创建分组对象
groups = df.groupby('部门')
print(type(groups))  # <class 'pandas.core.groupby.generic.DataFrameGroupBy'># 查看分组
for name, group in groups:print(f"\n{name}部门:")print(group)# 获取特定分组
sales_group = groups.get_group('销售')
print("\n销售部门:")
print(sales_group)# 查看分组大小
print("\n分组大小:")
print(groups.size())
# 输出:
# 部门
# 技术    3
# 销售    3
# dtype: int64# 查看分组数量
print(f"分组数量: {groups.ngroups}")
 
分组聚合
基本聚合函数
import pandas as pddata = {'部门': ['销售', '销售', '技术', '技术', '销售', '技术'],'工资': [8000, 10000, 12000, 11000, 9000, 13000],'年龄': [25, 30, 35, 28, 32, 40]
}
df = pd.DataFrame(data)
groups = df.groupby('部门')# 单列聚合
print(groups['工资'].sum())
# 输出:
# 部门
# 技术    36000
# 销售    27000
# Name: 工资, dtype: int64# 多列聚合
result = groups[['工资', '年龄']].mean()
print(result)# 多个聚合函数
result = groups['工资'].agg(['sum', 'mean', 'max', 'min', 'count'])
print(result)# 不同列使用不同的聚合函数
result = groups.agg({'工资': ['sum', 'mean'],'年龄': 'mean'
})
print(result)# 使用自定义名称
result = groups['工资'].agg([('总工资', 'sum'),('平均工资', 'mean'),('最高工资', 'max'),('最低工资', 'min')
])
print(result)
 
常用聚合函数
import pandas as pd
import numpy as npdata = {'部门': ['销售', '销售', '技术', '技术', '销售'],'工资': [8000, 10000, 12000, 11000, 9000],'年龄': [25, 30, 35, 28, 32]
}
df = pd.DataFrame(data)
groups = df.groupby('部门')# 统计函数
print("总和:", groups['工资'].sum())
print("平均值:", groups['工资'].mean())
print("中位数:", groups['工资'].median())
print("最大值:", groups['工资'].max())
print("最小值:", groups['工资'].min())
print("标准差:", groups['工资'].std())
print("方差:", groups['工资'].var())
print("计数:", groups['工资'].count())
print("非空计数:", groups['工资'].count())
print("唯一值数量:", groups['工资'].nunique())# 分位数
print("25%分位数:", groups['工资'].quantile(0.25))
print("75%分位数:", groups['工资'].quantile(0.75))# 第一个和最后一个值
print("第一个值:", groups['工资'].first())
print("最后一个值:", groups['工资'].last())
 
多级分组
import pandas as pddata = {'部门': ['销售', '销售', '技术', '技术', '销售', '技术'],'职位': ['经理', '员工', '高级', '员工', '员工', '经理'],'姓名': ['张三', '李四', '王五', '赵六', '孙七', '周八'],'工资': [15000, 8000, 15000, 11000, 9000, 20000],'年龄': [35, 25, 40, 28, 32, 45]
}
df = pd.DataFrame(data)# 按多列分组
groups = df.groupby(['部门', '职位'])# 查看分组
for name, group in groups:print(f"\n{name}:")print(group)# 聚合
result = groups['工资'].mean()
print("\n多级分组聚合:")
print(result)# 重置索引,转换为 DataFrame
result_df = groups['工资'].mean().reset_index()
print("\n转换为 DataFrame:")
print(result_df)# 多级分组的多列聚合
result = groups.agg({'工资': ['mean', 'sum'],'年龄': 'mean'
})
print("\n多列聚合:")
print(result)
 
分组转换
transform 方法返回与原始数据相同长度的结果,常用于创建新列。
import pandas as pddata = {'部门': ['销售', '销售', '技术', '技术', '销售', '技术'],'工资': [8000, 10000, 12000, 11000, 9000, 13000]
}
df = pd.DataFrame(data)# 计算每个部门相对于部门均值的偏差
df['部门平均工资'] = df.groupby('部门')['工资'].transform('mean')
df['与部门均值差'] = df['工资'] - df['部门平均工资']
print(df)# 标准化(Z-score)
def z_score(x):return (x - x.mean()) / x.std()df['标准化工资'] = df.groupby('部门')['工资'].transform(z_score)
print("\n标准化后:")
print(df)# 排名
df['部门内排名'] = df.groupby('部门')['工资'].transform('rank', ascending=False)
print("\n添加排名:")
print(df)# 累计值
df['部门累计工资'] = df.groupby('部门')['工资'].transform('cumsum')
print("\n累计工资:")
print(df)
 
分组过滤
filter 方法根据条件过滤整个分组。
import pandas as pddata = {'部门': ['销售', '销售', '技术', '技术', '销售', '技术'],'工资': [8000, 10000, 12000, 11000, 9000, 13000],'年龄': [25, 30, 35, 28, 32, 40]
}
df = pd.DataFrame(data)# 过滤:只保留组内人数 >= 3 的部门
filtered = df.groupby('部门').filter(lambda x: len(x) >= 3)
print(filtered)# 过滤:只保留平均工资 > 10000 的部门
filtered = df.groupby('部门').filter(lambda x: x['工资'].mean() > 10000)
print("\n平均工资 > 10000 的部门:")
print(filtered)# 过滤:只保留总工资 > 25000 的部门
filtered = df.groupby('部门').filter(lambda x: x['工资'].sum() > 25000)
print("\n总工资 > 25000 的部门:")
print(filtered)
 
分组应用自定义函数
apply 方法
import pandas as pddata = {'部门': ['销售', '销售', '技术', '技术', '销售', '技术'],'工资': [8000, 10000, 12000, 11000, 9000, 13000],'年龄': [25, 30, 35, 28, 32, 40]
}
df = pd.DataFrame(data)# 自定义函数:返回每个组的统计信息
def group_stats(group):return pd.Series({'人数': len(group),'平均工资': group['工资'].mean(),'工资范围': group['工资'].max() - group['工资'].min(),'年龄范围': group['年龄'].max() - group['年龄'].min()})result = df.groupby('部门').apply(group_stats)
print(result)# 自定义函数:返回 DataFrame
def add_rank(group):group = group.copy()group['部门内排名'] = group['工资'].rank(ascending=False)return groupresult = df.groupby('部门').apply(add_rank)
print("\n添加排名:")
print(result)# 使用 lambda 函数
result = df.groupby('部门').apply(lambda x: x.nlargest(2, '工资'))
print("\n每组工资最高的2人:")
print(result)
 
实际应用示例
示例 1:销售数据分析
import pandas as pd
import numpy as npnp.random.seed(42)
dates = pd.date_range('2024-01-01', periods=100, freq='D')
sales = pd.DataFrame({'日期': dates,'销售员': np.random.choice(['张三', '李四', '王五'], 100),'产品': np.random.choice(['A', 'B', 'C'], 100),'销售额': np.random.randint(1000, 5000, 100),'数量': np.random.randint(10, 50, 100)
})# 按销售员统计
salesperson_stats = sales.groupby('销售员').agg({'销售额': ['sum', 'mean', 'count'],'数量': 'sum'
})
print("销售员统计:")
print(salesperson_stats)# 按产品统计
product_stats = sales.groupby('产品').agg({'销售额': 'sum','数量': 'sum','销售员': 'nunique'
})
product_stats['平均单价'] = product_stats['销售额'] / product_stats['数量']
print("\n产品统计:")
print(product_stats)# 按销售员和产品统计
salesperson_product = sales.groupby(['销售员', '产品']).agg({'销售额': 'sum','数量': 'sum'
}).reset_index()
print("\n销售员-产品统计:")
print(salesperson_product)# 计算每个销售员的销售额占比
sales['销售员总销售额'] = sales.groupby('销售员')['销售额'].transform('sum')
sales['销售额占比'] = sales['销售额'] / sales['销售员总销售额'] * 100
print("\n添加销售额占比:")
print(sales[['销售员', '销售额', '销售员总销售额', '销售额占比']].head(10))
 
示例 2:员工绩效分析
import pandas as pdemployees = pd.DataFrame({'部门': ['销售', '销售', '技术', '技术', '销售', '技术', '销售', '技术'],'员工ID': ['E001', 'E002', 'E003', 'E004', 'E005', 'E006', 'E007', 'E008'],'基础工资': [8000, 10000, 12000, 11000, 9000, 13000, 8500, 11500],'绩效': [85, 92, 88, 90, 87, 95, 83, 91],'工龄': [2, 5, 8, 4, 3, 10, 2, 6]
})# 部门统计
dept_stats = employees.groupby('部门').agg({'基础工资': ['mean', 'sum', 'count'],'绩效': 'mean','工龄': 'mean'
})
print("部门统计:")
print(dept_stats)# 计算部门内排名
employees['部门内工资排名'] = employees.groupby('部门')['基础工资'].rank(ascending=False)
employees['部门内绩效排名'] = employees.groupby('部门')['绩效'].rank(ascending=False)# 计算综合排名
employees['综合得分'] = employees['绩效'] * 0.6 + employees['工龄'] * 10 * 0.4
employees['综合排名'] = employees.groupby('部门')['综合得分'].rank(ascending=False)print("\n员工排名:")
print(employees[['部门', '员工ID', '基础工资', '绩效', '部门内工资排名', '综合排名']])# 找出各部门绩效最高和最低的员工
def get_top_bottom(group):return pd.DataFrame({'最高绩效': [group.loc[group['绩效'].idxmax(), '员工ID']],'最低绩效': [group.loc[group['绩效'].idxmin(), '员工ID']]})top_bottom = employees.groupby('部门').apply(get_top_bottom).reset_index(level=1, drop=True)
print("\n各部门绩效最高和最低员工:")
print(top_bottom)
 
示例 3:时间序列分组
import pandas as pd
import numpy as npnp.random.seed(42)
dates = pd.date_range('2024-01-01', periods=365, freq='D')
data = pd.DataFrame({'日期': dates,'销售额': np.random.randint(1000, 10000, 365),'类别': np.random.choice(['A', 'B', 'C'], 365)
})# 按月份分组
data['年月'] = data['日期'].dt.to_period('M')
monthly_stats = data.groupby('年月').agg({'销售额': ['sum', 'mean', 'count']
})
print("月度统计:")
print(monthly_stats.head())# 按周分组
data['周'] = data['日期'].dt.to_period('W')
weekly_stats = data.groupby('周')['销售额'].sum()
print("\n周统计:")
print(weekly_stats.head())# 按类别和月份分组
category_monthly = data.groupby(['类别', '年月'])['销售额'].sum().reset_index()
print("\n类别-月度统计:")
print(category_monthly.head(10))# 计算环比增长
monthly_sales = data.groupby('年月')['销售额'].sum()
monthly_sales['环比增长'] = monthly_sales.pct_change() * 100
print("\n月度销售额环比增长:")
print(monthly_sales.head(10))
 
总结
数据聚合与分组是数据分析的核心功能:
- groupby:创建分组对象
 - 聚合函数:sum, mean, max, min, count 等
 - transform:分组转换,保持原始长度
 - filter:分组过滤
 - apply:应用自定义函数
 - 多级分组:按多列分组
 
