使用 pandas 计算三向交叉表中不同类型的百分比

问题描述 投票:0回答:1

假设我有一个简单调查的结果,其中受访者被分为 A、B 和 C 组,并被问到一个简单的是/否问题。我在 3 个月内(2023 年 8 月、9 月和 10 月)对此调查做出了回复。

我有以下格式的数据:

agg_counts=[
    {"group":'A','answer':'yes','month':'Aug 2023','count':12},
    {"group":'A','answer':'yes','month':'Sep 2023','count':5},
    {"group":'A','answer':'yes','month':'Oct 2023','count':4},
    {"group":'A','answer':'no','month':'Aug 2023','count':9},
    {"group":'A','answer':'no','month':'Sep 2023','count':10},
    {"group":'A','answer':'no','month':'Oct 2023','count':3},
    {"group":'B','answer':'yes','month':'Aug 2023','count':21},
    {"group":'B','answer':'yes','month':'Sep 2023','count':3},
    {"group":'B','answer':'yes','month':'Oct 2023','count':6},
    {"group":'B','answer':'no','month':'Aug 2023','count':8},
    {"group":'B','answer':'no','month':'Sep 2023','count':9},
    {"group":'B','answer':'no','month':'Oct 2023','count':2},
    {"group":'C','answer':'yes','month':'Aug 2023','count':11},
    {"group":'C','answer':'yes','month':'Sep 2023','count':4},
    {"group":'C','answer':'yes','month':'Oct 2023','count':9},
    {"group":'C','answer':'no','month':'Aug 2023','count':8},
    {"group":'C','answer':'no','month':'Sep 2023','count':1},
    {"group":'C','answer':'no','month':'Oct 2023','count':13}
    ]

以月份为列的交叉表如下所示:

month         Aug 2023  Oct 2023  Sep 2023
group answer                              
A     no             9         3        10
      yes           12         4         5
B     no             8         2         9
      yes           21         6         3
C     no             8        13         1
      yes           11         9         4

我想计算各组内的垂直百分比(因此 2023 年 8 月 A 组内的百分比加起来为 100%)、各组之间的垂直百分比(因此 2023 年 8 月列中的百分比加起来为 100%),以及水平百分比(因此每行的百分比加起来为 100%)。然后,我希望将数据放在 DataFrame 中,其中的列为:组、答案、月份、计数和 3 种类型的百分比。

我设法做到了这一点,但我认为必须有一种更好、更高效、更简洁的方法来做到这一点。

我这样做的方法是创建 3 个具有不同列/行/规范化选项的交叉表,将它们堆叠起来,重置索引,然后将它们合并到 DataFrame 中:

df=pd.DataFrame(agg_counts)

vp_it=pd.crosstab(
    columns=[df['group'],df['month']],
    index=[df['answer']],
    values=df['count'],
    aggfunc=np.sum,
    normalize='columns'
    )
df_vp_it=vp_it.stack([0,1]).reset_index().rename(columns={0:"vp_inner"})

vp_ot=pd.crosstab(
    columns=[df['month']],
    index=[df['group'],df['answer']],
    values=df['count'],
    aggfunc=np.sum,
    normalize='columns'
    )
df_vp_ot=vp_ot.stack(0).reset_index().rename(columns={0:"vp_outer"})

hp=pd.crosstab(
    columns=[df['month']],
    index=[df['group'],df['answer']],
    values=df['count'],
    aggfunc=np.sum,
    normalize='index'
    )
df_hp=hp.stack([0]).reset_index().rename(columns={0:"hp"})

merge_columns=['group','answer','month']
df_merged=df.merge(df_vp_it,on=merge_columns).merge(df_vp_ot,on=merge_columns).merge(df_hp,on=merge_columns)

是否有更好的方法来创建相同的输出?

pandas dataframe pivot-table
1个回答
0
投票

通过单个命令将数据转换为数据透视表(即所谓的“交叉表”):

df = pd.DataFrame(agg_counts).pivot_table(index=['group', 'answer'], columns='month')

然后,通过将每组的元素除以每组的总数(垂直分组归一化)来得到绝对数字相对百分比:

result = df/df.groupby('group').sum()

这是列份额(按组)。我认为您不能确保它同时也是“行”百分比..这些将是不同的值。这些数字要么“按组”(垂直)相加,要么“所有月份”(水平)相加,但不能同时进行,不是吗?

© www.soinside.com 2019 - 2024. All rights reserved.