我正在尝试理解numpy.einsum()函数,但来自stackoverflow的文档和this answer仍然给我留下了一些问题。
让我们考虑爱因斯坦和答案中定义的矩阵。
A = np.array([0, 1, 2])
B = np.array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
np.einsum('i,ij->i', A, B)
所以,基于我对爱因斯坦和的理解,我会将这个函数翻译成等价的符号(A_i * B_ij),所以我会得到:
j = 1:A_1 * B_11 + A_2 * B_21 + A_3 * B_31
j = 2:A_1 * B_12 + A_2 * B_22 + A_3 * B_32
依此类推,直到j = 4.这给出了
j = 1:0 + 4 + 16
j = 2:0 + 5 + 18
根据我的理解,这将是爱因斯坦的总和。相反,该函数不执行总和,而是将单独的项存储在矩阵中,我们可以在其中发现(A_i * B_ij)的结果0 0 0 0
4 5 6 7
16 18 20 22
这是如何实际控制的?我觉得这是由文档中提到的输出标签控制的:
可以通过将输出下标标签指定为来控制输出 好。这指定了标签顺序,并允许求和 在需要时被禁止或强迫
所以不知怎的,我假设把->i
禁用内部总和的求和。但这是如何工作的呢?这对我来说并不清楚。放->j
提供了预期的实际爱因斯坦和。
答案 0 :(得分:2)
看来你对爱因斯坦求和的理解是不正确的。你写出的下标操作的乘法是正确的,但总和是在错误的轴上。
想想这意味着什么:np.einsum('i,ij->i', A, B)
。
A
的形状为(i,)
,B
的形状为(i, j)
。B
的每一列乘以A
。B
的第二个轴上求和,即在标有j
的轴上求和。这会给出形状(i,) == (3,)
的输出,而下标符号会给出形状(j,) == (4,)
的输出。你在错误的轴上进行求和。
更详细信息:
请记住,乘法总是先发生。左侧下标告诉np.einsum
函数输入数组的哪些行/列/等要相互相乘。此步骤的输出始终与最高维输入数组具有相同的形状。即,在这一点上,一个假设的"中间体"数组的形状为(3, 4) == B.shape
。
乘法后,有求和。这是由右侧的省略的下标控制的。在这种情况下,省略j
,这意味着沿阵列的第一轴求和。 (你在第0次总结。)
如果您改为编写:np.einsum('i,ij->ij', A, B)
,则会有 no 求和,因为没有省略下标。因此,您可以获得在问题结束时获得的数组。
以下是几个例子:
例1:
没有省略下标,所以没有总结。只需将B
的列乘以A
即可。这是你写完的最后一个数组。
>>> (np.einsum('i,ij->ij', A, B) == (A[:, None] * B)).all()
True
例2:
与示例相同。将列相乘,然后对输出列进行求和。
>>> (np.einsum('i,ij->i', A, B) == (A[:, None] * B).sum(axis=-1)).all()
True
例3:
您在上面写的总和。将列相乘,然后对输出的行求和。
>>> (np.einsum('i,ij->j', A, B) == (A[:, None] * B).sum(axis=0)).all()
True
例4:
请注意,我们可以在末尾省略所有轴,以获得整个数组的总和。
>>> np.einsum('i,ij->', A, B)
98
Ex 5:
请注意,总和之所以发生,是因为我们重复了输入标签'i'
。如果我们为输入数组的每个轴使用不同的标签,我们可以计算类似于Kronecker产品的东西:
>>> np.einsum('i,jk', A, B).shape
(3, 3, 4)
修改强>
爱因斯坦和的NumPy实现与传统定义略有不同。从技术上讲,爱因斯坦总和并没有“输出标签”的概念。重复的输入标签总是暗示这些。
来自文档:"Whenever a label is repeated, it is summed."
因此,传统上,我们会编写类似np.einsum('i,ij', A, B)
的内容。这相当于np.einsum('i,ij->j', A, B)
。重复i
,因此将其相加,只留下标记为j
的轴。您可以考虑将 no 输出标签指定为与仅指定输入中未重复的标签相同的总和。也就是说,标签'i,ij'
与'i,ij->j'
相同。
输出标签是在NumPy中实现的扩展或扩充,允许调用者强制求和或在轴上强制执行 no 求和。来自文档:"The output can be controlled by specifying output subscript labels as well. This specifies the label order, and allows summing to be disallowed or forced when desired."