假设我有一个简单调查的结果,其中受访者被分为 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)
是否有更好的方法来创建相同的输出?
通过单个命令将数据转换为数据透视表(即所谓的“交叉表”):
df = pd.DataFrame(agg_counts).pivot_table(index=['group', 'answer'], columns='month')
然后,通过将每组的元素除以每组的总数(垂直分组归一化)来得到绝对数字相对百分比:
result = df/df.groupby('group').sum()
这是列份额(按组)。我认为您不能确保它同时也是“行”百分比..这些将是不同的值。这些数字要么“按组”(垂直)相加,要么“所有月份”(水平)相加,但不能同时进行,不是吗?