如何在NumPy中按第n列对数组进行排序?
比如说。
a = array([[9, 2, 3],
[4, 5, 6],
[7, 0, 5]])
我想按第二列对行进行排序,这样我就能得到回报。
array([[7, 0, 5],
[9, 2, 3],
[4, 5, 6]])
我想这是可行的。a[a[:,1].argsort()]
。
这表明了a
的第二列,并根据它进行相应的排序。
@steve's实际上是最优雅的做法。
关于正确的方法,请看numpy.ndarray.sort的顺序关键字参数。
然而,你需要把你的数组看作是一个有字段的数组(一个结构化数组)。
如果你最初没有用字段来定义你的数组,那么正确的方法就很难看了......
举个简单的例子,对它进行排序并返回一个副本。
In [1]: import numpy as np
In [2]: a = np.array([[1,2,3],[4,5,6],[0,0,1]])
In [3]: np.sort(a.view('i8,i8,i8'), order=['f1'], axis=0).view(np.int)
Out[3]:
array([[0, 0, 1],
[1, 2, 3],
[4, 5, 6]])
要对其进行原地排序。
In [6]: a.view('i8,i8,i8').sort(order=['f1'], axis=0) #<-- returns None
In [7]: a
Out[7]:
array([[0, 0, 1],
[1, 2, 3],
[4, 5, 6]])
据我所知,@Steve'的做法确实是最优雅的方式。
这种方法的唯一优点是,"order"参数是一个要对搜索进行排序的字段的列表。例如,你可以通过提供order=['f1','f2','f0'],按第二列排序,然后是第三列,最后是第一列。
你可以按照Steve Tjoa'的方法对多列进行排序,使用像mergesort这样稳定的排序方式,并将索引从最不重要的列排序到最重要的列。
a = a[a[:,2].argsort()] # First sort doesn't need to be stable.
a = a[a[:,1].argsort(kind='mergesort')]
a = a[a[:,0].argsort(kind='mergesort')]
这是按第0列,然后是第1列,然后是第2列进行排序。
从Python文档wiki中,我认为你可以做到。
a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]);
a = sorted(a, key=lambda a_entry: a_entry[1])
print a
输出结果是。
[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]
如果有人想在程序的关键部分使用排序,这里是不同建议的性能比较。
import numpy as np
table = np.random.rand(5000, 10)
%timeit table.view('f8,f8,f8,f8,f8,f8,f8,f8,f8,f8').sort(order=['f9'], axis=0)
1000 loops, best of 3: 1.88 ms per loop
%timeit table[table[:,9].argsort()]
10000 loops, best of 3: 180 µs per loop
import pandas as pd
df = pd.DataFrame(table)
%timeit df.sort_values(9, ascending=True)
1000 loops, best of 3: 400 µs per loop
所以,看起来用[argsort][1]来做索引是目前最快捷的方法...
[1]: http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.argsort.html
来自 [NumPy 邮件列表][1],这里有另一个解决方案。
>>> a
array([[1, 2],
[0, 0],
[1, 0],
[0, 2],
[2, 1],
[1, 0],
[1, 0],
[0, 0],
[1, 0],
[2, 2]])
>>> a[np.lexsort(np.fliplr(a).T)]
array([[0, 0],
[0, 0],
[0, 2],
[1, 0],
[1, 0],
[1, 0],
[1, 0],
[1, 2],
[2, 1],
[2, 2]])
[1]: http://mail.scipy.org/pipermail/numpy-discussion/2008-December/039332.html
我也有类似的问题。
我的问题:
我想计算一个SVD,需要将[特征值][1]按降序排列。 但我想保持特征值和特征向量之间的映射。 我的特征值在第一行,下面对应的特征向量在同一列。
所以我想把一个二维数组按第一行降序逐列排序。
我的解决方案
a = a[::, a[0,].argsort()[::-1]]
那么,这该如何操作呢?
a[0,]
只是我想排序的第一行。
现在我使用argsort来获取索引的顺序。
我使用[::-1]
因为我需要降序。
最后,我使用a[::, ...]
来获得一个视图,其中的列的顺序是正确的。
[1]: https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors
一个稍微复杂一点的lexsort
例子--在第1列上降序,其次在第2列上升序。
lexsort
的诀窍是,它以行为单位进行排序(因此有.T
),并且优先考虑最后一列。
In [120]: b=np.array([[1,2,1],[3,1,2],[1,1,3],[2,3,4],[3,2,5],[2,1,6]])
In [121]: b
Out[121]:
array([[1, 2, 1],
[3, 1, 2],
[1, 1, 3],
[2, 3, 4],
[3, 2, 5],
[2, 1, 6]])
In [122]: b[np.lexsort(([1,-1]*b[:,[1,0]]).T)]
Out[122]:
array([[3, 1, 2],
[3, 2, 5],
[2, 1, 6],
[2, 3, 4],
[1, 1, 3],
[1, 2, 1]])
下面是考虑到所有列的另一种解决方案([J.J][1]'的答案的更紧凑的方式)。
ar=np.array([[0, 0, 0, 1],
[1, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 1],
[0, 0, 1, 0],
[1, 1, 0, 0]])
用词典排序。
ar[np.lexsort(([ar[:, i] for i in range(ar.shape[1]-1, -1, -1)]))]
产出:
array([[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0]])