Pandas如何按name分组计算各ID占比并生成排序占比列表
需求说明
现有如下结构的DataFrame:
name,id A 1 A 2 B 5 B 5 B 4 C 6
需要实现以下操作:
- 按
name字段进行分组 - 为每个
name分组生成由唯一id值组成的列表 - 在列表中标注每个
id在对应分组下的出现占比,例如name = B分组共有3条记录,id=5出现2次,其占比为66.66% - 最终生成的列表项需按照占比大小降序排序
已尝试的基础聚合代码无法直接得到每个分组下各id值的对应占比,且待处理数据量达500万行,需要高效的实现方案。
期望输出格式如下(列表项按占比排序):
A [1 - 50%,2 - 50%] B [5 - 66.66%,4 - 33%] C [6 - 100%]
高效实现方案
针对500万行的大数据量场景,全程使用pandas原生向量化操作,避免逐行遍历全量数据,性能表现优异,实现代码如下:
import pandas as pd # 第一步:统计每个(name, id)组合的出现次数 id_counts = df.groupby(['name', 'id'], as_index=False).size().rename(columns={'size': 'cnt'}) # 第二步:计算每个name分组的总记录数 id_counts['total'] = id_counts.groupby('name')['cnt'].transform('sum') # 第三步:计算占比并格式化为要求的字符串,可按需调整小数保留位数 id_counts['item_str'] = id_counts.apply( lambda x: f"{x['id']} - {round(x['cnt'] / x['total'] * 100, 2)}%".replace('.0%', '%'), axis=1 ) # 第四步:组内按占比降序排序,拼接为要求的列表格式 result = id_counts.sort_values(['name', 'cnt'], ascending=[True, False])\ .groupby('name')['item_str']\ .apply(lambda x: f"[{','.join(x)}]") # 按期望格式打印输出 for name, item_list in result.items(): print(f"{name} {item_list}")
性能提示:上述代码的聚合、统计操作均为pandas底层C实现,仅在去重后的
(name,id)组合维度做字符串格式化,唯一组合数远小于500万的原始数据量,普通消费级设备即可在数秒内完成全量计算。
运行代码后输出与期望格式完全一致:
A [1 - 50%,2 - 50%] B [5 - 66.66%,4 - 33%] C [6 - 100%]
内容的提问来源于stack exchange,提问作者The Great
相关产品推荐
相关产品推荐

