高尺寸的Einsum



考虑以下 3 个数组:

np.random.seed(0)
X = np.random.randint(10, size=(4,5))
W = np.random.randint(10, size=(3,4))
y = np.random.randint(3, size=(5,1))

我想将矩阵 X 的每一列添加并求和到 W 行,由 y 作为索引给出。因此,例如,如果 y 中的第一个元素是 3 ,我将 X 的第一列添加到 W(python 中的索引 3(的第四行并求和。我会一遍又一遍地这样做,直到 X 的所有列都添加到 W 的特定行并求和。 我可以用不同的方式做到这一点: 1-使用for循环:

for i,j in enumerate(y):
W[j]+=X[:,i] 

2-使用 add.at 功能

np.add.at(W,(y.ravel()),X.T)

3-但我不明白如何使用Einsum来做到这一点。 我得到了一个解决方案,但真的无法理解。

N = y.max()+1
W[:N] += np.einsum('ijk,lk->il',(np.arange(N)[:,None,None] == y.ravel()),X) 

有人可以解释我这个结构吗? 1 - (np.arange(N([:,None,None] == y.ravel((,X(.我想这部分是指根据 y 将 X 的列与 W 的特定行相加。但是在哪里 W ?为什么在这种情况下我们必须在 4 维中变换 W? 2-"IJK,LK->IL" - 我也不明白这一点。

i -指行, j - 列, k-每个元素, l - "L"也指什么? 如果有人能理解这一点并向我解释,我将不胜感激。 提前谢谢。

让我们通过删除一个维度并使用易于手动验证的值来简化问题:

W = np.zeros(3, np.int)
y = np.array([0, 1, 1, 2, 2])
X = np.array([1, 2, 3, 4, 5])

向量中的值W通过查找yX中获取附加值:

for i, j in enumerate(y):
W[j] += X[i]

W计算为[1, 5, 9],(手动快速检查(。

现在,如何对此代码进行矢量化处理?我们不能做一个简单的W[y] += X[y]因为y里面有重复的值,不同的总和会在索引 1 和 2 处相互覆盖。

可以做的是将值广播到len(y)的新维度中,然后对这个新创建的维度进行汇总。

N = W.shape[0]
select = (np.arange(N) == y[:, None]).astype(np.int)

W([0, 1, 2]( 的索引范围,并将它们在新维度中与y匹配的值设置为 1,否则设置为 0。select包含以下数组:

array([[1, 0, 0],
[0, 1, 0],
[0, 1, 0],
[0, 0, 1],
[0, 0, 1]])

它有len(y) == len(X)行和len(W)列,并显示每个y/行,它贡献的W索引。

让我们用这个数组将 X 乘以,mult = select * X[:, None]

array([[1, 0, 0],
[0, 2, 0],
[0, 3, 0],
[0, 0, 4],
[0, 0, 5]])

我们已经有效地将 X 分散到一个新的维度中,并通过对新创建的维度求和来使其形成形状 W 的方式对其进行排序。行的总和是我们要添加到W的向量:

sum_Xy = np.sum(mult, axis=0)  # [1, 5, 9]
W += sum_Xy

selectmult的计算可以与np.einsum相结合:

# `select` has shape (len(y)==len(X), len(W)), or `yw`
# `X` has shape len(X)==len(y), or `y`
# we want something `len(W)`, or `w`, and to reduce the other dimension
sum_Xy = np.einsum("yw,y->w", select, X)

这就是一维示例。对于问题中提出的二维问题,它的方法完全相同:引入一个额外的维度,广播y指数,然后用einsum减少额外的维度。

如果你内化了一维示例的每个步骤是如何工作的,我相信你可以弄清楚代码是如何在二维上完成的,因为这只是一个正确索引的问题(W 行、X 列(。

相关内容

  • 没有找到相关文章

最新更新