将矩阵行的成对差异放在三维数组中

时间:2015-05-07 15:02:56

标签: python arrays performance matrix vectorization

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

   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, :])

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

它的目的是取代这个效率低下的循环:

<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>

2 个答案:

答案 0 :(得分: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]]])

答案 1 :(得分:0)

这是使用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