将矩阵行之间的成对差异放入三维数组中

4

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

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

我想创建一个三维数组,包含Y中第i行和第j行在位置(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, :])
2个回答

2
我用以下方法取得了一些成功:

(原文)

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

Y[:, np.newaxis] 创建一个维度为 (n, 1, 3) 的 Y 版本。然后,减法使用 广播 来完成所需操作。

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

完整示例:

>>> 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

这里有一种使用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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接