将Pandas DataFrame中的分类变量转换为带有计数和比例的MultiIndex

4

我有一个包含多个分类变量的Pandas DataFrame。例如:

import pandas as pd

d = {'grade':['A','B','C','A','B'], 
    'year':['2013','2013','2013','2012','2012']}

df = pd.DataFrame(d)

enter image description here

我希望将其转换为MultiIndex DataFrame,其具有以下属性:

  • 第一级索引是变量名称(例如'grade')
  • 第二级索引是变量内的级别(例如'A'、'B'、'C')
  • 一个列包含'n',表示该级别出现的次数
  • 第二个列包含'proportion',表示该级别所代表的比例。

例如:

enter image description here

是否有人能够提供创建此MultiIndex DataFrame的方法?

4个回答

6

你可以使用meltgroupby来完成这个任务:

df_out = df.melt().groupby(['variable','value']).size().to_frame(name='n')
df_out['proportion'] = df_out['n'].div(df_out.n.sum(level=0),level=0)
print(df_out)

输出:

                n  proportion
variable value               
grade    A      2         0.4
         B      2         0.4
         C      1         0.2
year     2012   2         0.4
         2013   3         0.6

如果你真的想疯狂一点,可以用一行代码实现:

(df.melt().groupby(['variable','value']).size().to_frame(name='n')
  .pipe(lambda x: x.assign(proportion = x[['n']]/x.groupby(level=0).transform('sum'))))

使用 @Wen 百分比计算升级解决方案:
(df.melt().groupby(['variable','value']).size().to_frame(name='n')
  .pipe(lambda x: x.assign(proportion = x['n'].div(x.n.sum(level=0),level=0))))

管道在这里很好用 :-) - BENY
感谢Scott和@Wen提供的出色解决方案。最终我选择了Wen的答案,因为我发现这种方法更容易理解。 - tomp
1
@tomp 一切都好。我们只是喜欢帮助他人并为自己学习。编程愉快! - Scott Boston

3
您可以尝试这个...
df1=df.apply(pd.value_counts).stack().swaplevel(0,1).to_frame('n')
df1['pct']=df1['n'].div(df1.n.sum(level=0),level=0)
df1
Out[89]: 
              n  pct
year  2012  2.0  0.4
      2013  3.0  0.6
grade A     2.0  0.4
      B     2.0  0.4
      C     1.0  0.2

可以吗,如果我把你的百分比计算加入到我的解决方案中?我不喜欢使用 groupby transform,因为 sum level 也可以起作用。 - Scott Boston
2
@ScottBoston 请继续:-) 那不是我的,是我们的 :-) - BENY
@tomp yw~ 开心编程 - BENY

1
逐步方法:

df1 = df.groupby("grade").count()
df2 = df.groupby("year").count() 

df1.columns = ['n']
df2.columns = ['n']
df1['proportion'] = df1.divide(df1.sum())
df2['proportion'] = df2.divide(df2.sum())

df_new = pd.concat([df1, df2], keys=['grade', 'year'], names=['variable'])
  • 在使用concat时,可以分配keys作为最外层索引。还可以使用names=为此新索引分配名称。

enter image description here


0

可以通过循环堆叠每个变量来创建DataFrame,但这似乎效率低下。例如:

d_end = []
for c in df.columns:
    temp_df = pd.DataFrame(df[c].value_counts().rename('n'))
    temp_df['proportion'] = temp_df['n'] / temp_df['n'].sum()
    temp_df['variable'] = c
    temp_df.set_index(['variable',temp_df.index],inplace=True)
    d_end.append(temp_df)

df_end = pd.concat(d_end,axis=0)

我希望有人能提出更好的方法,避免使用循环。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接