【问题标题】:Put pairwise differences of matrix rows in 3-d array将矩阵行的成对差异放入 3-d 数组中
【发布时间】:2015-07-18 06:02:42
【问题描述】:

我有一个形状为 (n, d) 的矩阵 Y。我已经通过以下方式计算了成对的行差异:

I, J = np.triu_indices(Y.shape[0], 0)
rowDiffs = (Y[I, :] - Y[J, :])

不,我想创建一个 3d 数组,其中包含位置 (i,j, :) 处 Y 的 i 和 j 行的差异。你会怎么做?

它的目的是替换这个低效的循环:

   for i in range(Y.shape[0]): 
        for j in range(Y.shape[0]):
            C[i,:] = C[i,:] + W[i, j] * (Y[i, :]-Y[j, :])

【问题讨论】:

    标签: python arrays performance matrix vectorization


    【解决方案1】:

    我在这方面取得了一些成功:

    row_diffs = Y[:, np.newaxis] - Y
    

    Y[:, np.newaxis] 创建尺寸为 (n, 1, 3) 的 Y 版本。然后,减法使用broadcasting 做你想做的事。

    不幸的是,我发现这种方法相对较慢,而且我还没有找到更好的方法。

    完整示例:

    >>> x = np.random.randint(10, size=(4, 3))
    >>> x
    array([[4, 0, 8],
           [8, 5, 3],
           [4, 1, 6],
           [2, 2, 4]])
    >>> x[:, np.newaxis] - x
    array([[[ 0,  0,  0],
            [-4, -5,  5],
            [ 0, -1,  2],
            [ 2, -2,  4]],
    
           [[ 4,  5, -5],
            [ 0,  0,  0],
            [ 4,  4, -3],
            [ 6,  3, -1]],
    
           [[ 0,  1, -2],
            [-4, -4,  3],
            [ 0,  0,  0],
            [ 2, -1,  2]],
    
           [[-2,  2, -4],
            [-6, -3,  1],
            [-2,  1, -2],
            [ 0,  0,  0]]])
    

    【讨论】:

      【解决方案2】:

      这是使用broadcastingnp.einsum 的矢量化方法-

      np.einsum('ij,ijk->ik',W,Y[:,None] - Y)
      

      运行时测试-

      In [29]: def original_app(Y,W):
          ...:     m = Y.shape[0]
          ...:     C = np.zeros((m,m))
          ...:     for i in range(Y.shape[0]): 
          ...:         for j in range(Y.shape[0]):
          ...:             C[i,:] = C[i,:] + W[i, j] * (Y[i, :]-Y[j, :])
          ...:     return C
          ...: 
      
      In [30]: # Inputs
          ...: Y = np.random.rand(100,100)
          ...: W = np.random.rand(100,100)
          ...: 
      
      In [31]: out = original_app(Y,W)
      
      In [32]: np.allclose(out, np.einsum('ij,ijk->ik',W,Y[:,None] - Y))
      Out[32]: True
      
      In [33]: %timeit original_app(Y,W)
      10 loops, best of 3: 70.8 ms per loop
      
      In [34]: %timeit np.einsum('ij,ijk->ik',W,Y[:,None] - Y)
      100 loops, best of 3: 4.01 ms per loop
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-18
        • 2018-01-31
        • 2019-09-27
        • 2021-02-07
        • 2021-11-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多