numpy dot() 和 inner() 的区别

70

什么是两者之间的区别?

import numpy as np
np.dot(a,b)

并且

import numpy as np
np.inner(a,b)

我尝试的所有示例都返回相同的结果。Wikipedia上两者有相同的文章?! 在inner()说明中,它说在更高的维度中其行为是不同的,但我无法产生任何不同的输出。 我应该使用哪个?

6个回答

72

numpy.dot:

对于二维数组,它相当于矩阵乘法;对于一维数组,它是向量的内积(不进行复共轭)。对于N维数组,它是a的最后一个轴和b的倒数第二个轴的和积:

numpy.inner:

对于一维数组,它是向量的普通内积(不进行复共轭);在更高维度中,它是a的最后几个轴和b的最后几个轴的和积。

(强调是作者加的.)

举个例子,考虑以下的2D数组示例:

>>> a=np.array([[1,2],[3,4]])
>>> b=np.array([[11,12],[13,14]])
>>> np.dot(a,b)
array([[37, 40],
       [85, 92]])
>>> np.inner(a,b)
array([[35, 41],
       [81, 95]])
因此,你应该使用适合你的应用程序的能够提供正确行为的方法。

性能测试

(请注意,我仅测试了1D情况,因为这是唯一情况下.dot.inner会给出相同结果的情况。)

>>> import timeit
>>> setup = 'import numpy as np; a=np.random.random(1000); b = np.random.random(1000)'

>>> [timeit.timeit('np.dot(a,b)',setup,number=1000000) for _ in range(3)]
[2.6920320987701416, 2.676928997039795, 2.633111000061035]

>>> [timeit.timeit('np.inner(a,b)',setup,number=1000000) for _ in range(3)]
[2.588860034942627, 2.5845699310302734, 2.6556360721588135]

所以也许.inner更快,但我的机器此刻负载相当高,因此计时不一致,也不一定非常准确。


2
@MillaWell,即使是2D数组,它们也是不同的:只有在1D时它们才相同。我不知道任何性能差异,有两种测试方法:阅读源代码(不容易)或使用timeit进行一些分析(更容易)。 - huon
1
我认为总体上我理解了一切。例如,在你的例子中,你计算.dot的第一个值为(111+213)。那么你如何计算你的例子中.inner的第一个值呢? - Milla Well
7
@MillaWell,你是正确的。让 c = np.dot(a,b)d = np.inner(a,b),则 c[i,j] == sum(a[i,:] * b[:,j])d[i,j] == sum(a[i,:] * b[j,:]) - huon
11
另一种表达差异的方式是说,对于向量来说它们是相同的,但对于2D数组而言,np.dot(a, b) == np.inner(a, b.T)np.dot(a, b.T) == np.inner(a, b) - senderle

22

np.dotnp.inner对于一维数组来说是相同的,这可能就是你没有注意到任何差异的原因。对于N维数组,它们对应于常见的张量运算。

np.inner有时被称为高阶和低阶张量之间的“向量积”,特别是张量乘以向量,并且常常导致“张量收缩”。它包括矩阵-向量乘法。

np.dot对应于“张量积”,并包括维基百科页面底部提到的情况。一般用于两个类似张量的乘法以生成新的张量。它包括矩阵-矩阵乘法。

如果您不使用张量,则无需担心这些情况,它们的行为是相同的。


2
看起来 np.dot 现在(即在 Python 3 中)是矩阵乘法,无论维度如何。因此,它与 np.inner 不同,即使对于 1-D 数组也是如此。 - James Hirschorn
1
我在使用NumPy 1.13.3和Python 3.6.3中看到了相同的结果。你在使用什么版本?一个例子也是好的。 - marshall.ward

15

对于一维和二维数组,numpy.inner 的工作方式是转置第二个矩阵,然后相乘。

A = [[a1,b1],[c1,d1]]
B = [[a2,b2],[c2,d2]]
numpy.inner(A,B)
array([[a1*a2 + b1*b2, a1*c2 + b1*d2],
       [c1*a2 + d1*b2, c1*c2 + d1*d2])

我使用类似以下例子来解决这个问题:

A=[[1  ,10], [100,1000]]
B=[[1,2], [3,4]]
numpy.inner(A,B)
array([[  21,   43],
       [2100, 4300]])

这也解释了一维情况下的行为,numpy.inner([a,b],[c,b]) = ac+bdnumpy.inner([[a],[b]], [[c],[d]]) = [[ac,ad],[bc,bd]]。 这是我知道的全部,不知道它在高维情况下有什么作用。


1
在高维空间中,内积和点积有很大的区别。以下是一个2x2矩阵和3x2矩阵的示例 x = [[a1,b1],[c1,d1]] y= [[a2,b2].[c2,d2],[e2,f2]]

np.inner(x,y)

输出结果为[[a1xa2+b1xb2,a1xc2+b1xd2,a1xe2+b1f2],[c1xa2+d1xb2,c1xc2+d1xd2,c1xe2+d1xf2]]。

但是在点积的情况下,输出会显示以下错误,因为您不能将一个2x2矩阵与一个3x2矩阵相乘。

ValueError: 形状(2,2)和(3,2)不对齐:2(dim 1)!= 3(dim 0)


1
内部在处理复杂的二维数组时存在问题,尝试将其与转置矩阵相乘。
array([[ 1.+1.j,  4.+4.j,  7.+7.j],
       [ 2.+2.j,  5.+5.j,  8.+8.j],
       [ 3.+3.j,  6.+6.j,  9.+9.j]])

你将会得到。
array([[ 0. +60.j,  0. +72.j,  0. +84.j],
       [ 0.+132.j,  0.+162.j,  0.+192.j],
       [ 0.+204.j,  0.+252.j,  0.+300.j]])

有效地将行乘以行而不是行乘以列。

-1

有人能解释一下为什么要踩我吗?这对我很有帮助,我认为它也会对其他人有帮助。 - Geoff Langenderfer
5
可以请您在回答中包含基础代码。 - Sanjay Manohar

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