ChatGPT解决这个技术问题 Extra ChatGPT

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

如何按第 n 列对 NumPy 数组进行排序?

例如,给定:

a = array([[9, 2, 3],
           [4, 5, 6],
           [7, 0, 5]])

我想按第二列对 a 的行进行排序以获得:

array([[7, 0, 5],
       [9, 2, 3],
       [4, 5, 6]])
这是一个非常糟糕的例子,因为 np.sort(a, axis=0) 对于给定矩阵来说是一个令人满意的解决方案。我建议用一个更好的例子进行编辑,但被拒绝了,尽管实际上这个问题会更清楚。该示例应类似于 a = numpy.array([[1, 2, 3], [6, 5, 2], [3, 1, 1]]) 并具有所需的输出 array([[3, 1, 1], [1, 2, 3], [6, 5, 2]])
大卫,你没有明白问题的重点。他希望保持每行中的顺序相同。
@marcorossi我确实明白了这一点,但是该示例的表述非常糟糕,因为正如我所说,有多个可能的答案(但是,这些答案不会满足OP的要求)。后来根据我的评论进行的编辑确实已获得批准(但有趣的是,我的评论被拒绝了)。所以现在一切都很好。
我认为使用结构化数组可能是使代码更具可读性的一种方法。我在这里附上了一个可能的答案:stackoverflow.com/a/67788660/13890678

M
Mateen Ulhaq

a 的第二列排序:

a[a[:, 1].argsort()]

这个不清楚,这里的1是什么?要排序的索引?
[:,1] 表示 a 的第二列。
如果您想要反向排序,请将其修改为 a[a[:,1].argsort()[::-1]]
我觉得这更容易阅读:ind = np.argsort( a[:,1] ); a = a[ind]
a[a[:,k].argsort()] 与 a[a[:,k].argsort(),:] 相同。这推广到另一个维度(使用一行对列进行排序):a[:,a[j,:].argsort()](希望我输入正确。)
T
Trenton McKinney

@steveanswer 实际上是最优雅的方式。

对于“正确”的方式,请参见 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]])

就地排序:

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'] 按第二列、第三列、第一列排序。


在我的 numpy 1.6.1rc1 中,它引发了 ValueError: new type not compatible with array.
提交功能请求以使“正确”方式变得不那么丑陋是否有意义?
如果数组中的值为 float 怎么办?我应该改变什么吗?
与史蒂夫的方法相比,这种方法的一个主要优点是它允许对非常大的数组进行就地排序。对于足够大的数组,np.argsort 返回的索引本身可能会占用大量内存,最重要的是,使用数组进行索引还会生成正在排序的数组的副本。
有人可以解释'i8,i8,i8'吗?这是针对每一列还是每一行?如果对不同的 dtype 进行排序,应该改变什么?如何找出正在使用的位数?谢谢
J
J.J

您可以按照 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。


为什么 First Sort 不需要是稳定的?
好问题 - 稳定意味着当出现平局时,您保持原始顺序,而未排序文件的原始顺序无关紧要。
这似乎是一个非常重要的观点。有一个默默地不排序的列表会很糟糕。
p
prl900

如果有人想在他们程序的关键部分使用排序,这里是不同提案的性能比较:

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 进行索引是迄今为止最快的方法......


M
Mateen Ulhaq

正如 the Python documentation 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]]]

使用此解决方案,可以获得一个列表而不是 NumPy 数组,因此这可能并不总是很方便(占用更多内存,可能更慢等)。
这个“解决方案”比最受支持的答案慢了一倍......好吧,实际上接近无穷大
@Jivan 实际上,这个解决方案比最受欢迎的答案快 5 倍imgur.com/a/IbqtPBL
P
Peter Mortensen

the NumPy mailing list 中,还有另一个解决方案:

>>> 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]])

正确的概括是a[np.lexsort(a.T[cols])]。其中 cols=[1] 在原始问题中。
P
Peter Mortensen

我有一个类似的问题。

我的问题:

我想计算 SVD,需要按降序对我的 eigenvalues 进行排序。但我想保留特征值和特征向量之间的映射。我的特征值位于第一行,其下方的相应特征向量位于同一列中。

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

我的解决方案

a = a[::, a[0,].argsort()[::-1]]

那么这是如何工作的呢?

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

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

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

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


D
David Buck
import numpy as np
a=np.array([[21,20,19,18,17],[16,15,14,13,12],[11,10,9,8,7],[6,5,4,3,2]])
y=np.argsort(a[:,2],kind='mergesort')# a[:,2]=[19,14,9,4]
a=a[y]
print(a)

所需的输出是 [[6,5,4,3,2],[11,10,9,8,7],[16,15,14,13,12],[21,20,19,18,17]]

请注意,argsort(numArray) 返回 numArray 的索引,因为它应该以排序方式排列。

例子

x=np.array([8,1,5]) 
z=np.argsort(x) #[1,3,0] are the **indices of the predicted sorted array**
print(x[z]) #boolean indexing which sorts the array on basis of indices saved in z

答案是 [1,5,8]


你确定不是[1,2,0]?
h
hpaulj

稍微复杂一点的 lexsort 示例 - 在第一列下降,第二列上升。 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]])

S
Sefa

这是另一个考虑 all 列的解决方案(J.J 的答案更简洁);

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]])

用 lexsort 排序,

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]])

E
Ehsan

这是一个老问题,但如果您需要将其推广到高于 2 维的数组,这里的解决方案可以很容易地推广:

np.einsum('ij->ij', a[a[:,1].argsort(),:])

这对于二维来说是一种过度杀伤,对于@steve 的回答来说,a[a[:,1].argsort()] 就足够了,但是这个答案不能推广到更高的维度。您可以找到an example of 3D array in this question.

输出:

[[7 0 5]
 [9 2 3]
 [4 5 6]]

u
umair ali

#用于沿第 1 列排序

indexofsort=np.argsort(dataset[:,0],axis=-1,kind='stable') 
dataset   = dataset[indexofsort,:]

A
Arkady
def sort_np_array(x, column=None, flip=False):
    x = x[np.argsort(x[:, column])]
    if flip:
        x = np.flip(x, axis=0)
    return x

原始问题中的数组:

a = np.array([[9, 2, 3],
              [4, 5, 6],
              [7, 0, 5]])

问题作者所期望的 sort_np_array 函数的结果:

sort_np_array(a, column=1, flip=False)
[2]: array([[7, 0, 5],
            [9, 2, 3],
            [4, 5, 6]])

l
lhoupert

感谢这篇文章:https://stackoverflow.com/a/5204280/13890678

我使用 structured array 找到了一个更“通用”的答案。我认为这种方法的一个优点是代码更容易阅读。

import numpy as np
a = np.array([[9, 2, 3],
           [4, 5, 6],
           [7, 0, 5]])

struct_a = np.core.records.fromarrays(
    a.transpose(), names="col1, col2, col3", formats="i8, i8, i8"
)
struct_a.sort(order="col2")

print(struct_a)
[(7, 0, 5) (9, 2, 3) (4, 5, 6)]

r
rubengavidia0x

Pandas 方法只是为了完整性:

a = np.array([[9, 2, 3],
              [4, 5, 6],
              [7, 0, 5]])              
a = pd.DataFrame(a) 

             
a.sort_values(1, ascending=True).to_numpy()
array([[7, 0, 5], # '1' means sort by second column
       [9, 2, 3],
       [4, 5, 6]])

prl900 进行基准测试,与接受的答案进行比较:

%timeit pandas_df.sort_values(9, ascending=True)
1000 loops, best of 3: 400 µs per loop

%timeit numpy_table[numpy_table[:,9].argsort()]
10000 loops, best of 3: 180 µs per loop  

m
marc_s

只需使用排序,使用要排序的列号。

a = np.array([1,1], [1,-1], [-1,1], [-1,-1]])
print (a)
a = a.tolist() 
a = np.array(sorted(a, key=lambda a_entry: a_entry[0]))
print (a)