按绝对值排序而不改变数据

65

我希望能够找到一种简单的方法,按照特定列的绝对值对Pandas数据框进行排序,但实际上不改变数据框中的任何值。类似于 sorted(df, key=abs)。因此,如果我有一个数据框如下:

    a   b
0   1   -3
1   2   5 
2   3   -1
3   4   2
4   5   -9

按'b'排序时得到的已排序数据如下:

    a   b
2   3   -1
3   4   2
0   1   -3
1   2   5 
4   5   -9
4个回答

72

使用Pandas >= V_1.1.0的完美简单解决方案:

sort_values()函数中使用参数key

import pandas as pd
df = pd.DataFrame({'A': ['a', 'b', 'c', 'd', 'e', 'f'], 'B': [-3, -2, -1, 0, 1, 2]})

df.sort_values(by='B', key=abs)

会产生:

    A   B
3   d   0
2   c   -1
4   e   1
1   b   -2
5   f   2
0   a   -3

3
直到看到这个答案,我才注意到key关键字参数! - Shan Dou
ttt.sort_values(by='B', key=pd.Series.abs) 也能工作,或许在较旧的 Pandas 版本中也是如此? - Cactus Philosopher
@CactusPhilosopher:不确定旧版本是否支持,因为根据文档key参数是“在1.1.0版本中新增的”,该版本于2020年7月28日发布。 - Lucecpkn
一个附加问题:如果我想按多列排序,并且只对其中一列使用abs()进行排序,我该如何修改这段代码使其工作? - Bowen Liu
@BowenLiu:我只能想到另一种方法: df['B_abs'] = df['B'].abs() 然后 df.sort_values(['B_abs', 'A']) - Lucecpkn

69

更新

自从0.17.0版本以来,ordersort已被弃用(感谢 @Ruggero Turra),现在您可以使用sort_values来实现这一功能:

In[16]:

df.reindex(df.b.abs().sort_values().index)
Out[16]: 
   a  b
2  3 -1
3  4  2
0  1 -3
1  2  5
4  5 -9

我希望看到这个程序可以跨多个索引执行此操作,例如,如果index1可以是“水果”或“蔬菜”,index2是任何水果或蔬菜,值是该项目的总花费,则可以按食品类型(index1)的成本绝对值排序数据框,然后再按每种水果或蔬菜的成本进行内部排序。 - HaPsantran
10
对于所有在这里搜索最大绝对值的值的人,请将代码更改为:df.reindex(df.b.abs().sort_values(ascending=False).index) - PV8
一个附加问题:如果我想按多列排序,并且只对其中一列使用abs()进行排序,我该如何修改这段代码使其工作? - Bowen Liu

18

朝着更符合习惯的pandas方向:使用argsort

一个更简洁的方法是在绝对值上调用Series.argsort,然后进行索引:

df.iloc[df['b'].abs().argsort()]

   a  b
2  3 -1
3  4  2
0  1 -3
1  2  5
4  5 -9

如果您需要重置索引,请使用Series.reset_index

df.iloc[df['b'].abs().argsort()].reset_index(drop=True)

   a  b
0  3 -1
1  4  2
2  1 -3
3  2  5
4  5 -9

最后,由于argsort没有ascending参数指定升序/降序,因此需要对df['b'].abs()进行取反以按降序排序。
df.iloc[(-df['b'].abs()).argsort()]

   a  b
4  5 -9
1  2  5
0  1 -3
3  4  2
2  3 -1

你也可以使用NumPy来完成这个任务——使用np.absndarray.argsort
df.iloc[np.abs(df['b'].values).argsort()]

   a  b
2  3 -1
3  4  2
0  1 -3
1  2  5
4  5 -9

或者,对于降序排序:
df.iloc[(-np.abs(df['b'].values)).argsort()]

   a  b
4  5 -9
1  2  5
0  1 -3
3  4  2
2  3 -1

0

对于系列数据:

series_name.sort_values(key=abs)

然后将其与数据框相结合:

df.reindex(series_name.sort_values(key=abs).index)

这如何补充现有的答案? - C8H10N4O2
@C8H10N4O2 而不是考虑整个数据框,只需对数据框的目标序列 / 列进行排序,然后相应地重新索引其余列即可。 - abir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接