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 对象进行排序?
从更实际的角度来说,我正在寻找的结果如下所示:
# 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"]。
您可以使用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)