【问题标题】:DataFrame sorting based on a function of multiple column values基于多列值函数的DataFrame排序
【发布时间】:2016-12-04 09:47:00
【问题描述】:

基于python, sort descending dataframe with pandas:

给定:

from pandas import DataFrame
import pandas as pd

d = {'x':[2,3,1,4,5],
     'y':[5,4,3,2,1],
     'letter':['a','a','b','b','c']}

df = DataFrame(d)

df 然后看起来像这样:

df:
      letter    x    y
    0      a    2    5
    1      a    3    4
    2      b    1    3
    3      b    4    2
    4      c    5    1

我想要类似的东西:

f = lambda x,y: x**2 + y**2
test = df.sort(f('x', 'y'))

这应该根据列 'x' 和 'y' 的平方值之和对完整的数据框进行排序,并给我:

test:
      letter    x    y
    2      b    1    3
    3      b    4    2
    1      a    3    4
    4      c    5    1
    0      a    2    5

升序或降序无关紧要。有没有一种简单的方法可以做到这一点?我还没有找到解决办法。

【问题讨论】:

    标签: python sorting pandas dataframe


    【解决方案1】:
    df.loc[(df.x ** 2 + df.y ** 2).sort_values().index]
    

    How to sort pandas dataframe by custom order on string index之后

    【讨论】:

    • 谢谢,这是一个非常好的解决方案!排序数据的索引与 iloc 结合使用。这很整洁。不需要其他列。
    • 这确实看起来是正确的方法,另一方面,您应该使用 .loc 而不是 .iloc 因为这不适用于大多数索引(它只适用于像 @987654326 这样的索引@. 以防万一,我会添加一个替代方案。
    • There 使用 ilocargsort 这与此策略非常相似。
    【解决方案2】:

    另一种类似于this one 的方法是使用argsort,它直接返回索引排列:

    f = lambda r: r.x**2 + r.y**2
    df.iloc[df.apply(f, axis=1).argsort()]
    

    我认为使用argsort 比常规的sort 能更好地翻译这个想法(我们不关心这个计算的值,只关心结果索引)。

    修补 DataFrame 以添加此功能也可能很有趣:

    def apply_sort(self, *, key):
        return self.iloc[self.apply(key, axis=1).argsort()]
    
    pd.DataFrame.apply_sort = apply_sort
    

    然后我们可以简单地写:

    >>> df.apply_sort(key=f)
    
       x  y letter
    2  1  3      b
    3  4  2      b
    1  3  4      a
    4  5  1      c
    0  2  5      a
    

    【讨论】:

    • 既然您在这里进行了逐行应用,与 andrewkittredge 的方法相比,这不会在任何矢量化操作上交易相当多的性能吗? sort 与 argsort 是否抵消了这些担忧?
    【解决方案3】:

    您是否尝试过创建一个新列然后对其进行排序。我无法对原始帖子发表评论,所以我只是发布我的解决方案。

    df['c'] = df.a**2 + df.b**2
    df = df.sort_values('c')
    

    【讨论】:

    • 这个解决方案的“问题”是它实际上创建了另一个列,这不是这里的确切目标(输入和输出列应该相同)。
    【解决方案4】:
    from pandas import DataFrame
    import pandas as pd
    
    d = {'one':[2,3,1,4,5],
         'two':[5,4,3,2,1],
         'letter':['a','a','b','b','c']}
    
    df = pd.DataFrame(d)
    
    #f = lambda x,y: x**2 + y**2
    array = []
    for i in range(5):
        array.append(df.ix[i,1]**2 + df.ix[i,2]**2)
    array = pd.DataFrame(array, columns = ['Sum of Squares'])
    test = pd.concat([df,array],axis = 1, join = 'inner')
    test = test.sort_index(by = "Sum of Squares", ascending = True).drop('Sum of Squares',axis =1)
    

    刚刚意识到你想要这个:

        letter  one  two
    2      b    1    3
    3      b    4    2
    1      a    3    4
    4      c    5    1
    0      a    2    5
    

    【讨论】:

      【解决方案5】:

      您可以创建一个临时列以在排序中使用,然后将其删除:

      df.assign(f = df['one']**2 + df['two']**2).sort_values('f').drop('f', axis=1)
      Out: 
        letter  one  two
      2      b    1    3
      3      b    4    2
      1      a    3    4
      4      c    5    1
      0      a    2    5
      

      【讨论】:

      • 这似乎是最好的方法,但它有点糟糕......将 lambda 函数传递给sort_values 会更优雅,就像你这样做一样python原生的sorted()调用
      • @AlexSpangher,看来我们目前尚不支持此功能,2020 年 2 月 :-(
      • python的优点是当它不存在的时候你可以直接add the method
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-08
      • 1970-01-01
      • 2018-02-14
      • 2020-10-16
      • 2021-04-22
      • 2021-05-19
      相关资源
      最近更新 更多