第 2 章 向量:带方向的量
学习目标
- 区分标量与向量,理解「向量 = 大小 + 方向」
- 掌握向量的两种表示:几何表示(有向线段)与代数表示(坐标数组)
- 理解向量相等与位置向量
- 理解零向量与负向量
- 会用 NumPy 表示向量,用 matplotlib 画向量
2.1 为什么需要向量
第 1 章我们学过的数,都是标量:只描述大小,不描述方向。身高 160 厘米、体重 50 千克、温度 25 摄氏度,这些量一个数就够了。
但有些量只说大小不够。老师说「放学后向东走 3 千米」,你必须知道向东这个方向,才能走到家;只说「走 3 千米」,东西南北都可以,等于没说。风是「北风 4 级」,力是「向右拉 10 牛」——这些量都有两个属性:
- 大小:3 千米、4 级、10 牛;
- 方向:东、北、向右。
既有大小又有方向的量,叫向量。只讲大小不讲方向的量,叫标量。
定义先行:向量是既有大小又有方向的量;标量是只有大小没有方向的量。
本书讨论二维平面与三维空间中的向量,但向量的思想(拆成分量、按分量运算)可以推广到任意维度——这正是后面矩阵和线性代数要干的事。
2.2 向量的几何表示:有向线段
在纸上,向量画成一条带箭头的线段:起点叫始点,终点叫终点,箭头指向终点,箭头的方向就是向量的方向,线段的长度就是向量的大小(也叫模)。

从点 到点 的向量,记作 。注意箭头的方向很重要: 与 大小相同、方向相反,是两个不同的向量。
向量的名字除了用两个端点,还可以用一个字母加箭头,比如 ;本书中向量统一用加粗的小写字母 表示,和普通数字 区分开。
2.3 向量相等:只看大小和方向
两个向量什么时候相等?大小相等,且方向相同——与起点在哪里无关。

图中的三个箭头,起点分别是 、、,但都是「向右 3 格、向上 2 格」,所以它们是同一个向量。就像「向东 3 千米」,不管从哪个城市出发,这个描述本身都一样。
位置向量是特例:起点固定在原点 的向量。任何一个向量 ,都可以平移,让起点落在原点,得到一个位置向量——这个位置向量的终点坐标 就是该向量唯一的坐标表示。
2.4 向量的坐标表示:从有向线段到数组
把向量放到坐标平面上:起点是 ,终点是 。那么从 到 的位移是:
即「横坐标的差、纵坐标的差」。例如 到 :
这个 的意思是:从 出发,向右走 3 格,再向上走 2 格,就到了 。它只与「怎么走」有关,与起点无关——这正好和 2.3 的结论一致:向量是「位移」,不是「位置」。
位置向量的坐标表示最简单:起点是 ,终点是 ,所以位置向量就是 本身。
在 NumPy 里,向量就是一个长度为 2 的数组:
import numpy as np
# 位置向量 (3, 2):向右 3,向上 2
v = np.array([3.0, 2.0])
print("v =", v)
print("维度 ndim =", v.ndim) # 1 维
print("长度 shape =", v.shape) # (2,),两个分量
print("分量 v[0] =", v[0], ", v[1] =", v[1])运行输出:
v = [3. 2.]
维度 ndim = 1
长度 shape = (2,)
分量 v[0] = 3.0 , v[1] = 2.0两个数 、 叫向量的分量(component)。分量就是坐标,只不过用数组装起来以后,以后可以放 3 个、4 个、100 个分量——二维、三维乃至更高维的向量,用同一套代码处理。
PyTorch 里用法几乎一样,后续章节会大量使用:
import torch
v = torch.tensor([3.0, 2.0])
print("torch v =", v)
print("类型 dtype =", v.dtype)运行输出:
torch v = tensor([3., 2.])
类型 dtype = torch.float322.5 零向量与负向量
零向量是大小为零、方向不确定的向量(习惯上认为它没有方向),记作 :
零向量对应的位移是「原地不动」。
负向量: 的负向量是
大小与 相同,方向正好相反——「向东 3 千米」的相反方向就是「向西 3 千米」。
import numpy as np
v = np.array([3.0, 2.0])
print("v =", v)
print("-v =", -v)
print("零向量:", np.zeros(2))运行输出:
v = [3. 2.]
-v = [-3. -2.]
零向量: [0. 0.]2.6 用 matplotlib 画向量
matplotlib 的 quiver 可以画带箭头的线段。把同一个向量 从原点、、 三个不同的起点画出来,你会看到三根平行且等长的箭头——它们是同一个向量:
import matplotlib.pyplot as plt
from matplotlib import font_manager
for f in font_manager.findSystemFonts():
if any(k in f for k in ("NotoSansCJK", "NotoSansSC", "wqy", "SimHei", "msyh", "PingFang")):
font_manager.fontManager.addfont(f)
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "WenQuanYi Zen Hei", "SimHei", "Microsoft YaHei", "PingFang SC"]
plt.rcParams["axes.unicode_minus"] = False
import numpy as np
v = np.array([3.0, 2.0])
starts = [np.array([0.0, 0.0]), np.array([1.0, 1.0]), np.array([-2.0, 0.0])]
labels = ["起点 O", "起点 A", "起点 C"]
colors = ["tab:red", "tab:blue", "tab:green"]
fig, ax = plt.subplots(figsize=(6, 6))
ax.axhline(0, color="black", linewidth=1)
ax.axvline(0, color="black", linewidth=1)
ax.grid(True, linestyle=":", alpha=0.5)
ax.set_xlim(-3.5, 5)
ax.set_ylim(-1.5, 5)
ax.set_aspect("equal")
for s, label, c in zip(starts, labels, colors):
ax.quiver(s[0], s[1], v[0], v[1], angles="xy", scale_units="xy", scale=1,
color=c, width=0.012)
ax.annotate(label, s, textcoords="offset points", xytext=(-24, -14), color=c)
ax.annotate("v = (3, 2)", (1.8, 3.2), color="tab:red", fontsize=13)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_title("同一个向量,不同的起点")
fig.savefig("book/public/figs/fig02-equal_vectors.png", dpi=120, bbox_inches="tight")
plt.close(fig)第一张图(2.2 的插图)画的是向量 的分量分解:
import matplotlib.pyplot as plt
from matplotlib import font_manager
for f in font_manager.findSystemFonts():
if any(k in f for k in ("NotoSansCJK", "NotoSansSC", "wqy", "SimHei", "msyh", "PingFang")):
font_manager.fontManager.addfont(f)
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "WenQuanYi Zen Hei", "SimHei", "Microsoft YaHei", "PingFang SC"]
plt.rcParams["axes.unicode_minus"] = False
import numpy as np
v = np.array([3.0, 2.0])
fig, ax = plt.subplots(figsize=(6, 6))
ax.axhline(0, color="black", linewidth=1)
ax.axvline(0, color="black", linewidth=1)
ax.grid(True, linestyle=":", alpha=0.5)
ax.set_xlim(-0.5, 4)
ax.set_ylim(-0.5, 3.5)
ax.set_aspect("equal")
# 向量本体
ax.quiver(0, 0, v[0], v[1], angles="xy", scale_units="xy", scale=1,
color="tab:red", width=0.02)
# 分量虚线:x 方向 3、y 方向 2
ax.plot([0, v[0]], [0, 0], color="tab:blue", linestyle="--")
ax.plot([v[0], v[0]], [0, v[1]], color="tab:green", linestyle="--")
ax.text(1.5, -0.3, "3", color="tab:blue", fontsize=13, ha="center")
ax.text(v[0] + 0.1, 0.9, "2", color="tab:green", fontsize=13)
ax.annotate("v = (3, 2)", (1.5, 1.4), color="tab:red", fontsize=14)
ax.scatter([0], [0], color="black", zorder=3)
ax.annotate("O", (0, 0), textcoords="offset points", xytext=(-14, -10))
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_title("向量 v = (3, 2):大小 1 格,方向向右上")
fig.savefig("book/public/figs/fig02-vector.png", dpi=120, bbox_inches="tight")
plt.close(fig)动手实践
- 说出下列量哪些是向量,哪些是标量:「体重 60 千克」「北风 5 级」「电梯下降 3 层」「从家到学校直线距离 2 千米」「向东偏南 30° 走 500 米」。
- 已知 、,写出向量 的坐标,再写 ,并解释两者有什么关系。
- 用 NumPy 表示 ,打印分量;再用
torch.tensor表示同样的向量。 - 修改 2.6 的代码,画一个从 指向 的向量,并标注它的坐标。
常见错误
| 错误写法/理解 | 原因 |
|---|---|
| 认为 与 相等 | 方向相反,不相等;它们互为负向量 |
| 把「位置」和「向量」混为一谈 | 位置是「点在哪」,向量是「怎么走」;同一个向量可以从不同起点出发 |
| 认为向量 必须从原点出发 | 坐标表示是「位移量」,与起点无关;位置向量才固定从原点出发 |
| 把向量长度当成分量个数 | v.shape 是 (2,),表示有 2 个分量;向量的「长度/大小」是模,第 4 章才学 |
章末练习
基础
- 写出从 到 的向量坐标;从 到 的向量坐标;比较两个向量,说明它们是否相等。
- 向量 的负向量是什么?画出 与 。
- 用 NumPy 创建向量 ,打印它的分量与 shape。
提高
- 一个向量从 出发,终点是 ;另一个向量从 出发,终点是 。它们相等吗?为什么?用代码验证两个「终点减起点」的结果。
- 若 ,且 ,求终点 的坐标。提示:终点坐标 = 起点坐标 + 向量坐标。
挑战
- 已知 ,写出它的模(大小)的表达式。提示:用 1.4 的距离公式,把起点放在原点。运行
np.linalg.norm(v)验证你的表达式。 - 在三维空间里,向量用三个分量 表示。猜测并验证:从 到 的向量坐标是什么?
np.array里三个分量表示它。
章末自测
- 下列哪个量是向量?
- A. 身高 160 厘米
- B. 向东 3 千米
- C. 体重 50 千克
- D. 温度 25 摄氏度
- 从 到 的向量 是?
- A.
- B.
- C.
- D.
- 向量 与下列哪个相等?
- A. 从 到 的向量
- B. 从 到 的向量
- C. 从 到 的向量
- D. 从 到 的向量
- 与 的关系是?
- A. 相等
- B. 互为负向量
- C. 没有关系
- D. 一个在 x 轴一个在 y 轴
- 零向量是?
- A. 没有方向的任何向量
- B. 大小为 0 的向量
- C. 长度为 0 的数组
- D. 以上都对
- 向量 的负向量是?
- A.
- B.
- C.
- D.
- NumPy 中
np.array([3.0, 2.0]).shape的结果是?- A.
2 - B.
(2,) - C.
[2] - D.
(1, 2)
- A.
- 「位置向量」的特点是?
- A. 终点在原点
- B. 起点在原点
- C. 大小等于 1
- D. 方向朝上
- 向量的「坐标表示」 的含义是?
- A. 从原点出发向右 2、向上 3
- B. 横方向移动 3、纵方向移动 2
- C. 长度是 3+2=5
- D. 终点一定是
torch.tensor([3.0, 2.0])的 dtype 通常是?- A.
torch.float32 - B.
torch.int64 - C.
torch.float64 - D.
torch.bool
- A.
