【问题标题】:Shuffle columns of an array with Numpy使用 Numpy 随机排列数组的列
【发布时间】:2013-12-12 14:40:25
【问题描述】:

假设我有一个维度为(n, m) 的数组r。我想打乱该数组的列。

如果我使用numpy.random.shuffle(r),它会洗牌。我怎样才能只洗牌?使第一列成为第二列,第三列成为第一列,依此类推。

示例:

输入:

array([[  1,  20, 100],
       [  2,  31, 401],
       [  8,  11, 108]])

输出:

array([[  20, 1, 100],
       [  31, 2, 401],
       [  11,  8, 108]])

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    一种方法是打乱转置数组:

     np.random.shuffle(np.transpose(r))
    

    另一种方法(参见 YXD 的回答 https://stackoverflow.com/a/20546567/1787973)是生成一个排列列表以按该顺序检索列:

     r = r[:, np.random.permutation(r.shape[1])]
    

    就性能而言,第二种方法更快。

    【讨论】:

    • 是的。不过,我推荐 r.T 进行转置。
    • @user2357112 是 r.Tnp.transpose(r) 完全相同但更短?
    • 实际上相同。一维数组有非常细微的差别,但您可能不会将Ttranspose 用于一维数组。
    • 由于 numpy.shuffle 打乱了行,但是采用矩阵的转置,你有效地打乱了列。然后你转回来。
    • @Matt:这是对原始数组视图的就地操作。它不会创建一个新的随机数组,因此不需要转置结果。
    【解决方案2】:

    还有另一种方式,它不使用转置,显然更快

    np.take(r, np.random.permutation(r.shape[1]), axis=1, out=r)
    

    CPU 时间:用户 1.14 毫秒,系统:1.03 毫秒,总计:2.17 毫秒。挂墙时间:3.89 毫秒

    其他答案中的做法:np.random.shuffle(r.T)

    CPU 时间:用户 2.24 毫秒,系统:0 纳秒,总计:2.24 毫秒 挂墙时间:5.08 毫秒

    我使用r = np.arange(64*1000).reshape(64, 1000) 作为输入。

    【讨论】:

    • 这是一个非常有趣的方法!我建议您使用timeit 来证明它确实更快。而且根据我的测试,好像是这样的!
    • r[:, np.random.permutation(r.shape[1])] 似乎比使用np.take 还要快
    • @MaximeChéramy 我使用了%%time,因为timeit 正在缓存中间结果,并且不清楚发生了什么。 r = r[:, np.random.permutation(r.shape[1])] 不错!但我的印象是np.takeout=r 使用更少的内存。可以用%memit查看吗?
    • 根据我的计时实验,实际上r[:, np.random.permutation(r.shape[1])] 似乎并不比np.take 快。您看到的加速很可能是因为缓存。
    【解决方案3】:

    对于一般轴,您可以遵循以下模式:

    >>> import numpy as np
    >>> 
    >>> a = np.array([[  1,  20, 100, 4],
    ...               [  2,  31, 401, 5],
    ...               [  8,  11, 108, 6]])
    >>> 
    >>> print a[:, np.random.permutation(a.shape[1])]
    [[  4   1  20 100]
     [  5   2  31 401]
     [  6   8  11 108]]
    >>> 
    >>> print a[np.random.permutation(a.shape[0]), :]
    [[  1  20 100   4]
     [  2  31 401   5]
     [  8  11 108   6]]
    >>> 
    

    【讨论】:

    • 代码有问题,洗牌一般不应该返回原始矩阵。
    【解决方案4】:

    一般来说,如果你想沿轴i 打乱一个 numpy 数组:

    def shuffle(x, axis = 0):
        n_axis = len(x.shape)
        t = np.arange(n_axis)
        t[0] = axis
        t[axis] = 0
        xt = np.transpose(x.copy(), t)
        np.random.shuffle(xt)
        shuffled_x = np.transpose(xt, t)
        return shuffled_x
    
    shuffle(array, axis=i)
    

    【讨论】:

      【解决方案5】:
      >>> print(s0)
      >>> [[0. 1. 0. 1.]
           [0. 1. 0. 0.]
           [0. 1. 0. 1.]
           [0. 0. 0. 1.]]
      >>> print(np.random.permutation(s0.T).T)
      >>> [[1. 0. 1. 0.]
           [0. 0. 1. 0.]
           [1. 0. 1. 0.]
           [1. 0. 0. 0.]]
      

      np.random.permutation(),行置换。

      【讨论】:

        【解决方案6】:

        所以,离你的答案更进一步:

        编辑:我很容易弄错这是如何工作的,所以我在每一步插入我对矩阵状态的理解。

        r == 1 2 3
             4 5 6
             6 7 8
        
        r = np.transpose(r)  
        
        r == 1 4 6
             2 5 7
             3 6 8           # Columns are now rows
        
        np.random.shuffle(r)
        
        r == 2 5 7
             3 6 8 
             1 4 6           # Columns-as-rows are shuffled
        
        r = np.transpose(r)  
        
        r == 2 3 1
             5 6 4
             7 8 6           # Columns are columns again, shuffled.
        

        然后将恢复正确的形状,并重新排列列。

        矩阵转置的转置 == 该矩阵,或者,[A^T]^T == A。因此,您需要在洗牌后进行第二次转置(因为转置不是shuffle) 以使其再次处于正确的形状。

        编辑:OP 的答案跳过存储转置,而是让洗牌在 r 上运行,就好像它是一样。

        【讨论】:

        • np.random.shuffle 不返回数组。
        • 所以我明白了,已编辑。无论如何,需要最后一步才能将矩阵恢复到其原始形状。
        • @Matt:不,不是。 transpose 返回原始数组的视图。一旦对转置数组进行了混洗,原始数组就会以所需的方式进行混洗。无需转置两次。
        • @user2357112 我在每个步骤中添加了一个示例矩阵来说明我的思维模式。自从我上一次线性课程以来已经十年了,但我很确定这就是 np.tranpose 和 np.random.shuffle 的文档所指示的内容。
        • @user2357112 阅读了您对该问题的评论,现在明白了,谢谢。
        猜你喜欢
        • 2019-03-19
        • 1970-01-01
        • 1970-01-01
        • 2012-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-06
        • 2012-06-24
        相关资源
        最近更新 更多