基于多列对 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
的新索引就是我们想要的(加一)。
使用numpy
的argsort
方法。
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
如何根据 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
的新索引就是我们想要的(加一)。
使用numpy
的argsort
方法。
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