程序员数学:用Python学透线性代数和微积分
上QQ阅读APP看书,第一时间看更新

3.3 点积:测量向量对齐

我们已经见过的一种向量乘法是标量乘法,将一个标量(实数)和一个向量结合起来,得到一个新的向量。不过还没有讨论过任何将向量相乘的方法。实际上,有两种重要的方法可以做到这一点,二者都提供了重要的几何学见解。一种叫作点积,使用点运算符书写(例如,);另一种叫作向量积(例如,)。对于数来说,这些符号的意思是一样的,如3·4 = 3 × 4。对于两个向量来说,运算不仅仅有不同的符号,而且代表的意义完全不同。

点积取两个向量并返回一个标量(数),而向量积取两个向量并返回另一个向量。然而,使用这两种运算都可以推断出三维空间中向量的长度和方向。我们首先从点积开始介绍。

3.3.1 绘制点积

点积(也叫内积)是对两个向量的运算,返回一个标量。换句话说,给定两个向量,那么的结果是实数。点积适用于二维、三维等任意维度的向量。它可以被看作测量输入向量对的“对齐程度”。首先来看看平面上的一些向量,以及它们的点积,以便对这个运算有一些直观的认识。

向量的长度分别为4和5,而且方向几乎相同。它们的点积为正,意味着它们是对齐的(见图3-24)。

图3-24 大致对齐的两个向量给出一个大的正点积

指向相似方向的两个向量的点积为正,并且向量越大,乘积就越大。对于同样对齐的较短向量,点积较小但仍然是正的。新向量的长度都是2(见图3-25)。

图3-25 指向相似方向的两个较短向量,点积较小但仍为正

相反,如果两个向量指向相反或大致相反的方向,则其点积为负(见图3-26和图3-27)。向量越长,则点积的负值越小。

图3-26 指向相反方向的向量点积为负

图3-27 指向相反方向的较短向量,点积较大但仍为负数

并非所有的向量对都明确地指向相似或相反的方向,点积可以检测这一点。如图3-28所示,如果两个向量的方向完全垂直,那么无论它们的长度如何,点积都是零。

图3-28 垂直向量的点积总是为零

这就是点积最重要的应用之一:在不做任何三角运算的情况下,计算两个向量是否垂直。这种垂直的情况也可以用来区分其他情况:如果两个向量的夹角小于90°,则向量的点积为正;如果夹角大于90°,则向量的点积为负。虽然还没有讲到计算点积的方法,但你现在知道如何解释这个值了。接下来介绍如何计算它。

3.3.2 计算点积

给定两个向量的坐标,有一个计算点积的简单公式:将相应的坐标相乘,然后将乘积相加。例如,在点积 (1, 2, -1)·(3, 0, 3) 中,坐标的乘积为3,坐标的乘积为0,坐标的乘积为-3,因为相加为 3 + 0 + (-3) = 0,所以点积为零。如果我说得没错,这两个向量应该是垂直的。如果绘制它们并从正确的角度去看,就能证明这一点(见图3-29)。

图3-29 点积为零的两个向量在三维空间中确实是垂直的

在三维空间中,我们的视角可能有误导性,这使得计算出向量的相对方向比目测更有价值。再看一个示例,图3-30显示了二维向量(2, 3)和(4, 5)在平面上具有相似的方向。坐标的乘积是2·4 = 8,而坐标的乘积是3·5 = 15。8 + 15 = 23就是点积的结果。这个结果是一个正数,证实了向量的夹角小于90°。它们在三维空间中可以表示为恰好位于平面内的向量(2, 3, 0)和(4, 5, 0)。但是无论在二维平面还是三维空间中,它们的相对几何性质是不变的。

图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)的点积是不同的。

图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°。

图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))。