【问题标题】:numpy array to permutation matrixnumpy数组到置换矩阵
【发布时间】:2015-02-04 01:39:53
【问题描述】:
np.array([1,2,3])

我有 numpy 数组。我想把它变成一个 numpy 数组,其中包含每个 1:1 排列的元组。像这样:

np.array([
    [(1,1),(1,2),(1,3)],
    [(2,1),(2,2),(2,3)],
    [(3,1),(3,2),(3,3)],
])

关于如何有效地做到这一点有什么想法吗?我需要做几百万次这个操作。

【问题讨论】:

    标签: python arrays performance numpy permutation


    【解决方案1】:

    我一直在研究如何更好地做到这一点,而不仅仅是针对 2 元组。它实际上可以使用np.indices 非常优雅地完成,它可以用来生成一组索引来索引原始数组:

    >>> x = np.array([1, 2, 3])
    >>> i = np.indices((3, 3)).reshape(2, -1)
    >>> a[i].T
    array([[1, 1],
           [1, 2],
           [1, 3],
           [2, 1],
           [2, 2],
           [2, 3],
           [3, 1],
           [3, 2],
           [3, 3]])
    

    一般情况如下:设n为每个排列中的项目数。

    n = 5
    x = np.arange(10)
    
    i = np.indices([x.size for _ in range(n)]).reshape(n, -1)
    a = x[i].T
    

    然后,如果需要,您可以将结果重新整形为 n 维数组形式,但通常具有排列就足够了。我没有测试这个方法的性能,但是原生 numpy 调用和索引应该很快。在我看来,至少这比其他解决方案更优雅。这和@Bill提供的meshgrid解决方案非常相似。

    【讨论】:

      【解决方案2】:

      使用numpy.meshgrid 的另一种方式。

      >>> x = np.array([1, 2, 3])
      >>> perms = np.stack(np.meshgrid(x, x))
      >>> perms
      array([[[1, 2, 3],
              [1, 2, 3],
              [1, 2, 3]],
      
             [[1, 1, 1],
              [2, 2, 2],
              [3, 3, 3]]])
      >>> perms.transpose().reshape(9, 2)
      array([[1, 1],
             [1, 2],
             [1, 3],
             [2, 1],
             [2, 2],
             [2, 3],
             [3, 1],
             [3, 2],
             [3, 3]])
      

      【讨论】:

        【解决方案3】:

        您可以使用itertools.product 获取排列,然后将结果转换为numpy 数组。

        >>> from itertools import product
        >>> p=list(product(a,repeat=2))
        >>> np.array([p[i:i+3] for i in range(0,len(p),3)])
        array([[[1, 1],
                [1, 2],
                [1, 3]],
        
               [[2, 1],
                [2, 2],
                [2, 3]],
        
               [[3, 1],
                [3, 2],
                [3, 3]]])
        

        【讨论】:

          【解决方案4】:

          你可以这样做:

          >>> a = np.array([1, 2, 3])
          >>> n = a.size
          >>> np.vstack((np.repeat(a, n), np.tile(a, n))).T.reshape(n, n, 2)
          array([[[1, 1],
                  [1, 2],
                  [1, 3]],
          
                 [[2, 1],
                  [2, 2],
                  [2, 3]],
          
                 [[3, 1],
                  [3, 2],
                  [3, 3]]])
          

          或者作为suggested by @Jaime,如果我们利用此处的广播,您可以获得大约 10 倍的加速:

          >>> a = np.array([1, 2, 3])
          >>> n = a.size                 
          >>> perm = np.empty((n, n, 2), dtype=a.dtype)
          perm[..., 0] = a[:, None]
          perm[..., 1] = a
          ... 
          >>> perm
          array([[[1, 1],
                  [1, 2],
                  [1, 3]],
          
                 [[2, 1],
                  [2, 2],
                  [2, 3]],
          
                 [[3, 1],
                  [3, 2],
                  [3, 3]]])
          

          时间比较:

          >>> a = np.array([1, 2, 3]*100)
          >>> %%timeit                   
          np.vstack((np.repeat(a, n), np.tile(a, n))).T.reshape(n, n, 2)
          ... 
          1000 loops, best of 3: 934 µs per loop
          >>> %%timeit                   
          perm = np.empty((n, n, 2), dtype=a.dtype)                     
          perm[..., 0] = a[:, None]
          perm[..., 1] = a
          ... 
          10000 loops, best of 3: 111 µs per loop
          

          【讨论】:

          • 如果您远离平铺和重复使用广播,您可以获得很大的加速(100 项数组为 10 倍):perm = np.empty((n, n, 2), dtype=a.dtype); perm[..., 0] = a; perm[..., 1] = a[:. None]
          【解决方案5】:

          如果您使用的是 numpy,请不要使用元组。使用它的力量并添加另一个尺寸为 2 的维度。 我的建议是:

          x = np.array([1,2,3])
          np.vstack(([np.vstack((x, x, x))], [np.vstack((x, x, x)).T])).T
          

          或:

          im = np.vstack((x, x, x))
          np.vstack(([im], [im.T])).T
          

          对于一般数组:

          ix = np.vstack([x for _ in range(x.shape[0])])
          return np.vstack(([ix], [ix.T])).T
          

          这将产生你想要的:

          array([[[1, 1],
                  [1, 2],
                  [1, 3]],
          
                 [[2, 1],
                  [2, 2],
                  [2, 3]],
          
                 [[3, 1],
                  [3, 2],
                  [3, 3]]])
          

          但是作为一个 3D 矩阵,你可以看到它的形状:

          Out[25]: (3L, 3L, 2L)
          

          随着数组大小变大,这比使用排列的解决方案更有效。将我的解决方案与@Kasra 的解决方案相比较,我的解决方案为 1 毫秒,而对于大小为 100 的数组的排列则为 46 毫秒。@AshwiniChaudhary 的解决方案更有效。

          【讨论】:

            猜你喜欢
            • 2011-03-21
            • 1970-01-01
            • 1970-01-01
            • 2019-12-12
            • 2012-05-28
            • 1970-01-01
            • 2017-04-12
            • 2013-06-30
            相关资源
            最近更新 更多