重排NumPy二维数组的列

81

有没有办法将numpy 2D数组中列的顺序更改为新的任意顺序?例如,我有一个数组

array([[10, 20, 30, 40, 50],
       [ 6,  7,  8,  9, 10]])

而我希望将其改为,比方说

array([[10, 30, 50, 40, 20],
       [ 6,  8, 10,  9,  7]])

通过应用置换

0 -> 0
1 -> 4
2 -> 1
3 -> 3
4 -> 2

在这些列上。在新的矩阵中,因此我希望原始矩阵的第一列保持不变,第二列移动到最后一列,依此类推。

有没有numpy函数可以实现呢?我有一个相当大的矩阵,并希望得到更大的矩阵,因此如果可能的话,需要快速地就地解决此问题(置换矩阵行不通)

谢谢。

4个回答

100

使用高级索引,可以在O(n)时间和O(n)空间内实现此操作:

>>> import numpy as np
>>> a = np.array([[10, 20, 30, 40, 50],
...               [ 6,  7,  8,  9, 10]])
>>> permutation = [0, 4, 1, 3, 2]
>>> idx = np.empty_like(permutation)
>>> idx[permutation] = np.arange(len(permutation))
>>> a[:, idx]  # return a rearranged copy
array([[10, 30, 50, 40, 20],
       [ 6,  8, 10,  9,  7]])
>>> a[:] = a[:, idx]  # in-place modification of a

请注意a[:, idx]返回的是副本而不是视图,参见这里。在一般情况下,由于numpy数组在内存中的步幅(strided)方式,无法实现O(1)空间复杂度解决方案。


4
花式索引不会原地修改矩阵。提问者要求使用原地方法。请查看此答案: https://dev59.com/Zn_aa4cB1Zd3GeqP9_TR - episodeyang
5
OP要求“如有可能,就在原地操作”。但由于ndarray在内存中的步幅方式,这种情况是不可能的。 - wim
3
当然,也许可以指出这不会就地改变矩阵,以便于那些通过谷歌搜索到这里的人们能够清楚地理解。 - episodeyang

27

在我看来,最简单的方法是:

a = np.array([[10, 20, 30, 40, 50],
              [6,  7,  8,  9,  10]])
print(a[:, [0, 2, 4, 3, 1]])

结果是:

[[10 30 50 40 20]
 [6  8  10 9  7 ]]

就像 MATLAB 的做法一样。这种方法可能不如花式索引版本高效,但它要简单得多,更易于阅读。当您不想在与同事的评论中解释花式索引节省时间时,这是一个很好的选择。 - James Oswald

8
我有一个基于矩阵的解决方案,通过将置换矩阵作用于原始矩阵进行后乘操作。这会改变原始矩阵中元素的位置。
import numpy as np

a = np.array([[10, 20, 30, 40, 50],
       [ 6,  7,  8,  9, 10]])

# Create the permutation matrix by placing 1 at each row with the column to replace with
your_permutation = [0,4,1,3,2]

perm_mat = np.zeros((len(your_permutation), len(your_permutation)))

for idx, i in enumerate(your_permutation):
    perm_mat[idx, i] = 1

print np.dot(a, perm_mat)

你好,欢迎来到SO。这个答案似乎解决了问题,但您介意编辑一下并解释一下您的代码在做什么吗?我理解它,但其他人可能不行,如果没有适当的解释,我们只是告诉他们该做什么,而不是如何做某事。 - Alerra
在一行中,这是 np.dot(a, np.eye(a.shape[1], dtype=a.dtype)[your_permutation])。对于小数组来说还可以,但处理大数据时性能会非常慢。 注意:O.P.在问题中提到“排列矩阵不行”,但很可能仍然值得在这里提供矩阵解决方案,以便其他发现此内容且不需要性能的用户受益。+1 - wim

0
如果您正在寻找任何随机排列,只需将列转置为行,对行进行排列,然后再次转置即可一行完成:
a = np.random.permutation(a.T).T

这行代码没有给出正确的结果。 - Darth Vader
1
哦,也许我误解了问题。我以为排列应该是随机生成的,但现在我看到这不是这样。这行代码确实很难产生问题中给定的特定排列。我正在编辑以澄清这一点。 - Frank Seidl
@FrankSeidl,我刚刚看到了你的评论,笑得太厉害了,不得不点赞。 "高度不可能" 确实是这样。roflmao。 - Helpful

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