文章目录
前言
在数据分析的世界里,简单的一维分组统计往往无法满足我们对数据洞察的深度需求。今天,让我们一起探索Pandas中多级分组和高级聚合的强大功能,让你的数据分析能力更上一层楼!
一、多级分组:层层深入的数据洞察
多级分组就像是数据版的俄罗斯套娃,每一层都揭示着不同的信息维度。
基础多级分组操作
python
python
import pandas as pd
import numpy as np
# 创建示例销售数据
np.random.seed(42)
data = {
'年份': np.random.choice([2021, 2022, 2023], 100),
'季度': np.random.choice(['Q1', 'Q2', 'Q3', 'Q4'], 100),
'地区': np.random.choice(['华东', '华南', '华北', '西部'], 100),
'产品类别': np.random.choice(['电子产品', '服装', '食品', '家居'], 100),
'销售额': np.random.uniform(1000, 50000, 100).round(2),
'销量': np.random.randint(10, 500, 100)
}
df = pd.DataFrame(data)
print("原始数据样例:")
print(df.head())
print(f"\n数据形状:{df.shape}")
# 简单的单级分组
region_sales = df.groupby('地区')['销售额'].sum()
print("\n按地区分组销售额:")
print(region_sales)
# 多级分组:地区 + 产品类别
multi_group = df.groupby(['地区', '产品类别'])['销售额'].sum()
print("\n按地区和产品类别分组:")
print(multi_group)
多级分组索引操作
python
python
# 创建多级分组对象
grouped = df.groupby(['年份', '季度', '地区'])
# 查看分组结构
print("分组数量:", grouped.ngroups)
print("分组键示例:", list(grouped.groups.keys())[:5])
# 选择特定分组的数据
specific_group = grouped.get_group((2022, 'Q2', '华东'))
print("\n2022年Q2华东地区数据:")
print(specific_group.head())
# 多级索引的切片操作
multi_index_result = df.groupby(['年份', '季度'])['销售额'].sum()
print("\n按年份和季度分组的销售额:")
print(multi_index_result)
# 使用unstack转换格式
pivot_result = multi_index_result.unstack()
print("\n数据透视格式:")
print(pivot_result)
# 交换索引层级
swapped = multi_index_result.swaplevel()
print("\n交换层级后的结果:")
print(swapped.head())
二、高级聚合:多维度统计的艺术
单一聚合函数已经不能满足需求?来看看高级聚合能做什么!
多指标聚合
python
python
# 同时对多个列应用多个聚合函数
advanced_agg = df.groupby(['地区', '产品类别']).agg({
'销售额': ['sum', 'mean', 'std', 'max', 'min'],
'销量': ['sum', 'mean', 'count']
}).round(2)
print("多指标聚合结果:")
print(advanced_agg)
# 自定义列名
custom_agg = df.groupby(['地区', '产品类别']).agg(
总销售额=('销售额', 'sum'),
平均销售额=('销售额', 'mean'),
销售额标准差=('销售额', 'std'),
最高销售额=('销售额', 'max'),
总销量=('销量', 'sum'),
订单数量=('销量', 'count')
).round(2)
print("\n自定义列名的聚合结果:")
print(custom_agg)
条件聚合
python
python
# 定义条件聚合函数
def high_sales_mean(df):
"""只计算高销售额(大于平均值)的平均值"""
high_sales = df[df['销售额'] > df['销售额'].mean()]
return high_sales['销售额'].mean()
def sales_distribution(df):
"""计算销售额分布:低/中/高"""
q1 = df['销售额'].quantile(0.25)
q3 = df['销售额'].quantile(0.75)
low = (df['销售额'] < q1).sum()
medium = ((df['销售额'] >= q1) & (df['销售额'] <= q3)).sum()
high = (df['销售额'] > q3).sum()
return pd.Series({'低销售额': low, '中销售额': medium, '高销售额': high})
# 应用条件聚合
conditional_result = df.groupby(['地区']).apply(
lambda x: pd.Series({
'高销售额平均值': high_sales_mean(x),
'总销售额': x['销售额'].sum(),
'高销售额占比': (x['销售额'] > x['销售额'].mean()).mean() * 100
})
).round(2)
print("条件聚合结果:")
print(conditional_result)
三、复杂分组场景实战
场景一:时间序列+多维度分组
python
python
# 创建时间序列数据
dates = pd.date_range('2023-01-01', periods=365, freq='D')
time_series_data = pd.DataFrame({
'日期': np.random.choice(dates, 1000),
'城市': np.random.choice(['北京', '上海', '广州', '深圳'], 1000),
'产品线': np.random.choice(['手机', '电脑', '平板', '配件'], 1000),
'销售额': np.random.uniform(100, 10000, 1000).round(2),
'利润率': np.random.uniform(0.1, 0.5, 1000)
})
# 添加时间维度列
time_series_data['月份'] = time_series_data['日期'].dt.month
time_series_data['季度'] = time_series_data['日期'].dt.quarter
time_series_data['星期几'] = time_series_data['日期'].dt.day_name()
# 多层时间+维度分组
time_grouped = time_series_data.groupby(
['城市', time_series_data['日期'].dt.to_period('M'), '产品线']
)
# 复杂聚合计算
time_analysis = time_grouped.agg({
'销售额': ['sum', 'mean', 'count'],
'利润率': lambda x: (x.mean() * 100).round(2)
}).round(2)
print("时间序列多维度分析:")
print(time_analysis.head(10))
场景二:跨维度计算指标
python
python
# 计算每个地区-产品类别的市场份额
total_sales_by_region = df.groupby('地区')['销售额'].sum()
total_sales_by_category = df.groupby('产品类别')['销售额'].sum()
# 方法1:使用transform计算组内占比
df['地区内占比'] = df.groupby('地区')['销售额'].transform(
lambda x: x / x.sum() * 100
).round(2)
df['类别内占比'] = df.groupby('产品类别')['销售额'].transform(
lambda x: x / x.sum() * 100
).round(2)
# 方法2:计算跨维度指标
market_share = df.groupby(['地区', '产品类别']).agg({
'销售额': 'sum'
}).groupby(level=0).transform(
lambda x: x / x.sum() * 100
).round(2)
market_share.columns = ['地区市场份额']
market_share = market_share.reset_index()
print("\n市场份额分析:")
print(market_share.head(10))
# 方法3:使用pivot_table计算
pivot_market = pd.pivot_table(
df,
values='销售额',
index='地区',
columns='产品类别',
aggfunc='sum',
margins=True,
margins_name='总计'
)
# 计算行百分比
row_percentage = pivot_market.div(pivot_market.iloc[:, -1], axis=0) * 100
print("\n各产品在各地区的销售占比:")
print(row_percentage.round(2))
四、高级技巧:自定义聚合与复杂计算
技巧1:链式聚合
python
python
# 链式聚合:先分组计算,再对结果进行二次计算
def analyze_sales_trend(group):
"""分析销售趋势"""
if len(group) < 2:
return pd.Series({
'增长趋势': '数据不足',
'月均增长率': 0,
'稳定性': 0
})
# 按月份排序
sorted_group = group.sort_values('月份')
# 计算增长率
growth_rates = sorted_group['销售额'].pct_change().dropna()
# 判断趋势
if growth_rates.mean() > 0.1:
trend = '快速增长'
elif growth_rates.mean() > 0:
trend = '缓慢增长'
elif growth_rates.mean() < -0.1:
trend = '快速下降'
else:
trend = '稳定'
return pd.Series({
'增长趋势': trend,
'月均增长率': growth_rates.mean() * 100,
'稳定性': 1 - growth_rates.std(),
'数据点数': len(group)
})
# 应用链式聚合
chain_analysis = time_series_data.groupby(['城市', '产品线']).apply(analyze_sales_trend)
print("\n销售趋势分析:")
print(chain_analysis.head(10))
技巧2:递归分组分析
python
python
def recursive_group_analysis(df, group_cols, depth=0, max_depth=2):
"""递归分组分析函数"""
if depth >= max_depth or not group_cols:
return df['销售额'].describe()
current_col = group_cols[0]
remaining_cols = group_cols[1:]
results = {}
for group_name, group_data in df.groupby(current_col):
if depth == max_depth - 1:
results[group_name] = group_data['销售额'].describe()
else:
results[group_name] = recursive_group_analysis(
group_data, remaining_cols, depth + 1, max_depth
)
return pd.concat(results, names=[current_col])
# 递归分析示例
recursive_result = recursive_group_analysis(
df,
group_cols=['地区', '产品类别', '年份'],
max_depth=2
)
print("\n递归分组分析结果:")
print(recursive_result.head(20))
五、性能优化与最佳实践
性能优化技巧
python
python
# 技巧1:使用named aggregation(性能更好)
fast_agg = df.groupby(['地区', '产品类别']).agg(
总销售额=pd.NamedAgg(column='销售额', aggfunc='sum'),
平均销售额=pd.NamedAgg(column='销售额', aggfunc='mean'),
销售数量=pd.NamedAgg(column='销量', aggfunc='sum')
)
# 技巧2:预过滤数据
# 错误做法:分组后过滤
# 正确做法:先过滤再分组
high_value_data = df[df['销售额'] > df['销售额'].quantile(0.75)]
grouped_high = high_value_data.groupby(['地区', '产品类别']).agg({'销售额': 'sum'})
# 技巧3:使用categorical类型加速分组
df['地区'] = df['地区'].astype('category')
df['产品类别'] = df['产品类别'].astype('category')
# 重新分组(会更快)
optimized_grouping = df.groupby(['地区', '产品类别']).agg({'销售额': 'sum'})
实用函数封装
python
python
def smart_group_analysis(df, group_columns, value_column,
agg_funcs=None, top_n=None):
"""
智能分组分析函数
参数:
- df: 数据框
- group_columns: 分组列列表
- value_column: 分析值列
- agg_funcs: 聚合函数字典,默认包含常用统计量
- top_n: 只显示前N个分组
"""
if agg_funcs is None:
agg_funcs = {
'总和': 'sum',
'平均值': 'mean',
'标准差': 'std',
'最小值': 'min',
'最大值': 'max',
'中位数': 'median',
'计数': 'count'
}
# 执行分组聚合
result = df.groupby(group_columns)[value_column].agg(agg_funcs)
# 如果需要,筛选前N个
if top_n and len(group_columns) == 1:
total_by_group = df.groupby(group_columns[0])[value_column].sum()
top_groups = total_by_group.nlargest(top_n).index
result = result.loc[top_groups]
return result.round(2)
# 使用封装函数
quick_analysis = smart_group_analysis(
df=df,
group_columns=['地区', '产品类别'],
value_column='销售额',
top_n=5
)
print("\n智能分组分析结果:")
print(quick_analysis.head(10))
六、真实业务场景应用
电商销售漏斗分析
python
python
# 模拟电商数据
ecommerce_data = pd.DataFrame({
'user_id': np.arange(1, 1001),
'注册日期': pd.date_range('2023-01-01', periods=1000, freq='D'),
'用户层级': np.random.choice(['新用户', '活跃用户', '核心用户', '流失用户'], 1000, p=[0.3, 0.4, 0.2, 0.1]),
'所在城市': np.random.choice(['一线城市', '二线城市', '三线及以下'], 1000),
'最近购买月份': pd.to_datetime(np.random.choice(
pd.date_range('2023-01-01', '2023-12-01', freq='M'), 1000
)),
'购买金额': np.random.exponential(500, 1000).round(2),
'购买次数': np.random.poisson(3, 1000)
})
# 添加月份信息
ecommerce_data['注册月份'] = ecommerce_data['注册日期'].dt.to_period('M')
ecommerce_data['最近购买月份'] = ecommerce_data['最近购买月份'].dt.to_period('M')
# 复杂的分层分组分析
funnel_analysis = ecommerce_data.groupby(
['注册月份', '用户层级', '所在城市']
).agg({
'user_id': 'count',
'购买金额': ['sum', 'mean'],
'购买次数': ['sum', 'mean']
}).round(2)
# 计算用户留存率
cohort_analysis = ecommerce_data.pivot_table(
index='注册月份',
columns=ecommerce_data['最近购买月份'] - ecommerce_data['注册月份'],
values='user_id',
aggfunc='count'
).fillna(0)
print("\n电商用户漏斗分析:")
print(funnel_analysis.head(15))
总结
- 通过本文的学习,你应该已经掌握了Pandas多级分组和高级聚合的核心技能:
多级分组让你能够从多个维度深入分析数据
高级聚合提供了丰富的统计方法和自定义能力
性能优化确保分析效率
实用封装提高代码复用性 - 记住这些最佳实践:
合理使用多级索引和unstack进行数据重塑
优先使用内置聚合函数,必要时再使用自定义函数
对分类数据使用categorical类型提升性能
封装常用分析模式为可重用函数
多级分组和高级聚合不仅是技术工具,更是数据思维的体现。它们帮助你发现数据中的模式、趋势和异常,为业务决策提供有力支持。