如何在Python Pandas中基于二进制列与范围列聚合计算CH列占比
在Pandas中按指定组合计算CH列值为1的百分比
原始DataFrame
| ID | U1 | U2 | U3 | CP | CH |
|---|---|---|---|---|---|
| 111 | 1 | 1 | 0 | 10-20 | 1 |
| 222 | 1 | 0 | 1 | 10-20 | 1 |
| 333 | 0 | 1 | 0 | 20-30 | 0 |
| 444 | 0 | 1 | 1 | 40-50 | 0 |
| 555 | 1 | 0 | 0 | 10-20 | 0 |
需求说明
需要按U1/U2/U3与CP的所有可能组合,计算CH列值为1的百分比,期望结果如下:
| idx | idx | CH_perc | 说明 |
|---|---|---|---|
| U1 | CP_10_20 | 0.66 | 3个ID的U1为1且CP=10-20,其中2个的CH为1,故2/3≈0.66 |
| U1 | CP_20_30 | 0 | 无符合条件的记录,百分比为0 |
| U1 | CP_30_40 | 0 | 无符合条件的记录,百分比为0 |
| U1 | CP_40_50 | 0 | 无符合条件的记录,百分比为0 |
| U2 | CP_10_20 | 1.00 | 1个ID的U2为1且CP=10-20,其CH为1,故1/1=1.00 |
| U2 | CP_20_30 | 0 | 1个ID的U2为1且CP=20-30,其CH为0,故0/1=0 |
| U2 | CP_30_40 | 0 | 无符合条件的记录,百分比为0 |
| U2 | CP_40_50 | 0 | 1个ID的U2为1且CP=40-50,其CH为0,故0/1=0 |
| U3 | CP_10_20 | 1.00 | 1个ID的U3为1且CP=10-20,其CH为1,故1/1=1.00 |
| U3 | CP_20_30 | 0 | 无符合条件的记录,百分比为0 |
| U3 | CP_30_40 | 0 | 无符合条件的记录,百分比为0 |
| U3 | CP_40_50 | 0 | 1个ID的U3为1且CP=40-50,其CH为0,故0/1=0 |
实现方案
完整代码
import pandas as pd import itertools # 构造原始DataFrame data = { 'ID': [111, 222, 333, 444, 555], 'U1': [1, 1, 0, 0, 1], 'U2': [1, 0, 1, 1, 0], 'U3': [0, 1, 0, 1, 0], 'CP': ['10-20', '10-20', '20-30', '40-50', '10-20'], 'CH': [1, 1, 0, 0, 0] } df = pd.DataFrame(data) # 1. 格式化CP列,转换为期望的CP_xx_xx格式 df['CP_formatted'] = 'CP_' + df['CP'].str.replace('-', '_') # 2. 宽表转长表,将U1/U2/U3拆分为单独行 melted = df.melt( id_vars=['CP_formatted', 'CH'], value_vars=['U1', 'U2', 'U3'], var_name='U_col', value_name='is_active' ) # 3. 生成U列和所有CP值的全量组合索引 u_cols = ['U1', 'U2', 'U3'] cp_values = ['CP_10_20', 'CP_20_30', 'CP_30_40', 'CP_40_50'] all_combinations = pd.MultiIndex.from_tuples( itertools.product(u_cols, cp_values), names=['U_col', 'CP_formatted'] ) # 4. 筛选活跃行(U列值为1),分组计算CH的均值(即1的占比),并补全缺失组合 grouped = melted[melted['is_active'] == 1].groupby(['U_col', 'CP_formatted'])['CH'].mean() grouped = grouped.reindex(all_combinations, fill_value=0) # 5. 整理结果格式,保留两位小数 result = grouped.reset_index().rename(columns={'U_col': 'idx', 'CP_formatted': 'idx', 'CH': 'CH_perc'}) result['CH_perc'] = result['CH_perc'].round(2) print(result)
代码说明
- 格式化CP列:把原始
CP列的10-20格式转换为CP_10_20,匹配期望结果的格式。 - 宽转长:将
U1/U2/U3三列拆分为行记录,方便后续按U列分组计算。 - 生成全量组合:通过笛卡尔积生成所有U列和CP值的组合,确保没有遗漏的分组。
- 计算百分比:筛选出U列值为1的行,按组合分组后计算
CH的均值(因为CH是0/1,均值直接代表1的占比),用reindex补全缺失组合并填充0。 - 整理格式:将结果转换为指定的列名格式,保留两位小数。
运行输出
idx idx CH_perc 0 U1 CP_10_20 0.67 1 U1 CP_20_30 0.00 2 U1 CP_30_40 0.00 3 U1 CP_40_50 0.00 4 U2 CP_10_20 1.00 5 U2 CP_20_30 0.00 6 U2 CP_30_40 0.00 7 U2 CP_40_50 0.00 8 U3 CP_10_20 1.00 9 U3 CP_20_30 0.00 10 U3 CP_30_40 0.00 11 U3 CP_40_50 0.00
内容的提问来源于stack exchange,提问作者unbik
相关产品推荐
相关产品推荐

