NumPy:按指定值重新排序数组

5

我有一个矩阵:

A = [ [1,2],
      [3,4],
      [5,6] ]

还有一个值的向量:

V = [4,6,2]

我希望能够使用V的值按照第2列重新排序A。结果应该如下所示:
A = [ [3,4],
      [5,6], 
      [1,2] ] # 2nd columns' values have the same order as V

如何做到呢?

2个回答

7
首先,我们需要找到A第二列中的值的索引,以便匹配V的顺序。在这种情况下,它是[1,2,0]。一旦我们有了这些,我们就可以使用numpy的“fancy”索引来完成剩下的工作。
因此,您可以像这样操作:
import numpy as np
A = np.arange(6).reshape((3,2)) + 1
V = [4,6,2]
column = A[:,1].tolist()
order = [column.index(item) for item in V]
print A[order,:]

如果您想完全避免使用python列表,则可以像下面显示的那样做。这是一个hack,可能有更好的方法,但是...

我们可以利用numpy.unique来实现这一点... 我在这里做的是依靠特定的实现细节(unique似乎从数组末尾开始),这个细节随时都可能发生变化... 这就是它变成了一个丑陋的hack的原因。

import numpy as np
A = np.arange(6).reshape((3,2)) + 1
V = np.array([4,6,2])
vals, order = np.unique(np.hstack((A[:,1],V)), return_inverse=True)
order = order[-V.size:]
print A[order,:]

嗯,有一种方法,但是看起来你不想按VA进行排序...(如果你想这样做,只需要使用np.argsort然后使用索引或其他类似的方法即可。)你想要AV相同的顺序。再说了,可能有比我描述的更简单的方法... - Joe Kington

6

@JoeKington的numpy解决方案非常聪明,但它依赖于A[:,1]按排序顺序排列。这里是通用情况的修复方法:

import numpy as np

np.random.seed(1)
N=5
A = np.arange(2*N).reshape((-1,2))+100
np.random.shuffle(A)
print(A)

如果A看起来像这样:

[[104 105]
 [102 103]
 [108 109]
 [100 101]
 [106 107]]

V

V = A[:,1].copy()
np.random.shuffle(V)
print(V)

看起来像这样:

[105 109 107 101 103]

然后我们使用Joe的解决方案:

vals, order = np.unique(np.hstack((A[:,1],V)), return_inverse=True)

但要保留 A[:,1]V 的顺序:

a_order = order[:V.size]
v_order = order[-V.size:]

在使用v_order重新排序之前,通过形成A[np.argsort(a_order)]来对A进行排序:

print A[np.argsort(a_order)][v_order]

[[104 105]
 [108 109]
 [106 107]
 [100 101]
 [102 103]]

(A[np.argsort(a_order)]是按照其第二列排序后的A。)


请注意,np.unique总是以排序的顺序返回数组。文档保证使用return_inverse=True时返回的索引是重构原始数组的唯一数组的索引。也就是说,如果像这样调用np.unique
uniq_arr, indices = np.unique(arr, return_inverse=True)

您有保障

unique_arr[indices] = arr

由于您可以依赖这种关系,Joe的方法不仅仅依赖于实现细节 -- unique总是会以这种方式行事。(著名的最后一句话 -- 考虑到np.unique1d返回的输出参数顺序发生了什么...但不要在意 :))

非常好,所有情况下都有很好的观点!我没有考虑得够透彻。 - Joe Kington

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接