![程序员数学:用Python学透线性代数和微积分](https://wfqqreader-1252317822.image.myqcloud.com/cover/548/42617548/b_42617548.jpg)
3.3 点积:测量向量对齐
我们已经见过的一种向量乘法是标量乘法,将一个标量(实数)和一个向量结合起来,得到一个新的向量。不过还没有讨论过任何将向量相乘的方法。实际上,有两种重要的方法可以做到这一点,二者都提供了重要的几何学见解。一种叫作点积,使用点运算符书写(例如,);另一种叫作向量积(例如,
)。对于数来说,这些符号的意思是一样的,如3·4 = 3 × 4。对于两个向量来说,运算
和
不仅仅有不同的符号,而且代表的意义完全不同。
点积取两个向量并返回一个标量(数),而向量积取两个向量并返回另一个向量。然而,使用这两种运算都可以推断出三维空间中向量的长度和方向。我们首先从点积开始介绍。
3.3.1 绘制点积
点积(也叫内积)是对两个向量的运算,返回一个标量。换句话说,给定两个向量和
,那么
的结果是实数。点积适用于二维、三维等任意维度的向量。它可以被看作测量输入向量对的“对齐程度”。首先来看看
平面上的一些向量,以及它们的点积,以便对这个运算有一些直观的认识。
向量和
的长度分别为4和5,而且方向几乎相同。它们的点积为正,意味着它们是对齐的(见图3-24)。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/291.jpg?sign=1738883920-X8YnJNjfdKuStPVLk1yaxFbYGmfK8E2x-0-76bfa501611b2443b175b4dd5fc23ab2)
图3-24 大致对齐的两个向量给出一个大的正点积
指向相似方向的两个向量的点积为正,并且向量越大,乘积就越大。对于同样对齐的较短向量,点积较小但仍然是正的。新向量和
的长度都是2(见图3-25)。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/292.jpg?sign=1738883920-Tdi8pTEH6NfMXIXRFs2glho7A5MjHMZ0-0-cdf63c8c7de3707a479d5427877a09fd)
图3-25 指向相似方向的两个较短向量,点积较小但仍为正
相反,如果两个向量指向相反或大致相反的方向,则其点积为负(见图3-26和图3-27)。向量越长,则点积的负值越小。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/293.jpg?sign=1738883920-rZqhEQUrTieZnMqJs1sUc58e7S58Rkk4-0-c393e0eea611f0928fd7cefd8e7af64c)
图3-26 指向相反方向的向量点积为负
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/294.jpg?sign=1738883920-MV7aCXWibTxzL8AZ05D7x089lOfBuYb1-0-0c631d148ef7579b50d3deabff873090)
图3-27 指向相反方向的较短向量,点积较大但仍为负数
并非所有的向量对都明确地指向相似或相反的方向,点积可以检测这一点。如图3-28所示,如果两个向量的方向完全垂直,那么无论它们的长度如何,点积都是零。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/295.jpg?sign=1738883920-oUHiZs25L0yG5vtVsJEExXLlTM3O9dTN-0-0e29cd1a019e7c5fdce05582559e64b2)
图3-28 垂直向量的点积总是为零
这就是点积最重要的应用之一:在不做任何三角运算的情况下,计算两个向量是否垂直。这种垂直的情况也可以用来区分其他情况:如果两个向量的夹角小于90°,则向量的点积为正;如果夹角大于90°,则向量的点积为负。虽然还没有讲到计算点积的方法,但你现在知道如何解释这个值了。接下来介绍如何计算它。
3.3.2 计算点积
给定两个向量的坐标,有一个计算点积的简单公式:将相应的坐标相乘,然后将乘积相加。例如,在点积 (1, 2, -1)·(3, 0, 3) 中,坐标的乘积为3,
坐标的乘积为0,
坐标的乘积为-3,因为相加为 3 + 0 + (-3) = 0,所以点积为零。如果我说得没错,这两个向量应该是垂直的。如果绘制它们并从正确的角度去看,就能证明这一点(见图3-29)。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/296.jpg?sign=1738883920-GU8X9yZRSuV5m7XjF714XKd40ovEPeTp-0-472d082833ef8d46380480b20bb6f462)
图3-29 点积为零的两个向量在三维空间中确实是垂直的
在三维空间中,我们的视角可能有误导性,这使得计算出向量的相对方向比目测更有价值。再看一个示例,图3-30显示了二维向量(2, 3)和(4, 5)在平面上具有相似的方向。
坐标的乘积是2·4 = 8,而
坐标的乘积是3·5 = 15。8 + 15 = 23就是点积的结果。这个结果是一个正数,证实了向量的夹角小于90°。它们在三维空间中可以表示为恰好位于
平面内的向量(2, 3, 0)和(4, 5, 0)。但是无论在二维平面还是三维空间中,它们的相对几何性质是不变的。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/297.jpg?sign=1738883920-KaPHz0ichD2cjY6jtO0tpwKSSHkz07qI-0-e53650281db20e01f048c705ccda49a8)
图3-30 计算点积的另一个示例
在Python中,可以实现一个点积函数来处理任意一对(只要它们的坐标数目相同即可)输入向量。例如:
def dot(u,v):
return sum([coord1 * coord2 for coord1,coord2 in zip(u,v)])
这段代码使用Python的zip
函数对相应的坐标进行配对,然后在推导式中将每对坐标相乘,并添加到结果列表中。下面就借助它,进一步探索点积的行为。
3.3.3 点积的示例
位于不同轴上的两个向量的点积为零并不奇怪。这说明它们是垂直的。
>>> dot((1,0),(0,2))
0
>>> dot((0,3,0),(0,0,-5))
0
我们还可以证实,向量越长,其点积的绝对值越大。例如,将任意一个输入向量乘以2,点积的输出就会翻倍。
>>> dot((3,4),(2,3))
18
>>> dot(scale(2,(3,4)),(2,3))
36
>>> dot((3,4),scale(2,(2,3)))
36
这说明,点积的绝对值与其输入向量的长度成正比。如果取同方向两个向量的点积,那么点积就等于两个向量长度的乘积。例如,(4, 3)的长度为5,(8, 6)的长度为10,所以二者的点积等于5·10。
>>> dot((4,3),(8,6))
50
当然,点积并不总是等于其输入向量长度的乘积。如图3-31所示,向量(5, 0)、(-3, 4)、(0, -5)和(-4, -3)的长度都是5,但它们与原始向量(4, 3)的点积是不同的。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/298.jpg?sign=1738883920-jP02kQf0O0NADGqLMroaSmsFWGvtmZHu-0-cf747f37b8081f266ff5e44279e52ad1)
图3-31 由于方向不同,相同长度的向量与向量 (4, 3)有不同的点积
两个长度为5的向量的点积范围是-25~25:当它们指向相反方向时,点积为-25;当它们对齐时,点积为5·5 = 25。在3.3.5节的练习中你会发现,两个向量的点积范围是长度乘积到长度乘积的负值。
3.3.4 用点积测量角度
我们已经知道,点积是根据两个向量的夹角而变化的。具体来说,当夹角角度为0到180°时,点积的取值范围是
和
长度乘积的1到-1倍。我们已经见过具有这样特征的函数,即余弦函数。其实点积还有另一个公式。如果
和
分别表示向量
和
的长度,那么点积的计算公式为:
是向量
和
之间的角度。原则上,这提供了一种计算点积的新方法。通过测量两个向量的长度和它们之间的角度,就可以得到点积的结果。如图3-32所示,假设已知有两个长度分别为3和2的向量,并使用量角器测量出它们的夹角是75°。
![](https://epubservercos.yuewen.com/8EA7F4/22124474309908206/epubprivate/OEBPS/Images/302.jpg?sign=1738883920-P41mH51Bny7sN8hKF5ycueLlPLWo06IU-0-e848b67892343521668cd483a9283fa1)
图3-32 长度分别为3和2的两个向量,夹角为75°
图3-32中两个向量的点积为。通过适当的弧度转换,我们可以使用Python计算出这个值约为1.55。
>>> from math import cos,pi
>>> 3 * 2 * cos(75 * pi / 180)
1.5529142706151244
在使用向量进行计算时,更常见的是基于坐标来计算角度。我们可以结合这两个公式来算出一个角:首先使用坐标计算向量的点积和长度,然后求解角度。
让我们找出向量(3, 4)和(4, 3)之间的角度。它们的点积是24,向量长度都是5。从新的点积公式可以得出:
可以将简化成
。使用Python的
math.acos
库,可以得到值约为0.284弧度或16.3°,其余弦值为24/25。
这个练习提醒了我们,为什么在二维平面上不需要点积。第2章展示了如何得到向量与轴正方向之间的角度。创造性地使用那个公式,可以在平面上找到我们想要的任意角度。点积在三维空间中才真正开始发挥作用,因为三维空间中的坐标变换对测量角度的帮助并不大。
例如,我们可以用同样的公式来求(1, 2, 2)和(2, 2, 1)之间的角度。它们的点积是1·2 + 2·2 + 2·1 = 8,向量长度都是3。这意味着,所以
,
约为0.476弧度或27.3°。
这个过程在二维平面或三维空间中是一样的,将被反复使用。通过实现Python函数来求两个向量之间的角度可以节省一些精力。因为dot
函数和length
函数中都没有硬编码维数,所以这个新函数也不会。利用这个公式可得:
以及
第二个公式可以被直接翻译成如下Python代码。
def angle_between(v1,v2):
return acos(
dot(v1,v2) /
(length(v1) * length(v2))
)
这段Python代码没有依赖向量和
的维数。它们既可以是包含2个坐标的元组,也可以是包含3个坐标的元组(实际上,还可以是包含4个或更多坐标的元组,我们将在后面的章节中讨论)。相比之下,接下来要说的向量积(外积、叉积)只在三维空间中有效。
3.3.5 练习
练习3.11:根据图3-33,将
、
和
从大到小排列。
![]()
图 3-33
解:乘积
是唯一正的点积,因为
和
是唯一一对夹角小于直角的向量对。此外,
比
更小(更负),因为
既大又离
更远,所以
。
练习3.12:(-1, -1, 1)和(1, 2, 1) 的点积是多少?这两个三维向量的夹角是大于90°、小于 90°,还是正好等于90°?
解:(-1, -1, 1)和(1, 2, 1)的点积为-1·1 + -1·2 + 1·1 = -2。因为结果是负数,所以两个向量之间的角度超过90°。
练习3.13(小项目):对于两个三维向量
和
,
和
的值都等于
。在这种情况下,
,而
和
都是36,是原结果的2倍。请证明这个规则对于任意实数
都适用,而不仅仅是2。换句话说,请证明对于任意
,
和
的值都等于
。
解:设
和
的坐标为
和
,那么
。因为
,
,我们可以通过展开点积来计算。
![]()
上式证明了标量乘法会对点积的结果进行相应的缩放处理。
另一个点积同理,以下公式证明了同样的事实。
练习3.14(小项目):用代数证明向量与其自身的点积是其长度的平方。
解:如果一个向量的坐标是
,那么它与自身的点积是
,确实是其长度
的平方。
练习3.15(小项目):找出长度为3的向量
和长度为7的向量
,使
。再找出一对向量
和
,使
。最后,再找出三对长度分别为3和7的向量,并证明它们的长度都在-21和21之间。
解:两个方向相同的向量(例如,沿
轴正方向)具有最高的点积。
>>> dot((3,0),(7,0)) 21
两个方向相反的向量(例如,分别沿
轴正负方向)具有最低的点积。
>>> dot((0,3),(0,-7)) -21
利用极坐标,可以很容易地再生成一些长度为3和7的任意角度的向量。
from vectors import to_cartesian from random import random from math import pi def random_vector_of_length(l): return to_cartesian((l, 2 *pi*random())) pairs = [(random_vector_of_length(3), random_vector_of_length(7)) for i in range(0,3)] for u,v in pairs: print("u = %s, v = %s" % (u,v)) print("length of u: %f, length of v: %f, dot product :%f" % (length(u), length(v), dot(u,v)))
练习3.16:设
和
是向量,其中
,
。如果
和
的夹角是101.3°,那么
是什么?
(a) 5.198
(b) 5.098
(c) -1.019
(d) 1.019
解:同样可以将这些值代入新的点积公式,并通过适当的弧度转换,使用Python计算结果。
>>> 3.61 * 1.44 * cos(101.3 * pi / 180) -1.0186064362303022
四舍五入到小数点后三位,答案与(c)一致。
练习3.17(小项目):通过把(3, 4)和(4, 3)转换为极坐标并取角的差值,来求出它们之间的角度。答案是以下哪一个?
(a) 1.569
(b) 0.927
(c) 0.643
(d) 0.284
提示:结果应与点积公式求得的值一致。
解:因为从
轴正半轴开始沿逆时针方向看,向量(3, 4)比(4, 3)距离更远,所以用(3, 4)的角度减去(4, 3)的角度就能得到答案。结果与答案(d)完全吻合。
>>> from vectors import to_polar >>> r1,t1 = to_polar((4,3)) >>> r2,t2 = to_polar((3,4)) >>> t1-t2 -0.2837941092083278 >>> t2-t1 0.2837941092083278
练习3.18:(1, 1, 1)与(-1, -1, 1)之间的角是多少度?
(a) 180°
(b) 120°
(c) 109.5°
(d) 90°
解:两个向量的长度都是
,约等于1.732。它们的点积是1·(-1) + 1·(-1) + 1·= -1,即
。所以,
。由此可求得这个角约为1.911弧度或109.5°(答案是(c))。