如果之前有人问过类似的问题,我很抱歉,我四处搜索但找不到解决方案。
我的数据集看起来像这样
data1 = {'Group':['Winner','Winner','Winner','Loser','Loser','Loser'],
'MathStudy': ['Read','Read','Notes','Cheat','Cheat','Read'],
'ScienceStudy': ['Notes','Read','Cheat','Cheat','Read','Notes']}
df1 = pd.DataFrame(data=data1)
我想获得每个组的每个类别的总数百分比,如下所示。在我的数据集中,赢家和输家的数量会发生变化,因此非常感谢灵活的解决方案。
先谢谢你!
答案 0 :(得分:4)
将 DataFrame.melt
与 crosstab
和 normalize
参数一起使用:
df1 = df1.melt('Group', var_name='Type')
df2 = pd.crosstab([df1['Group'], df1['Type']], df1['value'], normalize=0)
print (df2)
value Cheat Notes Read
Group Type
Loser MathStudy 0.666667 0.000000 0.333333
ScienceStudy 0.333333 0.333333 0.333333
Winner MathStudy 0.000000 0.333333 0.666667
ScienceStudy 0.333333 0.333333 0.333333
最后如果需要 MultiIndex
到带有删除 value
列名的列添加 DataFrame.rename_axis
和 DataFrame.reset_index
:
df2 = df2.rename_axis(columns=None).reset_index()
print (df2)
Group Type Cheat Notes Read
0 Loser MathStudy 0.666667 0.000000 0.333333
1 Loser ScienceStudy 0.333333 0.333333 0.333333
2 Winner MathStudy 0.000000 0.333333 0.666667
3 Winner ScienceStudy 0.333333 0.333333 0.333333
答案 1 :(得分:4)
@jezrael 的解决方案很直观,而且我会直接做。但是,我最近了解到 melt
通常表现不佳。如果性能很重要,这是一个替代方案,例如在重复使用的代码中:
g = df1.groupby('Group')
cols = ['MathStudy', 'ScienceStudy']
out = (pd.concat({col:g[col].value_counts(normalize=True) for col in cols})
.unstack(level=-1, fill_value=0)
)
带运行时间:
2.9 ms ± 96.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
与 melt
方法相比:
9.44 ms ± 261 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
输出:
Cheat Notes Read
MathStudy Loser 0.666667 0.000000 0.333333
Winner 0.000000 0.333333 0.666667
ScienceStudy Loser 0.333333 0.333333 0.333333
Winner 0.333333 0.333333 0.333333
注意:pd.crosstab
本质上是 groupby()
,带有一些额外的簿记。两列上的 groupby
通常要慢得多。
答案 2 :(得分:2)
这是另一种选择:
g = df.set_index('Group').stack().str.get_dummies().groupby(level=[0,1]).sum()
g.div(g.sum(axis=1),axis=0).round(2)