Pandas按指定列分类统计其他列唯一值出现频率
pandas按分类列分组统计其余列值频率实现方案
问题描述
使用pandas处理数据时,若数据表某一列包含4个分类值,需要针对该列的每一个唯一分类值,分别统计其余所有列中各唯一值的出现频率。
部分DataFrame数据示例
预期输出效果
实现代码
1. 构造测试样例
先构造和示例结构一致的测试数据,方便复现效果:
import pandas as pd # 测试数据,实际使用时替换为你自己的DataFrame即可 df = pd.DataFrame({ 'category_col': ['A','A','A','B','B','B','C','C','C','D','D','D'], # 含4个分类值的目标列 'feature1': [1,1,2,2,3,3,1,2,3,1,1,3], 'feature2': ['x','x','y','y','z','z','x','y','z','x','z','z'], 'feature3': ['m','n','m','n','m','n','m','m','n','n','m','n'] })
2. 核心统计逻辑
直接通过groupby按分类列分组,对组内其余列逐列做归一化计数即可得到频率结果,输出结构和预期完全匹配:
# 替换为你的分类列实际列名 target_col = 'category_col' # 自动提取所有需要统计的非分类列 calc_cols = df.columns.drop(target_col) # 分组统计各值出现频率 freq_result = df.groupby(target_col)[calc_cols].apply( lambda group: group.apply(lambda col: col.value_counts(normalize=True)) ).fillna(0) # 若需要输出百分比格式,取消下行注释即可 # freq_result = freq_result.applymap(lambda val: f"{val*100:.1f}%")
运行后freq_result的行索引为分类列的4个唯一值,列索引对应其余列的各个唯一取值,单元格值即为对应取值在该分类分组下的出现频率。
3. 可选:长表格式输出
如果需要用于后续可视化、透视表操作的长表结构(每行对应1条「分类+列名+取值+频率」记录),可以使用如下写法:
freq_result_long = df.melt(id_vars=target_col, value_vars=calc_cols)\ .groupby([target_col, 'variable', 'value'])\ .size()\ .groupby(level=[0,1])\ .apply(lambda s: s / s.sum())\ .reset_index(name='frequency')
常见调整说明
- 若需要统计出现次数而非频率,删除
value_counts的normalize=True参数,同时移除长表写法中的/s.sum()计算即可 - 若需要把空值纳入统计,在
value_counts中加入参数dropna=False - 数据量较大时该方法计算效率稳定,不需要额外做循环遍历优化
内容的提问来源于stack exchange,提问作者Sergei Semenets
相关产品推荐
相关产品推荐

