如何用pandas pivot_table聚合布尔值列并生成特定统计矩阵?
用Pivot Table实现自定义统计矩阵方案
当然可以用pivot_table实现你要的统计矩阵,不过需要先补充全局和各类汇总的统计数据,再调整结构适配你要的格式。咱们一步步来操作:
第一步:还原原始数据
先把你给出的DataFrame还原出来,方便后续操作:
import pandas as pd import numpy as np data = { 'code': [1000, 1000, 1000, 1000, 2000, 2000, 2000, 2000, 2000], 'y_m': [201701, 201701, 201702, 201702, 201701, 201701, 201702, 201702, 201702], 'has_id': [True, False, True, True, True, False, False, False, True] } df = pd.DataFrame(data)
第二步:计算所有需要的占比统计
你的需求里不仅有code+y_m的分组占比,还需要全局、单独code、单独y_m的占比,所以要把这些统计都算出来:
- 基础分组占比(你已经实现的部分):
grouped = df.groupby(['code', 'y_m'])['has_id'].apply(lambda x: np.sum(x)/len(x)).reset_index(name='pct_with_id')
- 单独code的全局占比(不区分y_m):
code_total = df.groupby('code')['has_id'].apply(lambda x: np.sum(x)/len(x)).reset_index(name='pct_with_id') code_total['y_m'] = 'total' # 标记为code总计
- 单独y_m的全局占比(不区分code):
ym_total = df.groupby('y_m')['has_id'].apply(lambda x: np.sum(x)/len(x)).reset_index(name='pct_with_id') ym_total['code'] = 'total' # 标记为y_m总计
- 全量数据的占比:
global_total = pd.DataFrame({ 'code': ['total'], 'y_m': ['total'], 'pct_with_id': [df['has_id'].sum()/len(df)] })
- 合并所有统计数据:
combined = pd.concat([grouped, code_total, ym_total, global_total], ignore_index=True)
第三步:用Pivot Table生成基础透视表
现在用pivot_table把合并后的数据转换成透视表,同时用-1填充缺失值:
pivot = combined.pivot_table(index='code', columns='y_m', values='pct_with_id', fill_value=-1)
这时候得到的透视表结构如下:
| code | 201701 | 201702 | total |
|---|---|---|---|
| 1000 | 0.5 | 1.0 | 0.75 |
| 2000 | 0.5 | 0.333... | 0.4 |
| total | 0.5 | 0.6 | 0.555... |
第四步:调整成目标矩阵格式
最后我们需要把透视表调整成你要的带占位符和特殊行列的结构:
# 创建目标矩阵的空结构 result = pd.DataFrame(index=[0,1,2,3], columns=[0,1,2,3]) # 填充0行(表头行) result.loc[0] = [-1, 0, 201701, 201702] # 填充0列(行标识列) result.loc[1, 0] = 0 result.loc[2, 0] = 1000 result.loc[3, 0] = 2000 # 填充全局统计行(行1) result.loc[1, 1] = round(global_total['pct_with_id'].values[0], 2) # 全量占比≈0.56 result.loc[1, 2] = ym_total[ym_total['y_m']==201701]['pct_with_id'].values[0] # 201701占比0.5 result.loc[1, 3] = ym_total[ym_total['y_m']==201702]['pct_with_id'].values[0] # 201702占比0.6 # 填充code=1000的统计行(行2) result.loc[2, 1] = code_total[code_total['code']==1000]['pct_with_id'].values[0] # 0.75 result.loc[2, 2] = grouped[(grouped['code']==1000)&(grouped['y_m']==201701)]['pct_with_id'].values[0] # 0.5 result.loc[2, 3] = grouped[(grouped['code']==1000)&(grouped['y_m']==201702)]['pct_with_id'].values[0] # 1.0 # 填充code=2000的统计行(行3) result.loc[3, 1] = code_total[code_total['code']==2000]['pct_with_id'].values[0] # 0.4 result.loc[3, 2] = grouped[(grouped['code']==2000)&(grouped['y_m']==201701)]['pct_with_id'].values[0] # 0.5 result.loc[3, 3] = round(grouped[(grouped['code']==2000)&(grouped['y_m']==201702)]['pct_with_id'].values[0], 2) # ≈0.33
运行后得到的result就是你要的统计矩阵啦:
0 1 2 3 0 -1 0 201701 201702 1 0 0.56 0.5 0.6 2 1000 0.75 0.5 1.0 3 2000 0.4 0.5 0.33
简单来说,pivot_table帮我们完成了核心的分组透视工作,剩下的就是补充汇总数据和调整格式,完全可以满足你的需求~
内容的提问来源于stack exchange,提问作者daiyue
相关产品推荐
相关产品推荐

