当时在numpy矩阵中混洗一列的有效方法

时间:2014-11-17 15:16:40

标签: python performance numpy matrix

我需要一个接一个地移动一个numpy矩阵的所有列。 这是我目前的代码

n, p = X.shape
val = []
for i in range(p):
    Xt = X.copy()
    np.random.shuffle(Xt[:, i])
    print(Xt)

我每次X复制到变量Xt。这似乎效率很低。

如何加快此代码的速度?

编辑:示例 鉴于

`X= [[0 3 6]
    [1 4 7]
    [2 5 8]]`

for循环的预期输出是:

>>> [[2 3 6]
 [1 4 7]
 [0 5 8]] 

[[0 5 6]
 [1 4 7]
 [2 3 8]] 

[[0 3 7]
 [1 4 8]
 [2 5 6]] 

>>> 

每次只应洗牌一列。所有其他列应具有与原始矩阵相同的值

2 个答案:

答案 0 :(得分:5)

可以在numpy中对列进行混洗,并且根本不需要复制:

import numpy as np
X = np.arange(25).reshape(5,5).transpose()
print X
np.random.shuffle(X[:,2])  # here, X[:,2] is a just a view onto this column of X
print X

,输出为:

[[ 0  1  2  3  4]  # the original
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]]

[[ 0  1  2  3  4]  # note that the middle column is shuffled here
 [ 5  6 12  8  9]
 [10 11 22 13 14]
 [15 16 17 18 19]
 [20 21  7 23 24]]

你正在进行大量的复制,而且很难判断是否有必要满足你的整体需求,但这并不是洗牌所必需的。

修改
虽然这个问题是以改组的方式写的,但由于可以在适当的位置进行改组,实际的低效率是由于复制造成的。因此,问题就是OP在副本方面需要什么?由于需要恢复原始阵列,因此需要对某些附加索引或数组值进行一些复制或复制。在这种情况下,唯一的效率是希望整个数组不需要为每个循环复制,而只需要复制列(或者,基本等效,复制整个矩阵一次 - 与复制矩阵p相比在问题的例子和@ajcr中完成的时间。以下生成器只是逐行执行:

def sc(x):
    p = X.shape[1]
    for i in range(p):
        hold = np.array(x[:,i])
        np.random.shuffle(x[:,i])
        yield x
        x[:,i] = hold

for i in sc(X):
    print i

给出:

[[ 2  5 11 15 20]    # #0 column shuffled
 [ 3  6 10 16 21]
 [ 0  7 14 17 22]
 [ 4  8 13 18 23]
 [ 1  9 12 19 24]]

[[ 0  5 11 15 20]    # #1 column shuffled
 [ 1  8 10 16 21]
 [ 2  9 14 17 22]
 [ 3  7 13 18 23]
 [ 4  6 12 19 24]]

#  etc

另一方面,如果整个数组需要为每个列移位一个新的副本,那就是时间的流逝,并且这些列是否被逐个洗牌或同时洗牌并不重要,等

答案 1 :(得分:1)

这是一种完全避免循环并构建所需数组的方法:

  • 给定一个包含X列的数组n,构建一个Y个数n的数组X

  • 创建一个掩码,从数组X中的Y的第i个副本中选择第i列。

  • 使用X

  • 上的掩码,将Y的列改组副本重新分配给Y的相关索引

在NumPy中,它看起来像这样:

>>> X = np.arange(9).reshape(3, 3)
>>> X
array([[0, 1, 2],          # an example array
       [3, 4, 5],
       [6, 7, 8]])

>>> Y = X * np.ones((3, 3, 3))
>>> mask = zeros_like(Y)
>>> mask[[0,1,2],:,[0,1,2]] = 1
>>> mask = mask.astype(bool)
>>> Y[mask] = np.random.permutation(X).ravel('F')
>>> Y
array([[[ 6.,  1.,  2.],   # first column shuffled
        [ 0.,  4.,  5.],
        [ 3.,  7.,  8.]],

       [[ 0.,  7.,  2.],   # second column shuffled
        [ 3.,  1.,  5.],
        [ 6.,  4.,  8.]],

       [[ 0.,  1.,  8.],   # third column shuffled
        [ 3.,  4.,  2.],
        [ 6.,  7.,  5.]]])