如何用Pandas按cust_id和product_id分组生成降序占比与数量分布列表
问题:按客户和产品分组计算区域购买占比与数量统计
给定如下Pandas DataFrame:
import pandas as pd data = { 'cust_id': ['abc', 'abc', 'abc', 'abc', 'abc', 'abc', 'abc', 'abc', 'abc', 'abc'], 'product_id': [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], 'purchase_country': ['India', 'India', 'India', 'Australia', 'Australia', 'Australia', 'Australia', 'Australia', 'Australia', 'Australia'] } df = pd.DataFrame(data)
需要完成以下目标:
- 创建
pct_region_split和num_region_split两列 pct_region_split存储各国家购买占比(如示例中Australia占70%,India占30%)num_region_split存储各国家购买行数/总行数(如示例中Australia为7/10,India为3/10)- 两列的值均以降序列表格式存储(占比高的排在前面)
尝试过以下代码但未得到预期结果:
df['total_purchases'] = df.groupby(['cust_id', 'product_id'])['purchase_country'].transform('size') df['unique_country'] = df.groupby(['cust_id', 'product_id'])['purchase_country'].transform('nunique')
注:真实数据包含1000+客户和200+产品组合,需得到每个cust_id+product_id组合对应的结果。
解决方案
直接通过分组统计+聚合整理的方式实现,代码如下:
# 1. 三级分组统计:客户+产品+国家,计算每个国家的购买次数 grouped = df.groupby(['cust_id', 'product_id', 'purchase_country']).size().reset_index(name='count') # 2. 计算每个客户-产品组的总购买数 grouped['total'] = grouped.groupby(['cust_id', 'product_id'])['count'].transform('sum') # 3. 计算占比并按占比降序排序(确保列表中占比高的在前) grouped['pct'] = (grouped['count'] / grouped['total'] * 100).round(1) grouped = grouped.sort_values(by=['cust_id', 'product_id', 'pct'], ascending=[True, True, False]) # 4. 聚合每个客户-产品组,生成列表格式的结果列 result = grouped.groupby(['cust_id', 'product_id']).agg( pct_region_split=('pct', lambda x: list(x)), num_region_split=('count', lambda x: [f"{cnt}/{x.sum()}" for cnt in x]) ).reset_index() # 查看结果 print(result)
输出结果
cust_id product_id pct_region_split num_region_split 0 abc 12 [70.0, 30.0] ['7/10', '3/10']
扩展:将结果合并回原DataFrame
如果需要让原DataFrame的每一行都带上对应的列表列,可执行以下代码:
df_final = df.merge(result, on=['cust_id', 'product_id'], how='left') print(df_final.head())
该方案高效适配大规模数据(1000+客户/200+产品),所有操作均基于Pandas内置分组函数,避免循环遍历,性能更优。
内容的提问来源于stack exchange,提问作者The Great
相关产品推荐
相关产品推荐

