按列对NumPy中的数组进行排序

295 python arrays sorting numpy scipy

如何在第n列中对NumPy中的数组进行排序?

例如,

a = array([[9, 2, 3],
           [4, 5, 6],
           [7, 0, 5]])
Run Code Online (Sandbox Code Playgroud)

我想按第二列对行进行排序,以便我回来:

array([[7, 0, 5],
       [9, 2, 3],
       [4, 5, 6]])
Run Code Online (Sandbox Code Playgroud)

Ste*_*joa 657

我认为这有效: a[a[:,1].argsort()]

这表示第二列,a并根据它进行排序.

  • 如果你想要反向排序,修改它为`a [a [:,1] .argsort()[:: - 1]]` (51认同)
  • `[:,1]`表示`a`的第二列. (26认同)
  • 我发现这更容易阅读:`ind = np.argsort(a [:,1]); a = a [ind]` (10认同)
  • 这还不清楚,这里的“ 1”是什么?索引排序依据? (2认同)
  • a[a[:,k].argsort()] 与 a[a[:,k].argsort(),:] 相同。这推广到另一个维度(使用一行对 cols 进行排序): a[:,a[j,:].argsort()] (希望我输入正确。) (2认同)
  • 需要使用 b = a[a[:, 1].argsort()] 那么 b 是排序后的 (2认同)

Joe*_*ton 125

@steve实际上是最优雅的做法.

对于"正确"方式,请参阅numpy.ndarray.sort的order关键字参数

但是,您需要将数组视为带有字段的数组(结构化数组).

如果你最初没有用字段定义你的数组,那么"正确"的方式是非常难看的......

作为一个简单的例子,要对它进行排序并返回一个副本:

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]])
Run Code Online (Sandbox Code Playgroud)

要就地排序:

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]])
Run Code Online (Sandbox Code Playgroud)

据我所知,@ Steve真的是最优雅的做法...

此方法的唯一优点是"order"参数是用于对搜索进行排序的字段列表.例如,您可以按第二列,然后是第三列,然后通过提供order = ['f1','f2','f0']排序第一列.

  • Would it make sense to file a feature request that the "correct" way be made less ugly? (8认同)
  • 这种方法相对于史蒂夫的一个主要优点是它允许非常大的数组进行分类.对于一个足够大的数组,`np.argsort`返回的索引可能会占用相当多的内存,而且最重要的是,使用数组进行索引也会生成正在排序的数组的副本. (8认同)
  • 有人能解释一下“i8,i8,i8”吗?这是针对每一列还是每一行?如果对不同的数据类型进行排序应该改变什么?如何查明正在使用多少位?谢谢 (4认同)
  • 在我的numpy 1.6.1rc1中,它引发了`ValueError:与数组不兼容的新类型 (3认同)
  • 如果数组中的值是"float"怎么办?我该改变什么吗? (2认同)

J.J*_*J.J 28

您可以按照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')]
Run Code Online (Sandbox Code Playgroud)

这按列0排序,然后是1,然后是2.

  • 好问题 - 稳定意味着当你有一个平局时你维持原始顺序,并且未分类文件的原始顺序是无关紧要的. (8认同)
  • 为什么First Sort不需要稳定? (4认同)

小智 19

Python文档维基,我认为你可以做到:

a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]); 
a = sorted(a, key=lambda a_entry: a_entry[1]) 
print a
Run Code Online (Sandbox Code Playgroud)

输出是:

[[[0, 0, 1], [1, 2, 3], [4, 5, 6]]]
Run Code Online (Sandbox Code Playgroud)

  • 使用此解决方案,可以获得列表而不是NumPy数组,因此这可能并不总是方便(占用更多内存,可能更慢等). (18认同)

prl*_*900 17

如果有人想在其程序的关键部分使用排序,则可以对不同的建议进行性能比较:

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
Run Code Online (Sandbox Code Playgroud)

因此,看起来使用argsort进行索引是迄今为止最快的方法...


fgr*_*egg 16

NumPy邮件列表中,这是另一个解决方案:

>>> 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]])
Run Code Online (Sandbox Code Playgroud)

  • 正确的概括是“ a [np.lexsort(aT [cols])]”。原始问题中的cols = [1]。 (2认同)

xum*_*202 6

我有一个类似的问题。

我的问题:

我想计算一个 SVD 并且需要按降序对我的特征值进行排序。但我想保留特征值和特征向量之间的映射。我的特征值在第一行,对应的特征向量在它下面的同一列中。

所以我想按降序按第一行对二维数组进行列排序。

我的解决方案

a = a[::, a[0,].argsort()[::-1]]
Run Code Online (Sandbox Code Playgroud)

那么这是如何工作的呢?

a[0,] 只是我想排序的第一行。

现在我使用 argsort 来获取索引的顺序。

我使用[::-1]是因为我需要降序。

最后,我使用a[::, ...]以正确顺序获取列的视图。