【问题标题】:Sort pandas dataframe both on values of a column and index?根据列值和索引对熊猫数据框进行排序?
【发布时间】:2013-12-15 03:42:14
【问题描述】:

是否可以按列的值和索引对 pandas 数据帧进行排序?

如果您按列的值对 pandas 数据框进行排序,则可以得到按列排序的结果数据框,但不幸的是,您会看到数据框的索引顺序在排序列的相同值内变得混乱。

那么,我是否可以按列对数据框进行排序,例如名为count 的列,但也可以按索引值对其进行排序?是否也可以按降序对列进行排序,而按升序对索引进行排序?

我知道如何对数据框中的多个列进行排序,也知道我可以通过首先reset_index() 索引并对其进行排序,然后再次创建索引来实现我在此提出的要求。但这是不是更直观、更有效的方式呢?

【问题讨论】:

    标签: python pandas sorting dataframe


    【解决方案1】:

    Pandas 0.23 终于把你带到了那里:-D

    您现在可以将索引名称(而不仅仅是列名称)作为参数传递给sort_values。所以,这个单行代码有效:

    df = df.sort_values(by = ['MyCol', 'MyIdx'], ascending = [False, True])
    

    如果您的索引当前未命名:

    df = df.rename_axis('MyIdx').sort_values(by = ['MyCol', 'MyIdx'], ascending = [False, True])
    

    【讨论】:

    • 很好,绝对是最灵活的答案,应该成为推荐的方法。
    • 确保您的索引有一个名称df.index.name
    【解决方案2】:

    在 pandas 0.23+ 中您可以直接执行 - 请参阅 OmerB 的 answer如果您还没有 0.23+,请继续阅读。


    我敢冒险,最简单的方法是将索引复制到一列,然后按两者排序。

    df['colFromIndex'] = df.index
    df = df.sort(['count', 'colFromIndex'])
    

    我也希望能够只做类似df.sort(['count', 'index']) 的事情,但这当然行不通。

    【讨论】:

    • 奇怪,当我尝试这个时,它仍然只对“count”列而不是“colFromIndex”列进行排序......
    • 注意:排序已被弃用。 sort_values 现在正在使用中。
    • 从 pandas 0.23 开始,现在可以像df.sort(['count', 'index']) 那样做。请参阅下面的answer
    • @OmerB 这仍然不起作用。我得到了与 durbachit 相同的结果 - 我只看到在一列上完成了排序,而第二列被忽略了。
    • @ragzputin - 您尝试了哪种方法?注意这个问题有两个答案,我的需要 Pandas 0.23 或更高版本。
    【解决方案3】:

    从熊猫版本 0.22 开始。

    您可以暂时将该列设置为索引,对该列的索引进行排序然后重置。默认会保持现有索引的顺序:

    df = df.set_index('column_name', append=True).sort_index(level=1).reset_index(level=1)
    

    我认为上述内容可以使用“就地”选项完成,但我认为如上所述更容易阅读。

    【讨论】:

    • 好主意,除了我不知道这种方法是否允许多个索引的不同排序顺序。
    【解决方案4】:

    您可以在 sort_index 中使用升序参数,但您必须将其作为列表传递,它才能从 pandas 0.22.0 开始正常工作。

    import pandas as pd
    import numpy as np
    df = pd.DataFrame({'idx_0':[2]*6+[1]*5,
                       'idx_1':[6,4,2,10,18,5,11,1,7,9,3],
                       'value_1':np.arange(11,0,-1),
                       'MyName':list('SORTEDFRAME')})
    
    df = df.set_index(['idx_0','idx_1'])
    df
    

    输出:

                MyName  value_1
    idx_0 idx_1                
    2     6          S       11
          4          O       10
          2          R        9
          10         T        8
          18         E        7
          5          D        6
    1     11         F        5
          1          R        4
          7          A        3
          9          M        2
          3          E        1
    

    按值和索引排序应该得到“FRAMESORTED”而不是“SORTEDFRAME”

    df.sort_values('value_1', ascending=False)\
      .sort_index(level=0, ascending=[True])
    

    输出:

                MyName  value_1
    idx_0 idx_1                
    1     11         F        5
          1          R        4
          7          A        3
          9          M        2
          3          E        1
    2     6          S       11
          4          O       10
          2          R        9
          10         T        8
          18         E        7
          5          D        6
    

    请注意,您必须将sort_index 中的ascending 参数作为列表而不是标量传递。它不会起作用。

    【讨论】:

      【解决方案5】:

      要对列进行降序排序,同时保持索引升序:

      import pandas as pd
      df = pd.DataFrame(index=range(5), data={'c': [4,2,2,4,2]})
      df.index = df.index[::-1]
      print df.sort(column='c', ascending=False)
      

      输出:

         c
      1  4
      4  4
      0  2
      2  2
      3  2
      

      【讨论】:

      • 谢谢。但随后它会导致索引的破坏,在某些情况下我可能不喜欢它,因此仍然更喜欢reset_index()...不过感谢您的回答。
      • “破坏索引”是什么意思?
      • 这将破坏多指数。您可以在docs 中的多索引示例之一上尝试此操作。我会发布代码,但它基本上无法作为评论阅读。
      【解决方案6】:

      您可以使用 groupby 和 apply 的组合:

      In [2]: df = pd.DataFrame({
                  'transID':  range(8),
                  'Location': ['New York','Chicago','New York','New York','Atlanta','Los Angeles',
                                  'Chicago','Atlanta'],
                  'Sales':    np.random.randint(0,10000,8)}).set_index('transID')
      In [3]: df
      Out[3]:
              Location    Sales
      transID
      0       New York    1082
      1       Chicago     1664
      2       New York    692
      3       New York    5669
      4       Atlanta     7715
      5       Los Angeles 987
      6       Chicago     4085
      7       Atlanta     2927
      
      In [4]: df.groupby('Location').apply(lambda d: d.sort()).reset_index('Location',drop=True)
      Out[4]:
              Location    Sales
      transID
      4       Atlanta     7715
      7       Atlanta     2927
      1       Chicago     1664
      6       Chicago     4085
      5       Los Angeles 987
      0       New York    1082
      2       New York    692
      3       New York    5669
      

      我将“位置”放在最后一行,因为 groupby 将分组级别插入索引中的第一个位置。排序然后删除它们会保留排序顺序。

      【讨论】:

        【解决方案7】:

        我相信即使应用了sort_index,来自sort_values 的原始订单也会保留,所以这应该有效:

        df.sort_values('count', ascending=False).sort_index(level=[index_level1, index_level2])
        

        【讨论】:

        • 这个我试过了,不是保留原来的顺序。
        猜你喜欢
        • 2017-01-12
        • 2014-12-29
        • 1970-01-01
        • 2015-11-06
        • 2021-07-03
        • 2022-07-19
        • 1970-01-01
        • 2021-11-02
        • 2021-10-07
        相关资源
        最近更新 更多