Skip to content

第 4 章 长度、点积与夹角

学习目标

  • 由勾股定理推导向量的模(长度)公式
  • 掌握单位向量的概念与求法
  • 掌握点积的两种定义,并理解它们为什么等价
  • 会由余弦定理推导点积的几何意义
  • 会用点积判断垂直、求夹角
  • 会推导并计算投影向量
  • 会用 NumPy 与 PyTorch 计算模、点积、夹角与投影

4.1 向量的模:长度公式

向量 (长度、大小)记作 。把起点放在原点,终点是 ,向量的长度就是原点到终点的距离——这正是第 1 章的两点间距离公式:

向量的模

也就是说,模公式就是勾股定理:水平分量 和竖直分量 是两条直角边,向量本身是斜边。

python
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, 4.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.5)
ax.set_ylim(-0.5, 5.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)
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.35, "x = 3", color="tab:blue", fontsize=12, ha="center")
ax.text(v[0] + 0.1, 1.8, "y = 4", color="tab:green", fontsize=12)
ax.annotate("‖v‖ = 5", (1.4, 2.5), color="tab:red", fontsize=14)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_title("模 = 勾股定理:3² + 4² = 5²")
fig.savefig("book/public/figs/fig04-length.png", dpi=120, bbox_inches="tight")
plt.close(fig)

三维向量 的模,是把它先投影到 平面再套一次勾股定理:

依此类推, 维向量 的模是所有分量平方和再开方:

NumPy 与 PyTorch 一行搞定:

python
import numpy as np

v = np.array([3.0, 4.0])
print("手动计算:", np.sqrt(3**2 + 4**2))
print("np.linalg.norm:", np.linalg.norm(v))

运行输出:

text
手动计算: 5.0
np.linalg.norm: 5.0
python
import torch

v = torch.tensor([3.0, 4.0])
print("torch.norm:", torch.norm(v))

运行输出:

text
torch.norm: tensor(5.)

4.2 单位向量:长度为 1 的「方向」本身

单位向量是模等于 1 的向量。它只表示方向,不携带大小信息。

任意非零向量 ,除以自己的模,就得到同方向的单位向量:

例:,,所以

python
import numpy as np

v = np.array([3.0, 4.0])
unit = v / np.linalg.norm(v)
print("单位向量:", unit)
print("它的模:", np.linalg.norm(unit))

运行输出:

text
单位向量: [0.6 0.8]
它的模: 1.0

两个最常用的单位向量是 轴方向的 轴方向的 。任何向量都能写成它们的「数乘之和」:

这行等式是第 5 章「线性组合」和第 11 章「基」的起点——先把这句话记住,后面会反复用到。

4.3 点积:定义与计算

点积(也叫内积数量积)是向量的一种乘法,结果是一个(标量),不是向量。两个二维向量:

「对应分量相乘,再全部相加」。例:

NumPy、PyTorch 的写法:

python
import numpy as np

u = np.array([1.0, 2.0])
w = np.array([3.0, 1.0])
print("np.dot:", np.dot(u, w))
print("u @ w:", u @ w)
print("手动:", u[0] * w[0] + u[1] * w[1])

运行输出:

text
np.dot: 5.0
u @ w: 5.0
手动: 5.0
python
import torch

u = torch.tensor([1.0, 2.0])
w = torch.tensor([3.0, 1.0])
print("torch.dot:", torch.dot(u, w))

运行输出:

text
torch.dot: tensor(5.)

4.4 点积的几何意义:余弦定理登场

分量定义好算,但它「是什么」?答案是:点积把长度夹角联系了起来。

先复习余弦定理。三角形的两边 夹着角 ,对边是 ,则

推导(锐角情形):过顶点作高 ,把底边分成 两段。由勾股定理,

(用到了 。)

现在把 放在同一起点,夹角为 。从 的终点指向 的终点的向量是 ,所以三角形三边是 。对三角形用余弦定理:

另一方面,直接用分量计算 :

两条路算出的是同一个量,右边对应相等,于是得到点积的几何意义:

其中 是两向量的夹角,取

点积与夹角

这条公式立刻带来三个重要结论:

python
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

u = np.array([4.0, 0.0])
w = np.array([2.0, 3.0])
theta = np.arccos(np.dot(u, w) / (np.linalg.norm(u) * np.linalg.norm(w)))

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.5)
ax.set_ylim(-0.5, 4)
ax.set_aspect("equal")

ax.quiver(0, 0, u[0], u[1], angles="xy", scale_units="xy", scale=1,
          color="tab:blue", width=0.02)
ax.quiver(0, 0, w[0], w[1], angles="xy", scale_units="xy", scale=1,
          color="tab:red", width=0.02)

# 夹角弧线
arc = np.linspace(0, theta, 60)
ax.plot(0.7 * np.cos(arc), 0.7 * np.sin(arc), color="tab:green")
ax.annotate("θ", (0.9, 0.38), color="tab:green", fontsize=14)

ax.annotate("u", (u[0] / 2, 0.25), color="tab:blue", fontsize=14)
ax.annotate("w", (w[0] / 2 + 0.1, w[1] / 2 + 0.25), color="tab:red", fontsize=14)
ax.set_title("u · w = ‖u‖‖w‖cosθ")
fig.savefig("book/public/figs/fig04-dot_angle.png", dpi=120, bbox_inches="tight")
plt.close(fig)
  1. 当且仅当 ,即 ——两个非零向量垂直,当且仅当它们的点积为 0
  2. 点积大于 0,说明夹角小于 (方向偏「同向」);小于 0,说明夹角大于 (方向偏「反向」)。
  3. 柯西-施瓦茨不等式:因为 ,所以

这个不等式是很多机器学习理论(比如相似度、特征值扰动)的地基,现在你已经有推导它的完整材料了。

4.5 用点积求夹角

由几何意义解出 :

例:

所以

python
import numpy as np

u = np.array([1.0, 2.0])
w = np.array([3.0, 1.0])

cos_theta = np.dot(u, w) / (np.linalg.norm(u) * np.linalg.norm(w))
theta = np.arccos(np.clip(cos_theta, -1.0, 1.0))   # clip 防止浮点误差越界
print("cosθ =", cos_theta)
print("θ(弧度) =", theta)
print("θ(度) =", np.degrees(theta))

运行输出:

text
cosθ = 0.7071067811865475
θ(弧度) = 0.7853981633974484
θ(度) = 45.00000000000001

浮点误差让结果差一点点,所以四舍五入后才是 45°——这也是为什么书里建议用 np.allclose 而不是 ==

AI 里的余弦相似度就是 本身:把两个词、两张图片、两段文字各自变成向量,夹角越小、余弦越接近 1,就认为它们越相似。你学的这条公式,正是现代大模型里「注意力」打分的基本工具。

4.6 投影:把一个向量「压」到另一个方向上

投影解决这样的问题:阳光垂直照下来,一根斜杆在地面上的影子有多长、朝哪个方向?

给定 ,把 分解成两部分:一部分平行于 (投影),另一部分垂直于 。平行部分记作

推导投影向量

方向的单位向量为 方向上的带符号长度(夹角为锐角时为正)。由点积公式:

把这个带符号长度乘上方向 ,就得到投影向量:

投影

例:(水平方向)、

python
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

u = np.array([4.0, 0.0])
w = np.array([2.0, 3.0])
proj = (np.dot(u, w) / np.dot(u, u)) * u

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.5)
ax.set_ylim(-0.5, 4)
ax.set_aspect("equal")

ax.quiver(0, 0, u[0], u[1], angles="xy", scale_units="xy", scale=1,
          color="tab:blue", width=0.02)
ax.quiver(0, 0, w[0], w[1], angles="xy", scale_units="xy", scale=1,
          color="tab:red", width=0.02)
ax.quiver(0, 0, proj[0], proj[1], angles="xy", scale_units="xy", scale=1,
          color="tab:purple", width=0.02)

# 垂直辅助线:w 终点到投影终点
ax.plot([w[0], proj[0]], [w[1], proj[1]], color="gray", linestyle="--")

ax.annotate("u", (u[0] / 2, 0.25), color="tab:blue", fontsize=14)
ax.annotate("w", (w[0] / 2 + 0.1, w[1] / 2 + 0.25), color="tab:red", fontsize=14)
ax.annotate("投影", (proj[0] / 2, -0.45), color="tab:purple", fontsize=14, ha="center")
ax.set_title("w 在 u 上的投影")
fig.savefig("book/public/figs/fig04-projection.png", dpi=120, bbox_inches="tight")
plt.close(fig)

影子在水平方向长 2,竖直的 3 完全被「压掉」了。

python
import numpy as np

u = np.array([4.0, 0.0])
w = np.array([2.0, 3.0])

proj = (np.dot(u, w) / np.dot(u, u)) * u
print("投影向量:", proj)
print("验证:投影与 u 平行:", np.isclose(proj[1], 0.0))

运行输出:

text
投影向量: [2. 0.]
验证:投影与 u 平行: True

投影在第 13 章会再次出现:最小二乘法本质上就是「把观测向量投影到模型能到达的平面上」。这一章的投影公式,就是未来那套推导的种子。

动手实践

  1. 计算 :(用公式手算再用 np.linalg.norm 验证)。
  2. 的单位向量,验证它的模为 1。
  3. 判断下列向量对是否垂直,用点积说明理由:;;
  4. 用点积求 的夹角(精确到度),再用 4.5 的代码验证。
  5. 画出 上的投影,检查投影是否与 平行。

常见错误

错误写法/理解原因
点积结果写成向量,如 点积是「对应分量相乘再相加」,结果是标量 5
计算模模是平方和的平方根,,不是 7
忘记 要除 夹角公式的分母是两向量模的乘积
np.arccos 直接算结果出现 NaN浮点误差让比值略超 ,先 np.clip 再求反余弦
认为垂直必须有一个向量是零向量两个非零向量夹角 90° 即垂直,等价于点积为 0

章末练习

基础

  1. 求模:
  2. 计算点积:
  3. 判断 是否垂直,用点积解释。

提高

  1. 的夹角,保留一位小数(度)。
  2. 已知 ,求夹角
  3. 投影到 上,画出并计算投影向量。

挑战

  1. 证明:若 长度相等,则 垂直于 。提示:计算 ,利用点积的分配律。
  2. 三个向量 满足 ,能否推出 ?找出反例并解释。

章末自测

    • A.
    • B.
    • C.
    • D.
    • A.
    • B.
    • C.
    • D.
  1. 两个非零向量垂直,当且仅当?
    • A. 它们的模相等
    • B. 它们的点积为 0
    • C. 它们方向相同
    • D. 它们的夹角为 0°
    • A.
    • B.
    • C.
    • D.
  2. 单位向量的模是?
    • A.
    • B.
    • C.
    • D. 任意值
  3. 的单位向量是?
    • A.
    • B.
    • C.
    • D.
  4. 上的投影向量是?
    • A.
    • B.
    • C.
    • D.
  5. 柯西-施瓦茨不等式是?
    • A.
    • B.
    • C.
    • D.
  6. 余弦定理的正确形式是?
    • A.
    • B.
    • C.
    • D.
  7. np.arccos 的输入应限制在?
    • A.
    • B.
    • C.
    • D. 任意实数