基于多列对 DataFrame 进行排名

Rank DataFrame based on multiple columns

如何根据 2 列对 DataFrame 进行排名?

在下面的示例中,col_b 将成为 col_a 的决胜局。

DataFrame:

df = pd.DataFrame({'col_a':[0,0,0,1,1,1], 'col_b':[5,2,8,3,7,4]})

df
   col_a  col_b
0      0      5
1      0      2
2      0      8
3      1      3
4      1      7
5      1      4

预期输出:

   col_a  col_b  Rank
0      0      5   2
1      0      2   1
2      0      8   3
3      1      3   4
4      1      7   6
5      1      4   5

找到我自己的解决方案:创建一个包含列的元组并对其进行排序。 不会处理不同的 ascending/descending 顺序,但这对我的问题有好处。

df['rank'] = df[['col_a','col_b']].apply(tuple, 1).rank()

这是一种方法。通过对列和 re-indexing 进行排序来创建临时 DataFrame。然后用新的index作为rank,加入回原来的df。

temp_df = df.sort_values(['col_a', 'col_b']).reset_index()
temp_df['rank'] = temp_df.index + 1
print(temp_df)
#   index  col_a  col_b  rank
#0      1      0      2     1
#1      0      0      5     2
#2      2      0      8     3
#3      3      1      3     4
#4      5      1      4     5
#5      4      1      7     6

'index'对应于原始DataFrame中的索引。使用它可以将 temp_df 连接回 df 和 select 您想要的列:

df = df.join(temp_df.set_index('index'), rsuffix="_r")[['col_a', 'col_b', 'rank']]
print(df)
#   col_a  col_b  rank
#0      0      5     2
#1      0      2     1
#2      0      8     3
#3      1      3     4
#4      1      7     6
#5      1      4     5

这是一个 one-line 使用 sort_values 的方法:

In [135]: df['rank'] = df.sort_values(['col_a', 'col_b'])['col_b'].index + 1

In [136]: df
Out[136]: 
   col_a  col_b  rank
0      0      5     2
1      0      2     1
2      0      8     3
3      1      3     4
4      1      7     6
5      1      4     5

此代码段背后的逻辑:基本上,DataFrame.sort_values 函数接受多个列名和 returns 基于传递的列名顺序的数据框的排序副本。默认的排序顺序是 ascending 这就是我们想要的。如果你想要另一个订单,你可以将订单作为布尔值的可迭代传递给 ascending 关键字参数。最后 column_b 的新索引就是我们想要的(加一)。

使用numpyargsort方法。

df = pd.DataFrame({'col_a':[0,0,0,1,1,1], 'col_b':[5,2,8,3,7,4]})
df["rank"] = np.argsort(
              df.values.copy().view(dtype=[('x', int), ('y', int)]).flatten(),  
              order=("x","y")
             ) + 1


    col_a   col_b   rank
0   0        5       2
1   0        2       1
2   0        8       3
3   1        3       4
4   1        7       6
5   1        4       5