如何使用 Linalg.multi_dot 计算数组的点积?

数组的点积可以通过 NumPy 库的 linalg.multi_dot 函数来计算,该函数比其前身 更容易计算并且需要更少的计算时间np.dot

我们还将在这篇文章中看到np.dot和的比较multi_dot

在本文中查找您需要了解的有关如何使用 np dot() 计算数组和向量的点积的所有内容。

什么是点积?

点积是两个长度相同的数组之间的数学运算,返回标量值。它的计算方式为两个数组的逐元素乘积之和。其给出如下:dot(a, b)[i,j,k,m] = sum(a [i,j,:] * b[k,:,m])


关于 linalg.multi_dot 您需要了解的一切

NumPy 库的这个函数很方便,因为它可以在单个函数调用中计算两个或多个数组的点积。

单一函数调用是指在计算两个或多个数组的点积时,无需在不同的函数调用中分别计算数组的点积,然后将结果合并到另一个函数调用中。我们只需调用一次函数即可计算尽可能多的数组的点积。

multi_dot 可以被认为是:

def mulit_dot(arrays): return functools.reduce(np.dot, arrays)

句法:

linalg.multi_dot(arrays*out=None)

论据 描述 默认值 必需/可选
数组 如果第一个参数是一维,则将其视为行向量。如果最后一个参数是一维,则将其视为列向量 生成
的数组具有与第一个参数相同的行数和与第二个参数相同的列数
类似数组的序列 必需的
出去 输出参数。它通常不会在语法中指定,但是当指定时,计算的输出应该与此字段中指定的类型和内存布局相同。此参数的目的是重用现有的 NumPy 数组作为输出参数
,这可以提高性能如果不满足参数
的指定条件,函数将引发异常out
ndarray 选修的
论据multi_dot

返回:此函数返回给定数组的点积作为输入。输出是一个 NumPy 数组。

两个简单数组的点积

让我们计算两个简单二维矩阵的点积。

代码如下。

1
2
3
4
5
6
7
import numpy as np
#creating two arrays
a=np.array([[1,2],[3,4]])
b=np.array([[5,6],[7,8]])
#computing the dot product
comp=np.linalg.multi_dot([a, b])
print(comp)

import numpy as np我们正在导入具有别名的 NumPy 库 – np.

在第三行和第四行中,使用函数创建了两个数组np.array,并将其存储在两个不同的变量 a 和 b 中。

a 和 b 的点积是在 的帮助下计算的np.linalg.multi_dot,并存储在第六行中名为 comp 的变量中。

在下一行中,我们将打印点积的结果。

a 和 b 的点积如下所示。/

点积1

让我们检查一下执行所需的时间。

1
2
#checking the execution time
%timeit np.linalg.multi_dot([a, b])

%timeit函数用于计算执行此操作所需的时间。

时间1

现在我们已经了解了基本功能,让我们看一个更复杂的示例。


当其中一个数组具有无穷值时,两个数组的点积

让我们首先考虑一个具有正无穷大值的数组。

当我们处理无穷值的消除时,这里有一篇文章展示了如何在 python 中创建无穷值。

代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
#creating arrays
a=np.array([[3,np.inf],[4,5]])
b=np.array([[5,6],[7,8]])
print("The first array is:\n",a)
print("-"*15)
print("The second array is :\n",b)
print("-"*15)
#converting the infintiy values to some number
a1=np.nan_to_num(a,posinf=12)
print("Modified array :\n",a1)
print("*"*15)
comp1=np.linalg.multi_dot([a1, b])
print("The dot product of two arrays is:\n",comp1)

import numpy as np我们正在导入具有别名的 NumPy 库 – np.

在第三行中,我们创建一个二维数组,其中包含一个正无穷值。该关键字np.inf用于创建正无穷大值。该数组存储在一个名为 a 的变量中。

在第四行中,我们创建一个二维数组,该数组存储在名为 b 的新变量中。

在下一行中,我们将第一个数组打印到屏幕上。

print("-"*15)用作分隔符。它在屏幕上打印 15 个连字符 (-)。

在第 7 行中,我们将第二个数组打印到屏幕上。

print("-"*15)用作分隔符。它在屏幕上打印 15 个连字符 (-)。

现在我们有两个数组 a 和 b。但我们需要用某个数字替换正无穷大值。可以使用np.nan_to_num方法通过传递我们需要修改的数组 (a) 和我们希望替换无穷大的数字(在本例中为 12)来完成。posinf用于指定我们给出的数字是正数。

修改后的数组存储在 a1 中并作为参数传递给函数multi_dot

点积的结果存储在 comp1 中并在第 14 行打印。

输出是:

点积2

让我们看看点积是否适用于负值。

代码如下所示。

import numpy as np
#creating arrays
a=np.array([[3,6],[4,5]])
b=np.array([[5,-np.inf],[7,8]])
print("The first array is:\n",a)
print("-"*15)
print("The second array is :\n",b)
print("-"*15)
#converting the infintiy values to some number
b1=np.nan_to_num(b,neginf=-13)
print("Modified array :\n",b1)
print("*"*15)
comp2=np.linalg.multi_dot([a,  b1])
print("The dot product of two arrays is:\n",comp2)

import numpy as np我们正在导入具有别名的 NumPy 库 – np.

在第三行中,我们创建一个二维数组,该数组存储在一个名为 a 的新变量中。

在第四行中,我们创建一个二维数组,其中包含一个负无穷值。关键字 –np.inf用于创建负无穷大值。该数组存储在名为 b 的变量中。

在下一行中,我们将第一个数组打印到屏幕上。

print("-"*15)用作分隔符。它在屏幕上打印 15 个连字符 (-)。

在第 7 行中,我们将第二个数组打印到屏幕上。

print("-"*15)用作分隔符。它在屏幕上打印 15 个连字符 (-)。

我们需要用某个数字替换负无穷大值。可以使用np.nan_to_num方法通过传递我们需要修改的数组 (b) 和我们希望替换无穷大的数字(在本例中为 -13)来完成。neginf用于指定我们给出的数字是负数。

修改后的数组存储在 b1 中并作为参数传递给函数multi_dot

点积的结果存储在 comp1 中并在第 14 行打印。

计算的点积如下:

点积3

三个三维数组的点积

让我们考虑三个 3×3 维度的矩阵。

这是代码。

import numpy as np
#creating three matrices
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("First 3x3 matrix:\n",a)
print("-"*15)
b = np.array([[9, 0,1], [1, 5, 4], [8,1,0]])
print("Second 3x3 matrix:\n",b)
print("-"*15)
c = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
print("Third 3x3 matrix:\n",c)
print("*"*15)
#calculating the dot product
comp3 = np.linalg.multi_dot([a,b,c])
print("The dot product is:")
print(comp3)

在第一行中,我们将 NumPy 库引入到环境中。

三维数组可以被认为是三个列表组合在一起形成一个矩阵。

在第三行中,我们创建第一个数组并将其存储在变量 a 中。

在下一行中,我们在屏幕上打印数组。\n是一个换行符。之后的所有参数都\n 打印在新行中。

print("-"*15):该行用于创建分隔符并在屏幕上输出 15 个连字符 (-)。

以下行用于创建存储在 b 中的第二个矩阵。

我们正在屏幕上打印新的数组。

我们正在创建第三个数组并将其存储在第九行中名为 c 的变量中,

第 13 行计算三个数组(a、b 和 c)的点积,并将其存储在名为 comp3 的变量中。

最后,我们在第 14 行打印结果。

输出如下所示。

点积4

np.dot 和 multi_dot 所花费的执行时间

让我们比较一下两种方法的执行时间:np.dotmulti_dot

这是代码np.dot

1
2
3
4
5
6
7
8
9
10
11
12
#using np.dot
import numpy as np
#Creating arrays
a = np.array([[1, 3], [4, 6]])
b = np.array([[5, 6], [7, 9]])
c = np.array([[6, 1], [3, 4]])
#computing the dot product
comp1 = np.dot(a, b)
res=np.dot(comp1,c)
print("Dot products of these 3 arrays is:")
print(res)
%timeit np.dot(a,b,c)

我们分别在第 4,5 和 6 行创建三个数组 a、b 和 c。

由于我们使用的是np.dot,因此我们无法立即将所有三个数组作为参数传递给函数。因此,我们计算前两个数组(a 和 b)的点积,并将结果存储在名为 comp1 的变量中。

现在, comp1 和数组 c 作为参数传递给np.dot,三个矩阵的点积存储在 res 中。

在第 11 行,我们打印结果。

np.dot在第 12 行中,我们正在计算使用 magic 命令的执行时间%timeit

输出如下所示。

np.dot 的时间

正如您所看到的,所花费的时间np.dot不到 3 微秒。

让我们看看 的代码multi_dot

1
2
3
4
5
6
7
8
9
10
11
#using multi_dot
import numpy as np
#Creating arrays
a = np.array([[1, 3], [4, 6]])
b = np.array([[5, 6], [7, 9]])
c = np.array([[6, 1], [3, 4]])
#computing the dot product
comp2 = np.linalg.multi_dot([a, b, c])
print("Dot products of these 3 arrays is:")
print(comp2)
%timeit np.linalg.multi_dot([a, b, c])

我们分别在第 4,5 和 6 行创建三个数组 a、b 和 c。

由于我们使用的是multi_dot,因此我们不需要多次计算点积。我们可以将所有三个数组传递给函数并在单个函数调用中获得点积。

结果存储在名为 comp2 的变量中。

在最后一行,我们检查multi_dotusing 的执行时间%timeit

多点时间

从两个输出中观察到,multi_dot花费的时间几乎是 的 2 倍np.dot


结论

我们已经了解了什么是点积以及multi_dot函数如何使我们能够在单个函数调用中计算两个或多个数组的点积。我们还看到了 的语法multi_dot()

在第一个示例中,我们计算了两个二维大小的简单矩阵的点积。

接下来,我们了解了当一个数组具有无限值(正值和负值)时如何计算点积。

我们还看到了三维数组点积的计算。

最后,我们比较了np.dotmulti_dot虽然multi_dot可以帮助我们在一次调用中计算两个或多个数组的点积,但np.dot执行时间要少得多。

因此,可以肯定地说,np.dot和之间的选择multi-dot取决于用例和数组的大小。

如果数组很简单并且维度较小,np.dot则可以使用它们。但如果数组的维度更高(例如 4d),我们需要选择multi_dot.

参考

linalg.multi_dot 的官方 NumPy 手册。

关于timeit模块使用的堆栈溢出问题。