Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么numpy.dot会有这种行为?_Python_Numpy_Linear Algebra_Matrix Multiplication_Array Broadcasting - Fatal编程技术网

Python 为什么numpy.dot会有这种行为?

Python 为什么numpy.dot会有这种行为?,python,numpy,linear-algebra,matrix-multiplication,array-broadcasting,Python,Numpy,Linear Algebra,Matrix Multiplication,Array Broadcasting,我试图理解为什么numpy的dot函数的行为是这样的: M = np.ones((9, 9)) V1 = np.ones((9,)) V2 = np.ones((9, 5)) V3 = np.ones((2, 9, 5)) V4 = np.ones((3, 2, 9, 5)) 现在np.dot(M,V1)和np.dot(M,V2)表现为 预期。但是对于V3和V4来说,结果令人惊讶 我: 我分别期望(2,9,5)和(3,2,9,5)。另一方面,np.matmul 我所期望的是:矩阵乘法是广播的

我试图理解为什么numpy的
dot
函数的行为是这样的:

M = np.ones((9, 9))
V1 = np.ones((9,))
V2 = np.ones((9, 5))
V3 = np.ones((2, 9, 5))
V4 = np.ones((3, 2, 9, 5))
现在
np.dot(M,V1)
np.dot(M,V2)
表现为 预期。但是对于
V3
V4
来说,结果令人惊讶 我:

我分别期望
(2,9,5)
(3,2,9,5)
。另一方面,
np.matmul
我所期望的是:矩阵乘法是广播的 在第二个参数的前N-2维上,以及 结果具有相同的形状:

>>> np.matmul(M, V3).shape
(2, 9, 5)
>>> np.matmul(M, V4).shape
(3, 2, 9, 5)
所以我的问题是:为什么要这样做
np.dot
它的行为是什么?它有什么特殊用途吗, 还是应用了一些一般规则的结果?

来自以下文件:

matmul
在两个重要方面与
dot
不同

  • 不允许用标量乘法
  • 矩阵堆栈一起广播,就像矩阵是元素一样
总之,这是您期望的标准矩阵乘法

另一方面,它只等价于二维阵列的矩阵乘法。对于更大的尺寸

它是a的最后一个轴与b的倒数第二个轴的和积:

dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
[来源:文件资料]

这类似于内部(点)积。对于向量,
numpy.dot
返回点积。数组被认为是向量的集合,并返回向量的点积

来自:

对于二维数组,它等价于矩阵乘法,对于一维数组,它等价于向量的内积(无复共轭)。对于N维,它是
a
最后一个轴和
b的倒数第二个轴上的和积:

dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
对于
np.dot(M,V3)

贯穿线表示已求和的维度,因此不存在于结果中


相反,将N维数组视为二维矩阵的“堆栈”:

行为取决于以下方式的参数

  • 如果两个参数都是二维的,则它们将像常规矩阵一样相乘
  • 如果任一参数为N-D,N>2,将其视为驻留在最后两个索引中的矩阵堆栈,并相应地进行广播
在这两种情况下执行相同的减少,但轴的顺序不同<代码>np.matmul本质上等同于:

for ii in range(V3.shape[0]):
    out1[ii, :, :] = np.dot(M[:, :], V3[ii, :, :])


等效的
einsum
表达式为:

In [92]: np.einsum('ij,kjm->kim',M,V3).shape
Out[92]: (2, 9, 5)
In [93]: np.einsum('ij,lkjm->lkim',M,V4).shape
Out[93]: (3, 2, 9, 5)
通过这种方式表达,
dot
等价物“ij,lkjm->ilkm”看起来就像“matmul”等价物“ij,lkjm->lkim”一样自然

关于原因:

dot
matmult
都是2D*2D矩阵乘法的推广。但根据数学性质、广播规则等,它们是许多可能的选择

dot
matmul
的选择非常不同:

对于点
,某些维度(此处为绿色)专用于第一个数组, 其他(蓝色)为第二个

matmul
需要一个关于广播规则的堆栈对齐

Numpy诞生于图像分析环境中,
dot
可以通过
out=dot(图像、变换)的方式轻松管理一些任务。(参见早期版本的第92页中的dot文档)

举个例子:

from pylab import *
image=imread('stackoverflow.png')

identity=eye(3)
NB=ones((3,3))/3
swap_rg=identity[[1,0,2]]
randoms=[rand(3,3) for _ in range(6)]

transformations=[identity,NB,swap_rg]+randoms
out=dot(image,transformations)

for k in range(9): 
    subplot(3,3,k+1)
    imshow (out[...,k,:])

现代的
matmul
可以做与旧的
dot
相同的事情,但必须考虑矩阵的堆栈。(
matmul(image,transformations[:,None])
here)


毫无疑问,它在其他环境中更好。

这实际上在dot和MATMUL的numpy文档中得到了解释。还有一个例子:
a1=np.random.rand(3,4);a2=np.rand.rand(10,4,1);A=(a1@a2);B=np.数组([a1@a2[i,:,0]表示范围(10)]内的i);断言A.shape==B.shape;断言np.allclose(A.squence(),B)
for ii in range(V3.shape[0]):
    out1[ii, :, :] = np.dot(M[:, :], V3[ii, :, :])
for ii in range(V4.shape[0]):
    for jj in range(V4.shape[1]):
        out2[ii, jj, :, :] = np.dot(M[:, :], V4[ii, jj, :, :])
In [92]: np.einsum('ij,kjm->kim',M,V3).shape
Out[92]: (2, 9, 5)
In [93]: np.einsum('ij,lkjm->lkim',M,V4).shape
Out[93]: (3, 2, 9, 5)
from pylab import *
image=imread('stackoverflow.png')

identity=eye(3)
NB=ones((3,3))/3
swap_rg=identity[[1,0,2]]
randoms=[rand(3,3) for _ in range(6)]

transformations=[identity,NB,swap_rg]+randoms
out=dot(image,transformations)

for k in range(9): 
    subplot(3,3,k+1)
    imshow (out[...,k,:])