在 Python 中乘法矩阵的 3 种方法

已发表: 2022-05-09

在本教程中,您将学习如何在 Python 中将两个矩阵相乘

您将从学习有效矩阵乘法的条件开始,并编写一个自定义 Python 函数来乘法矩阵。 接下来,您将看到如何使用嵌套列表推导式获得相同的结果。

最后,您将继续使用 NumPy 及其内置函数更有效地执行矩阵乘法。

如何检查矩阵乘法是否有效

在编写矩阵乘法的 Python 代码之前,让我们重温一下矩阵乘法的基础知识。

仅当矩阵A中的列数等于矩阵B中的行数时,两个矩阵 A 和 B 之间的矩阵乘法才有效。

您之前可能遇到过矩阵乘法的这种情况。 然而,你有没有想过为什么会这样?

嗯,这是因为矩阵乘法的工作方式。 看看下面的图片。

在我们的通用示例中,矩阵 A 有m行和n列。 矩阵 B 有np列。

矩阵乘法

产品矩阵的形状是什么?

结果矩阵 C 中索引 (i, j) 处的元素是矩阵 A 的第 i 行和矩阵 B 的第 j 列的点积。

因此,要在结果矩阵 C 中的特定索引处获取元素,您必须分别计算矩阵 A 和 B 中相应行和列的点积。

重复上述过程,您将得到形状为mxp的乘积矩阵 C — mp列,如下所示。

产品矩阵

并且两个向量ab之间的点积或内积由以下等式给出。

点积

现在总结一下:

  • 很明显,点积仅在相等长度的向量之间定义。
  • 因此,要使行和列之间的点积有效——当两个矩阵相乘时——你需要它们都具有相同数量的元素。
  • 在上面的通用示例中,矩阵 A 中的每一行都有n 个元素。 矩阵 B 中的每一列也有n 个元素。

仔细看, n是矩阵A的列数,也是矩阵B的行数。这正是为什么需要矩阵A的列数等于数字的原因矩阵B中的行数

我希望您了解矩阵乘法有效的条件以及如何获取乘积矩阵中的每个元素。

让我们继续编写一些 Python 代码来将两个矩阵相乘。

编写一个自定义 Python 函数来乘以矩阵

作为第一步,让我们编写一个自定义函数来乘以矩阵。

此功能应执行以下操作:

  • 接受两个矩阵 A 和 B 作为输入。
  • 检查 A 和 B 之间的矩阵乘法是否有效。
  • 如果有效,则将两个矩阵 A 和 B 相乘,并返回乘积矩阵 C。
  • 否则,返回矩阵 A 和 B 不能相乘的错误消息。

第 1 步使用 NumPy 的random.randint()函数生成两个整数矩阵。 您还可以将矩阵声明为嵌套的 Python 列表。

 import numpy as np np.random.seed(27) A = np.random.randint(1,10,size = (3,3)) B = np.random.randint(1,10,size = (3,2)) print(f"Matrix A:\n {A}\n") print(f"Matrix B:\n {B}\n") # Output Matrix A: [[4 9 9] [9 1 6] [9 2 3]] Matrix B: [[2 2] [5 7] [4 4]]

第 2 步:继续定义函数multiply_matrix(A,B) 。 此函数将两个矩阵AB作为输入,如果矩阵乘法有效,则返回乘积矩阵C

 def multiply_matrix(A,B): global C if A.shape[1] == B.shape[0]: C = np.zeros((A.shape[0],B.shape[1]),dtype = int) for row in range(rows): for col in range(cols): for elt in range(len(B)): C[row, col] += A[row, elt] * B[elt, col] return C else: return "Sorry, cannot multiply A and B."

解析函数定义

让我们继续解析函数定义。

将 C 声明为全局变量:默认情况下,Python 函数内的所有变量都具有局部作用域。 而且您无法从函数外部访问它们。 为了使乘积矩阵 C 可以从外部访问,我们必须将其声明为全局变量。 只需在变量名之前添加global限定符。

检查矩阵乘法是否有效:使用shape属性检查 A 和 B 是否可以相乘。 对于任何数组arrarr.shape[0]arr.shape[1]分别给出行数和。 因此if A.shape[1] == B.shape[0]检查矩阵乘法是否有效。 仅当此条件为True时,才会计算乘积矩阵。 否则,该函数将返回错误消息。

使用嵌套循环计算值:为了计算结果矩阵的元素,我们必须遍历矩阵 A 的行,外部for循环执行此操作。 内部for循环帮助我们遍历矩阵 B 的列。最里面for循环帮助访问所选列中的每个元素。

️ 现在我们已经了解了 Python 函数乘以矩阵的工作原理,让我们用我们之前生成的矩阵 A 和 B 调用该函数。

 multiply_matrix(A,B) # Output array([[ 89, 107], [ 47, 49], [ 40, 44]])

由于 A 和 B 之间的矩阵乘法有效,因此函数multiply_matrix()返回乘积矩阵 C。

使用 Python 嵌套列表理解将矩阵相乘

在上一节中,您编写了一个 Python 函数来乘以矩阵。 现在,您将看到如何使用嵌套列表推导来做同样的事情。

这是乘法矩阵的嵌套列表理解。

嵌套列表理解矩阵乘法

起初,这可能看起来很复杂。 但我们将逐步解析嵌套列表推导。

让我们一次只关注一个列表理解并确定它的作用。

我们将使用以下通用模板进行列表理解:

 [<do-this> for <item> in <iterable>] where, <do-this>: what you'd like to do—expression or operation <item>: each item you'd like to perform the operation on <iterable>: the iterable (list, tuple, etc.) that you're looping through

️ 查看我们的指南 List Comprehension in Python – with Examples 以获得深入的理解。

在继续之前,请注意,我们希望一次构建结果矩阵 C一行

嵌套列表理解解释

第 1 步:计算矩阵 C 中的单个值

给定矩阵 A 的第 i 行和矩阵 B 的第 j 列,下面的表达式给出矩阵 C 中索引 (i, j) 处的条目。

 sum(a*b for a,b in zip(A_row, B_col) # zip(A_row, B_col) returns an iterator of tuples # If A_row = [a1, a2, a3] & B_col = [b1, b2, b3] # zip(A_row, B_col) returns (a1, b1), (a2, b2), and so on

如果 i = j = 1 ,表达式将返回矩阵 C 的条目c_11 。因此您可以通过这种方式在一行中获取一个元素。

第 2 步:在矩阵 C 中构建一行

我们的下一个目标是构建一整行。

对于矩阵 A 中的第 1 行,您必须遍历矩阵 B 中的所有列以在矩阵 C 中获得完整的一行。

回到列表理解模板。

  • <do-this>替换为步骤 1 中的表达式,因为那是您想要做的。
  • 接下来,将<item>替换为B_col — 矩阵 B 中的每一列。
  • 最后,将<iterable>替换为zip(*B) — 包含矩阵 B 中所有列的列表。

这是第一个列表理解。

 [sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] # zip(*B): * is the unzipping operator # zip(*B) returns a list of columns in matrix B

步骤 3:构建所有行并获得矩阵 C

接下来,您必须通过计算其余行来填充乘积矩阵 C。

为此,您必须遍历矩阵 A 中的所有行。

再次返回列表推导,然后执行以下操作。

  • <do-this>替换为步骤 2 中的列表推导式。回想一下,我们在上一步中计算了整行。
  • 现在,将<item>替换为A_row矩阵 A 中的每一行。
  • 而您的<iterable>就是矩阵 A 本身,因为您正在遍历它的行。

这是我们最终的嵌套列表理解。

 [[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] for A_row in A]

是时候验证结果了!

 # cast into NumPy array using np.array() C = np.array([[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] for A_row in A]) # Output: [[ 89 107] [ 47 49] [ 40 44]]

如果你仔细观察,这相当于我们之前的嵌套 for 循环——只是它更简洁。

您还可以使用一些内置函数更有效地执行此操作。 让我们在下一节中了解它们。

在 Python 中使用 NumPy matmul() 对矩阵进行乘法运算

np.matmul()将两个矩阵作为输入,如果输入矩阵之间的矩阵乘法有效,则返回乘积。

 C = np.matmul(A,B) print(C) # Output: [[ 89 107] [ 47 49] [ 40 44]]

请注意,此方法比我们之前学习的两种方法更简单。 实际上,您可以使用等效的 @ 运算符代替np.matmul() ,我们马上就会看到。

如何在 Python 中使用 @ 运算符对矩阵进行乘法运算

在 Python 中, @是用于矩阵乘法的二元运算符。

它对两个矩阵进行运算,通常是 N 维 NumPy 数组,并返回乘积矩阵。

注意:您需要 Python 3.5 及更高版本才能使用@运算符。

这是您可以使用它的方法。

 C = [email protected] print(C) # Output array([[ 89, 107], [ 47, 49], [ 40, 44]])

请注意,乘积矩阵 C 与我们之前获得的相同。

你可以使用 np.dot() 来乘法矩阵吗?

如果您曾经遇到过使用np.dot()将两个矩阵相乘的代码,那么它是这样工作的。

 C = np.dot(A,B) print(C) # Output: [[ 89 107] [ 47 49] [ 40 44]]

您会看到np.dot(A, B)还返回预期的产品矩阵。

但是,根据 NumPy 文档,您应该只使用np.dot()来计算两个一维向量的点积,而不是矩阵乘法。

回想一下上一节,乘积矩阵 C 的索引 (i, j) 处的元素是矩阵 A 的第 i 行和矩阵 B 的第 j 列的点积。

由于 NumPy 将此点积运算隐式广播到所有行和所有列,因此您将得到结果乘积矩阵。 但是为了保持代码可读性并避免歧义,请改用np.matmul()@运算符。

结论

在本教程中,您学习了以下内容。

  • 矩阵乘法有效的条件:矩阵A中的数 = 矩阵B中的数。
  • 如何编写一个自定义 Python 函数来检查矩阵乘法是否有效并返回乘积矩阵。 函数体使用嵌套的 for 循环。
  • 接下来,您学习了如何使用嵌套列表推导来乘以矩阵。 它们比 for 循环更简洁,但容易出现可读性问题。
  • 最后,您学会了使用 NumPy 内置函数 np.matmul() 来乘法矩阵,以及这在速度方面如何最有效。
  • 您还了解了在 Python 中使用@运算符将两个矩阵相乘。

这结束了我们关于 Python 中的矩阵乘法的讨论。 下一步,学习如何在 Python 中检查一个数字是否为素数。 或者解决有关 Python 字符串的有趣问题。

快乐学习!