如何对 Pandas 数据框进行条件排序(即根据另一列中的值在一列中进行升序和降序排列)?

Fel*_* D. 5 python sorting dataframe pandas

是否可以对 Pandas DataFrame 的行相对于多个列进行排序,并将列中的某些行按升序放置,而其他行(同一列内)按降序放置?这是我正在寻找的一个可重复的小例子:

设置

import pandas as pd

df = pd.DataFrame(data={'class':['A','A','A','B','B','B','C','C','C'],
                        'val':[20,10,15,55, 75, 71,3,1,2],
                        'sub':['a','c','b','b','a','c','c','a','b']})

print(df)
# This is the original unsorted DataFrame
#  class  val sub
#0     A   20   a
#1     A   10   c
#2     A   15   b
#3     B   55   b
#4     B   75   a
#5     B   71   c
#6     C    3   c
#7     C    1   a
#8     C    2   b

Run Code Online (Sandbox Code Playgroud)

如何df根据以下“规则”对上面的 DataFrame 对象进行排序?

  • 第一优先级:根据“类别”列按字母升序排序
  • 第二优先级:然后,在“class”列的每个唯一值中,根据“val”列对行进行排序,如下所示:
    • 对于“class”==“A”的行,按升序对“val”值进行排序
    • 对于“class”==“B”的行,按降序对“val”值进行排序
    • 对于“class”==“C”的行,按升序对“val”值进行排序

从更实际的角度来说,我正在寻找的结果如下所示:

# This is the sorted DataFrame that I'm trying to get
#  class  val sub
#1     A   10   c
#2     A   15   b
#0     A   20   a
#4     B   75   a
#5     B   71   c
#3     B   55   b
#7     C    1   a
#8     C    2   b
#6     C    3   c
Run Code Online (Sandbox Code Playgroud)

有没有直接的方法来做到这一点?

我的尝试

在尝试解决这个问题时,我创建了一个额外的“排序”列并操纵其中的值,使它们在数字上都遵循升序。

df['val_temp'] = df.apply(lambda x: x['val'] if x['class'] in ['A','C'] else -x['val'], axis=1)

df.sort_values(by=['class','val_temp'], ascending=[True,True]).drop(columns='val_temp')
Run Code Online (Sandbox Code Playgroud)

问题是这个解决方法看起来真的很脏并且不适用于非数字值。例如,如果我想在列上进行第二优先级排序"sub",我不知道如何继续。

Pandas 是否提供了一个接口来执行此操作,还是我只需要依赖像上面这样的“肮脏”解决方法?

聚苯乙烯

我看过这个线程这个线程string,但它们只提供了一种基于数学的解决方法,就像我上面所做的那样,当我们需要对像这样的列进行排序时,它不起作用df["sub"]

moz*_*way 5

您可以使用GroupBy.apply字典来映射每个组的排序顺序:

order = {'A': True, 'B': False, 'C': True}

(df.groupby('class', group_keys=False)
   .apply(lambda s: s.sort_values(by='val', ascending=order[s.name]))
 )
Run Code Online (Sandbox Code Playgroud)

注意。groupby默认情况下对组进行排序,因此隐式对“类”进行排序

输出:

  class  val sub
1     A   10   c
2     A   15   b
0     A   20   a
4     B   75   a
5     B   71   c
3     B   55   b
7     C    1   a
8     C    2   b
6     C    3   c
Run Code Online (Sandbox Code Playgroud)