【问题标题】:pandas groupby sort within groupspandas groupby 在组内排序
【发布时间】:2015-03-06 17:08:54
【问题描述】:

我想将我的数据框按两列分组,然后对组内的聚合结果进行排序。

In [167]: df

Out[167]:
   count     job source
0      2   sales      A
1      4   sales      B
2      6   sales      C
3      3   sales      D
4      7   sales      E
5      5  market      A
6      3  market      B
7      2  market      C
8      4  market      D
9      1  market      E


In [168]: df.groupby(['job','source']).agg({'count':sum})

Out[168]:
               count
job    source       
market A           5
       B           3
       C           2
       D           4
       E           1
sales  A           2
       B           4
       C           6
       D           3
       E           7

我现在想在每个组中按降序对计数列进行排序。然后只取前三行。得到类似的东西:

                count
job     source
market  A           5
        D           4
        B           3
sales   E           7
        C           6
        B           4

【问题讨论】:

    标签: python sorting pandas group-by


    【解决方案1】:

    你想要做的实际上还是一个 groupby(在第一个 groupby 的结果上):对每个组的前三个元素进行排序。

    从第一个groupby的结果开始:

    In [60]: df_agg = df.groupby(['job','source']).agg({'count':sum})
    

    我们按第一级索引分组:

    In [63]: g = df_agg['count'].groupby('job', group_keys=False)
    

    然后我们要对每个组进行排序('order')并取前三个元素:

    In [64]: res = g.apply(lambda x: x.sort_values(ascending=False).head(3))
    

    但是,为此,有一个快捷功能可以做到这一点,nlargest

    In [65]: g.nlargest(3)
    Out[65]:
    job     source
    market  A         5
            D         4
            B         3
    sales   E         7
            C         6
            B         4
    dtype: int64
    

    所以一口气,这看起来像:

    df_agg['count'].groupby('job', group_keys=False).nlargest(3)
    

    【讨论】:

    • 是否有一种方法可以总结每组前三个结果中未包含的所有内容,并将它们添加到每个作业的名为“其他”的源组中?
    • order 已弃用,请改用sort_values
    • 感谢您的出色回答。对于进一步的步骤,是否有一种方法可以根据 groupby 列中的值分配排序顺序?例如,如果值为“买入”,则升序排序;如果值为“卖出”,则降序排序。
    • use as_index=False 创建一个普通的数据框然后正常排序可能更容易。
    • @young_souvlaki 你仍然需要一个 groupby 操作来只取每组的前 3 个,这对于普通排序是不可能的
    【解决方案2】:

    您也可以一次性完成,首先进行排序,然后使用 head 获取每组的前 3 个。

    In[34]: df.sort_values(['job','count'],ascending=False).groupby('job').head(3)
    
    Out[35]: 
       count     job source
    4      7   sales      E
    2      6   sales      C
    1      4   sales      B
    5      5  market      A
    8      4  market      D
    6      3  market      B
    

    【讨论】:

    • groupby 是否保证订单被保留?
    • 看来确实如此;来自the documentation of groupbygroupby 保留每个组内的行顺序
    • toto_tico- 这是正确的,但是在解释该语句时需要小心。单个组内的行顺序被保留,但是 groupby 默认有一个 sort=True 语句,这意味着组本身可能已按键排序。换句话说,如果我的数据框有键(输入)3 2 2 1,.. 按对象分组将按 1 2 3 (排序)的顺序显示 3 个组。使用 sort=False 确保保留组顺序和行顺序。
    • head(3) 给出超过 3 个结果?
    • @Nabin 应用于groupby,它似乎为每个组提供了前 3 行。
    【解决方案3】:

    这是另一个按排序顺序排在前 3 位并在组内排序的示例:

    In [43]: import pandas as pd                                                                                                                                                       
    
    In [44]:  df = pd.DataFrame({"name":["Foo", "Foo", "Baar", "Foo", "Baar", "Foo", "Baar", "Baar"], "count_1":[5,10,12,15,20,25,30,35], "count_2" :[100,150,100,25,250,300,400,500]})
    
    In [45]: df                                                                                                                                                                        
    Out[45]: 
       count_1  count_2  name
    0        5      100   Foo
    1       10      150   Foo
    2       12      100  Baar
    3       15       25   Foo
    4       20      250  Baar
    5       25      300   Foo
    6       30      400  Baar
    7       35      500  Baar
    
    
    ### Top 3 on sorted order:
    In [46]: df.groupby(["name"])["count_1"].nlargest(3)                                                                                                                               
    Out[46]: 
    name   
    Baar  7    35
          6    30
          4    20
    Foo   5    25
          3    15
          1    10
    dtype: int64
    
    
    ### Sorting within groups based on column "count_1":
    In [48]: df.groupby(["name"]).apply(lambda x: x.sort_values(["count_1"], ascending = False)).reset_index(drop=True)
    Out[48]: 
       count_1  count_2  name
    0       35      500  Baar
    1       30      400  Baar
    2       20      250  Baar
    3       12      100  Baar
    4       25      300   Foo
    5       15       25   Foo
    6       10      150   Foo
    7        5      100   Foo
    

    【讨论】:

      【解决方案4】:

      如果您不需要对列求和,请使用@tvashtar 的答案。如果您确实需要求和,那么您可以使用@joris 的答案或与它非常相似的答案。

      df.groupby(['job']).apply(lambda x: (x.groupby('source')
                                            .sum()
                                            .sort_values('count', ascending=False))
                                           .head(3))
      

      【讨论】:

        【解决方案5】:

        试试这个,这是一种简单的 groupby 和降序排序的方法:

        df.groupby(['companyName'])['overallRating'].sum().sort_values(ascending=False).head(20)
        

        【讨论】:

          【解决方案6】:

          你可以在一行中完成 -

          df.groupby(['job']).apply(lambda x: x.sort_values(['count'], ascending=False).head(3)
          .drop('job', axis=1))
          

          apply() 的作用是获取每组 groupby 并将其分配给 lambda 函数中的 x。

          【讨论】:

            【解决方案7】:

            我在没有使用“by”的情况下收到此错误:

            TypeError:sort_values() 缺少 1 个必需的位置参数:'by'

            所以,我把它改成了这个,现在它可以工作了:

            df.groupby(['job','source']).agg({'count':sum}).sort_values(by='count',ascending=False).head(20)
            
            

            【讨论】:

              【解决方案8】:

              @joris 的回答很有帮助。 这对我有用。

              df.groupby(['job'])['count'].nlargest(3)
              

              【讨论】:

                【解决方案9】:

                当分组数据框包含多个分组列时,其他方法会擦除其他列。

                edf = pd.DataFrame({"job":["sales", "sales", "sales", "sales", "sales",
                                           "market", "market", "market", "market", "market"],
                                    "source":["A", "B", "C", "D", "E", "A", "B", "C", "D", "E"],
                                    "count":[2, 4,6,3,7,5,3,2,4,1],
                                    "other_col":[1,2,3,4,56,6,3,4,6,11]})
                
                gdf = edf.groupby(["job", "source"]).agg({"count":sum, "other_col":np.mean})
                gdf.groupby(level=0, group_keys=False).apply(lambda g:g.sort_values("count", ascending=False))
                

                这将保持other_col 以及在每个组中按count 列排序

                【讨论】:

                  猜你喜欢
                  • 2018-07-01
                  • 1970-01-01
                  • 2015-01-17
                  • 2018-11-05
                  • 2020-02-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2023-03-27
                  • 2018-08-29
                  相关资源
                  最近更新 更多