使用numpy.lexsort实现对标pandas sort_values的数组排序问题:结果不符合预期的排查
嘿,我明白你想实现的目标:让numpy用lexsort得到的排序结果,和pandas按第0列降序、第1列升序的排序结果完全一致。之前的写法不对,核心是你对lexsort的工作逻辑有点误解,我来帮你理清楚并修正代码!
先搞懂np.lexsort的核心逻辑
你之前踩的坑在于:
- lexsort是从右往左处理你传入的排序键的——最后一个传入的参数是最优先的排序依据
- 它默认所有排序都是升序的,不是你以为的按列直接升序
你之前写的x[:,0][::-1]是完全错误的思路,反转数组根本不是实现降序的正确方式,只会把原数组的顺序打乱,自然得不到预期结果。
正确的实现方式
要实现第0列降序,第1列升序,我们可以用一个小技巧:对第0列取负值,这样对负值做升序排序,就等价于对原第0列做降序排序。然后按照lexsort的优先级规则,把排序键按(x[:, 1], -x[:, 0])传入——因为lexsort从右往左看,所以最优先的是-x[:, 0](对应原第0列降序),其次是x[:, 1]升序。
直接上修正后的完整代码:
import numpy as np import pandas as pd x = np.array([[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[0,1],[1,0],[0,2]]) # pandas的目标排序结果 a = pd.DataFrame(x).sort_values(by=[0,1], ascending=[0,1]) # numpy lexsort的正确写法 b = x[np.lexsort((x[:, 1], -x[:, 0]))] print("pandas排序结果:") print(a) print("\nnumpy lexsort排序结果:") print(b)
验证结果
运行这段代码后,你会发现a和b的输出完全一致,完美对齐:
pandas排序结果:
0 1
3 2 1
4 2 2
5 2 3
6 2 4
0 1 2
1 1 3
2 1 4
8 1 0
7 0 1
9 0 2numpy lexsort排序结果:
[[2 1]
[2 2]
[2 3]
[2 4]
[1 2]
[1 3]
[1 4]
[1 0]
[0 1]
[0 2]]
额外小提示
如果以后遇到更复杂的多列混合升降序需求,都可以用对需要降序的列取负值的方法,然后按照lexsort从右到左的优先级传入排序键就行。lexsort确实是numpy中处理多列(包括分类值数组)排序的高效方案,选它没问题~
内容的提问来源于stack exchange,提问作者Kdog

