3

我正在尝试基于矩阵编写快速、优化的代码,并且最近发现了 einsum 作为实现显着加速的工具。

是否可以使用它来有效地设置多维数组的对角线,还是只能返回数据?

在我的问题中,我试图通过对每个方阵 (N x N) 矩阵中的列求和来设置方阵数组(形状:M x N x N)的对角线。

我当前的(缓慢的,基于循环的)解决方案是:

# Build dummy array
dimx = 2  # Dimension x (likely to be < 100)
dimy = 3  # Dimension y (likely to be between 2 and 10)
M = np.random.randint(low=1, high=9, size=[dimx, dimy, dimy])

# Blank the diagonals so we can see the intended effect
np.fill_diagonal(M[0], 0)
np.fill_diagonal(M[1], 0)

# Compute diagonals based on summing columns
diags = np.einsum('ijk->ik', M)

# Set the diagonal for each matrix 
# THIS IS LOW. CAN IT BE IMPROVED?
for i in range(len(M)):
    np.fill_diagonal(M[i], diags[i])

# Print result   
M

请问这可以改善吗?似乎 np.fill_diagonal 不接受非方阵(因此强制我的基于循环的解决方案)。也许 einsum 也可以在这里提供帮助?

4

2 回答 2

3

一种方法是将形状重塑为2D,将列设置为 步长ncols+1对角线值。重塑创建了一个视图,因此我们可以直接访问这些对角线位置。因此,实施将是 -

s0,s1,s2 = M.shape
M.reshape(s0,-1)[:,::s2+1] = diags
于 2017-05-15T23:07:50.983 回答
2

如果你这样做np.source(np.fill_diagonal),你会看到在 2d 案例中它使用“跨步”方法

    if a.ndim == 2:
        step = a.shape[1] + 1
        end = a.shape[1] * a.shape[1]
    a.flat[:end:step] = val

@Divakar's解决方案通过在 2 维上“展平”将其应用于您的 3d 案例。

您可以将列与 相加M.sum(axis=1)。虽然我隐约记得一些发现einsum实际上更快的时间。 sum更传统一点。

有人要求能够在 中扩展维度einsum,但我认为这不会发生。

于 2017-05-16T00:24:22.520 回答