使用额外的列对DataFrame进行分组和数据透视

时间:2018-12-19 16:26:58

标签: python pandas group-by pandas-groupby counting

我有一个看起来像这样的数据框:

id       status      year 
1        yes         2014
3        no          2013
2        yes         2014
4        no          2014

实际数据框非常大,具有多个ID和年份。我正在尝试创建一个新的数据框,其中包含按年份分组的“是”和“否”的百分比。

我当时正在考虑按年份对数据框进行分组,然后将每年的状态放在列表中,然后以这种方式分析是和否的计数,但是我想知道是否还有一种更Python化的方法这个吗?

我希望最终数据帧看起来像这样:

year      yes_count     no_count     ratio_yes_to_toal    
2013       0             1             0%
2014       2             1             67%

4 个答案:

答案 0 :(得分:2)

我建议按yearstatus分组,计数,旋转并创建比例的其他列:

df2 = df.groupby(['year', 'status']).count().pivot_table(index="year", columns=["status"]).fillna(0)
df2.columns = df2.columns.get_level_values(1)
df2['ratio'] = df2['yes'] / (df2['yes'] + df2['no'])

输出

status   no  yes     ratio
year                      
2013    1.0  0.0  0.000000
2014    1.0  2.0  0.666667

答案 1 :(得分:2)

您可以使用pivot_table而不使用groupby以获得更快的解决方案。

v = df.pivot_table(index='year', columns='status', aggfunc='size').fillna(0) 
v.join((v['yes'] / v.sum(1)).to_frame('ratio'))
# Or, if you care about micro-optimizing the code, 
# v['ratio'] = v['yes'] / v.sum(1)

       no  yes     ratio
year                    
2013  1.0  0.0  0.000000
2014  1.0  2.0  0.666667

答案 2 :(得分:1)

要获取计数和百分比,可能最简单的方法是分两步进行操作:groupby + value_counts + unstack,然后进行除法。

df1 = df.groupby('year').status.value_counts().unstack(1).fillna(0)
df1['ratio_yes'] = df1['yes'].div(df1.sum(1), axis=0)*100

#status   no  yes  ratio_yes
#year                       
#2013    1.0  0.0   0.000000
#2014    1.0  2.0  66.666667

如果只需要百分比,则可以添加normalize=True参数,并一步一步完成:

df1 = df.groupby('year').status.value_counts(normalize=True).unstack(1).fillna(0)*100

#status          no        yes
#year                         
#2013    100.000000   0.000000
#2014     33.333333  66.666667

答案 3 :(得分:0)

pd.crosstab

您可以交叉列表化数据框,然后计算比率:

res = pd.crosstab(df['year'], df['status'])
res['yes_pct'] = res['yes'].div(res.sum(1))

print(res)

status  no  yes   yes_pct
year                     
2013     1    0  0.000000
2014     1    2  0.666667