【问题标题】:Pandas groupby using MultiIndex valuesPandas groupby 使用 MultiIndex 值
【发布时间】:2021-04-04 08:27:41
【问题描述】:

假设我有一个数据框,其中包含代表学生专业和学生 GPA 的多索引列。我想找到每一行的每个专业的班级排名。如果学生每个人只有一个专业,那么我可以将专业堆叠为 multiindex 和 groupby(level=1).rank() 的另一个级别。但是,因为学生可以改变他们的专业,所以我必须将这些作为每年的单独功能。什么是获得正确输出的有效方法?我知道我可以通过遍历行来强制它,但我希望避免这种情况,因为我可能正在处理大量数据。

样本df:

categories = ['major', 'gpa']
students = ['Joe', 'Bob', 'Sara']
columns = pd.MultiIndex.from_product([categories, students])
index = range(4)
students_df = pd.DataFrame([['english', 'math', 'math', 3.8, 2.2, 3.7],
                            ['english', 'math', 'math', 3.5, 2.4, 3.9],
                            ['english', 'english', 'math', 3.5, 3.6, 3.9],
                            ['english', 'english', 'math', 3.7, 3.5, 3.8],
                            ], index=range(4), columns=columns)
print(students_df)

         major                 gpa          
       Joe      Bob  Sara  Joe  Bob Sara
0  english     math  math  3.8  2.2  3.7
1  english     math  math  3.5  2.4  3.9
2  english  english  math  3.5  3.6  3.9
3  english  english  math  3.7  3.5  3.8

预期输出

       rank          
       Joe  Bob Sara
0      1      2    1
1      1      2    1
2      2      1    1
3      1      2    1

【问题讨论】:

    标签: python pandas pandas-groupby multi-index


    【解决方案1】:

    我想出了这个怪物。这是正确的,但我希望有人提供更好的解决方案:

    ranks = students_df.stack().reset_index()\
                       .groupby(['level_0', 'major']).rank(ascending=False)
    students_df.stack().reset_index().join(ranks, rsuffix='_rank')\
               .set_index(['level_0', 'level_1'])['gpa_rank'].unstack().astype(int)
    #level_1  Bob  Joe  Sara
    #level_0                
    #0          2    1     1
    #1          2    1     1
    #2          1    2     1
    #3          2    1     1
    

    【讨论】:

      【解决方案2】:

      您可以使用stack 设置数据框,以便您可以有效地groupby 索引([0,1,2,3])和major 计算rank。然后,unstack(1) 数据框回到它的原始列。传递给stack() 的整数参数指示多索引列级别的位置,您从列发送到行(或从宽到长)。而且,unstack() 正好相反——它从行发送到列(或从长到宽)。因此,0 是第一级,1 是第二级,依此类推。无论位置如何,stack() 和 unstack() 在取消透视/旋转数据帧方面都非常有效。

      这是使用.index.get_level_values(0)的方法1:

      df = students_df.stack(1)
      df = (df.assign(gpa=df.groupby([df.index.get_level_values(0), 'major'])
                            .rank(ascending=False)).unstack(1))
              
      Out[1]: 
         gpa              major               
         Bob  Joe Sara      Bob      Joe  Sara
      0  2.0  1.0  1.0     math  english  math
      1  2.0  1.0  1.0     math  english  math
      2  1.0  2.0  1.0  english  english  math
      3  2.0  1.0  1.0  english  english  math
      

      这是使用 rename_axis() 的方法 2,但输出略有不同:

      df = students_df.stack(1).rename_axis(['', 'Name'])
      df = df.assign(gpa=df.groupby(['', 'major']).rank(ascending=False)).unstack(1)
      df
      
      Out[2]: 
            gpa              major               
      Name  Bob  Joe Sara      Bob      Joe  Sara
      
      0     2.0  1.0  1.0     math  english  math
      1     2.0  1.0  1.0     math  english  math
      2     1.0  2.0  1.0  english  english  math
      3     2.0  1.0  1.0  english  english  math
      

      【讨论】:

        猜你喜欢
        • 2017-04-06
        • 2018-10-28
        • 1970-01-01
        • 2021-05-18
        • 2023-03-25
        • 1970-01-01
        • 1970-01-01
        • 2019-10-18
        • 2018-03-01
        相关资源
        最近更新 更多