向量性质 向量性质描述了决定向量行为的几何与代数特征。本节介绍大小、方向、单位向量、相等、平行、正交以及线性无关,它们是每一个 ML 特征空间的基石。 向量的大小(magnitude,又称长度)告诉你它延伸得有多远。可以把它想成箭头的长度。对于向量 $\mathbf{a} = (a1, a2, a3)$,其大小为: $$\|\mathbf{a}\| = \sqrt{a1^2 + a2^2 + a3^2}$$ 这其实就是勾股定理在更高维情形下的推广,度量的是从原点到该点的直线距离。 向量的方向告诉你它指向哪里;直观地想象一条从原点连到该坐标点的直线即可。 当没有显式指定原点时,我们通常默认为 (0,0,...0),也就是中心点,至少在可视化时如此。
向量性质描述了决定向量行为的几何与代数特征。本节介绍大小、方向、单位向量、相等、平行、正交以及线性无关,它们是每一个 ML 特征空间的基石。
这其实就是勾股定理在更高维情形下的推广,度量的是从原点到该点的直线距离。
向量的方向告诉你它指向哪里;直观地想象一条从原点连到该坐标点的直线即可。
当没有显式指定原点时,我们通常默认为 (0,0,...0),也就是中心点,至少在可视化时如此。
位置无关紧要,关键始终是位移:从原点出发画的向量 (3, 2) 和从另一点出发画的同一个 (3, 2) 仍然相等。
若 k > 0,它们同向;若 k < 0,它们反向。无论哪种,它们都落在经过原点的同一条直线上。
直观上,平行向量不携带任何「新」的方向信息,其中一个只是另一个的拉伸或翻转版本。
如果两个向量指向完全独立的方向,它们就是正交(orthogonal,即垂直)的。沿其中一个方向移动,在另一个方向上毫无进展。
想象先向北走再向东走,这两个方向就是正交的——无论你向北走多远,都不会让你向东移动分毫。我们会非常频繁地遇到正交性。
正交性对 ML 至关重要:彼此正交的特征携带完全独立的信息,这对表示来说是理想的。
更一般地,任意两个向量之间存在一个夹角 \theta,取值范围从 0° 到 180°。
这个夹角刻画了两个方向之间的全部关系:0° 表示平行(同向),180° 表示平行(反向),90° 表示正交。介于其间的则是一种混合。
ML 中大多数向量关系都处在这个谱系的某处。稍后我们会看到精确的工具(点积、余弦相似度)来计算这个角度。
如果一组向量中至少有一个可以由其他向量经缩放相加得到,那么这组向量线性相关。它没有给集合带来任何新信息。
例如,若 \mathbf{c} = 2\mathbf{a} + 3\mathbf{b},则 \mathbf{c} 是冗余的——通过 \mathbf{a} 和 \mathbf{b} 你已经拥有了 \mathbf{c} 所能提供的一切。
平行向量总是线性相关的,因为其中一个只是另一个的缩放副本。任何包含零向量的集合也都是线性相关的。
如果一组向量中没有任何一个能由其他向量构成,它们就是线性无关(linearly independent)的。每一个都贡献了一个真正的新方向。正交向量总是线性无关的。
一点直觉:如果你想研究不同的人并把它们表示为向量,线性相关(的人)会让观察结果偏向被过度采样的数据点,这是设计 AI 训练数据集时一个重要的考量因素。
在 2 维中,两个线性无关的向量可以到达平面上的任意一点;在 3 维中则需要三个。「需要多少个独立向量」这一想法与维数直接相连。
当一个向量的大部分分量为零时,它是稀疏(sparse)的。反之,大部分分量非零,则称为稠密(dense)。
稀疏性之所以重要,是因为它同时影响存储和计算。稀疏向量只需记录非零项,因而可以更高效地存储和处理。
单位向量是大小恰好为 1 的向量。它纯粹表示一个方向,不包含任何长度信息。你可以把任意向量除以它的大小来得到单位向量:
这个过程叫做归一化(normalisation)。它剥去「有多远」而只保留「朝哪边」,这在机器学习中很重要。
标准单位向量分别沿各坐标轴指向:\hat{\mathbf{i}} = (1, 0, 0)、\hat{\mathbf{j}} = (0, 1, 0)、\hat{\mathbf{k}} = (0, 0, 1)。任何向量都可以写成它们的组合,例如 (3, 2, 4) = 3\hat{\mathbf{i}} + 2\hat{\mathbf{j}} + 4\hat{\mathbf{k}}。
import jax.numpy as jnp a = jnp.array([3.0, 4.0]) magnitude = jnp.sqrt(jnp.sum(a ** 2)) print(f"Magnitude of a: {magnitude}")
import jax.numpy as jnp a = jnp.array([2, 4, 6]) b = jnp.array([1, 2, 3]) ratios = a / b print(f"Ratios: {ratios}") print(f"Parallel: {jnp.allclose(ratios, ratios[0])}")