AI 数学课程 · 第 14 课,共 180

向量作为 AI 数据:特征如何把文档变成数字

学习读取行向量和列向量,手动并用 NumPy 构建文档特征向量,并发现形状或特征顺序错误。

分享这篇文章

“AI 模型使用数据。AI 模型使用向量。”(译文)读者看到的是一个句子,数值模型需要一组包含数字的固定位置。一种简单的编码方式是统计选定的词,得到

[2211].\begin{bmatrix} 2\\ 2\\ 1\\ 1 \end{bmatrix}.

这四个数字本身并不能说明问题。只有当编码规则规定位置 1 统计 ai、位置 2 统计 model、位置 3 统计 data、位置 4 统计 vector 时,它们才有用。按顺序排列的数字及其坐标含义共同构成一个特征向量。

学完本课,你将能够读取行向量和列向量,把坐标解释为特征,手动并用 NumPy 编码一个小文档,还能诊断数值正确但特征顺序或数组形状错误的代码。

**学习成果:**读取行向量和列向量,并把坐标解释为特征。

本课回到第 5 课:AI 的张量索引。在那里,索引回答“哪个位置?”这里,这些位置作为一个表示一起移动。官方 Mathematics for Machine Learning companion 在第 2.2 节介绍了行向量和列向量记法。下面的文档、编码规则、计算、代码、图示和评估题均为原创。

向量同时需要数值和坐标含义

上标 T\mathsf{T} 表示转置,它把行显示切换为列显示,或把列显示切换为行显示。粗体 x\boldsymbol{x} 表示整个向量;普通符号 xjx_j 表示一个坐标。因此

x=[x1x2x3x4]和xT=[x1x2x3x4]\boldsymbol{x}=\begin{bmatrix}x_1\\x_2\\x_3\\x_4\end{bmatrix} \quad\text{和}\quad \boldsymbol{x}^{\mathsf{T}}=\begin{bmatrix}x_1&x_2&x_3&x_4\end{bmatrix}

包含相同的四个坐标值,但方向不同。

对于 AI 数据,坐标通常代表约定好的特征,而不是没有名称的槽位。特征是提供给模型的一种可测量属性。它可以是词频、像素强度、温度读数或学习得到的信号。如果 fjf_j 表示特征 jj,编码器 ϕ\phi 可以把项目 dd 映射为

ϕ(d)=[f1(d)f2(d)⋮fn(d)]∈Rn.\phi(d)= \begin{bmatrix} f_1(d)\\ f_2(d)\\ \vdots\\ f_n(d) \end{bmatrix} \in\mathbb{R}^{n}.

这个方程分开说明两项工作。编码器决定如何测量每个特征;向量则以固定顺序保留所得测量值。若后续模型要一致地比较或组合这些值,每个文档都必须在同一坐标使用同一特征。

逐坐标构建文档向量

编码以下文档:

AI models use data. AI models use vectors.

使用以下有序词表:

(ai,model,data,vector).(\texttt{ai},\texttt{model},\texttt{data},\texttt{vector}).

在这个刻意缩小的例子中,规范化规则将文本转为小写、移除标点,把 models 改为 model,并把 vectors 改为 vector。由于 use 在固定词表中没有对应坐标,因此忽略它。真实文本系统需要有文档记录的分词器和词表;这里展示这个玩具规则,是为了让每个计数都能审计。

规范化后的词元是

ai, model, use, data, ai, model, use, vector

现在逐个坐标计算:

x1=count⁡(ai)=2,x2=count⁡(model)=2,x3=count⁡(data)=1,x4=count⁡(vector)=1.\begin{aligned} x_1&=\operatorname{count}(\texttt{ai})=2,\\ x_2&=\operatorname{count}(\texttt{model})=2,\\ x_3&=\operatorname{count}(\texttt{data})=1,\\ x_4&=\operatorname{count}(\texttt{vector})=1. \end{aligned}

因此,

ϕ(d)=[2211]∈R4.\phi(d)= \begin{bmatrix} 2\\2\\1\\1 \end{bmatrix} \in\mathbb{R}^{4}.
固定的特征顺序把四个有名称的词元计数变成四个坐标。箭头保留每个标签与其数值之间的对应契约。
从文档到特征向量的流程文档 AI models use data, AI models use vectors 会被规范化,并按照 ai、model、data 和 vector 的顺序特征进行计数。得到的列向量包含 2、2、1 和 1。1 · 文档AI models use data.AI models usevectors.小写化models → modelvectors → vector2 · 有序特征1 · ai22 · model23 · data14 · vector13 · 列向量2211形状 4 × 1数值与标签一起移动:坐标 3 表示“data 的计数”。
语义替代说明:该文档的有序特征与计数
坐标特征计数含义
1ai2规范化后的词元 ai 出现两次。
2model2两个 models 实例变成 model。
3data1规范化后的词元 data 出现一次。
4vector1词元 vectors 变成 vector。

图示让表示契约变得可见:每个计数都沿着自己的特征标签进入对应坐标。该列向量有四个条目,因此形状是 4×14\times1。它仍然表示一个文档,而不是四个文档。

固定坐标为何让数值学习成为可能

如果某坐标对一个文档表示 data,对另一个文档却表示 vector,模型就无法让该坐标承担一致的行为。因此,特征映射在各个样本之间固定两件事:

  1. 坐标的数量;以及
  2. 每个坐标所对应的特征。

对于任意两个文档 dad_a 和 dbd_b,位置 jj 的值必须是同一种测量 fjf_j:

ϕ(da)j=fj(da),ϕ(db)j=fj(db).\phi(d_a)_j=f_j(d_a), \qquad \phi(d_b)_j=f_j(d_b).

这正是常见文本向量化软件背后的机制。官方 scikit-learn CountVectorizer 文档把词表描述为从词项到特征索引的映射。它的 transform 方法使用该词表,创建形状为 (n_samples, n_features) 的文档—词项计数数组:每一行对应一个文档,每一列对应词表中的一个特征。

计数向量之所以有用,恰恰在于它是有选择的。它保留选定特征出现的次数,丢弃原始词序、句子边界以及不在词表中的词元。以下两个文档

ai model data
data model ai

在这种编码下都会映射为 [1,1,1,0]T[1,1,1,0]^\mathsf{T}。向量相等表示保留下来的计数相等,并不表示原文或含义相等。

行和列是形状,而不是阅读方向

抽象向量 x\boldsymbol{x} 属于 R4\mathbb{R}^{4}。数学通常把它的坐标显示为 4×14\times1 的列矩阵:

[2211]∈R4×1.\begin{bmatrix}2\\2\\1\\1\end{bmatrix}\in\mathbb{R}^{4\times1}.

转置这个列显示会得到行向量:

[2211]∈R1×4.\begin{bmatrix}2&2&1&1\end{bmatrix}\in\mathbb{R}^{1\times4}.

第一种形状有四行一列;第二种有一行四列。两种方向都不会改变坐标与特征的对应关系。第一项仍属于 ai,第二项仍属于 model,依此类推。

表示写法形状方向
列向量[2,2,1,1]T[2,2,1,1]^\mathsf{T}4×14\times1四行一列
行向量[2,2,1,1][2,2,1,1]1×41\times4一行四列
NumPy 一维数组np.array([2, 2, 1, 1])(4,)尚无行/列轴

最后一行是值得记住的实现边界。一维 NumPy 数组有一个长度为 4 的轴。它不是二维的行数组或列数组。NumPy 官方 ndarray 文档把 shape 定义为包含每个数组维度大小的元组,而 ndim 统计轴的数量。对于 shape == (4,),只有一个轴。

NumPy 通过增加轴明确方向

以下可执行示例复现手工计算:

from collections import Counter

import numpy as np

document = "AI models use data. AI models use vectors."
vocabulary = ("ai", "model", "data", "vector")

raw_tokens = document.lower().replace(".", "").split()
normalization = {"models": "model", "vectors": "vector"}
tokens = [normalization.get(token, token) for token in raw_tokens]
counts = Counter(tokens)

x = np.array([counts[feature] for feature in vocabulary], dtype=np.int64)
column = x.reshape(-1, 1)
row = x.reshape(1, -1)

print("features:", vocabulary)
print("values:", x.tolist())
print("1-D shape:", x.shape)
print("column shape:", column.shape)
print("row shape:", row.shape)
print("x.T shape:", x.T.shape)

经验证的输出是:

features: ('ai', 'model', 'data', 'vector')
values: [2, 2, 1, 1]
1-D shape: (4,)
column shape: (4, 1)
row shape: (1, 4)
x.T shape: (4,)

官方 numpy.reshape 文档指出,兼容的 reshape 会返回形状改变但数据不变的数组。这里,reshape(-1, 1) 要求 NumPy 推断行数并创建一列;reshape(1, -1) 要求一行并推断列数。

最后一个输出揭示了一个常见错误。官方 numpy.transpose 文档规定,转置一维数组会返回未改变的视图。它没有第二个轴可供交换。要创建形状 (4, 1),请使用 x[:, np.newaxis] 或 x.reshape(-1, 1);要创建形状 (1, 4),请使用 x[np.newaxis, :] 或 x.reshape(1, -1)。

三个看起来正确的数组可能描述不同的数据

形状只是契约的一半,特征顺序提供另一半。假设一个流水线声明

F=(ai,model,data,vector)F=(\texttt{ai},\texttt{model},\texttt{data},\texttt{vector})

并存储 [2,2,1,1]T[2,2,1,1]^\mathsf{T}。另一个流水线声明

G=(data,vector,ai,model)G=(\texttt{data},\texttt{vector},\texttt{ai},\texttt{model})

却直接传入相同的数字序列而不重新排序。在 GG 下,第一坐标声称 data 出现两次,这对该文档是错误的。数组长度和 dtype 都符合预期,因此仅靠形状验证无法发现语义错误。

从 FF 改为 GG 时,必须让每个值和其标签一起移动:

特征顺序1234Fai:2model:2data:1vector:1Gdata:1vector:1ai:2model:2\begin{array}{c|cccc} \text{特征顺序} & 1 & 2 & 3 & 4\\\hline F & \texttt{ai}:2 & \texttt{model}:2 & \texttt{data}:1 & \texttt{vector}:1\\ G & \texttt{data}:1 & \texttt{vector}:1 & \texttt{ai}:2 & \texttt{model}:2 \end{array}

所以按 GG 顺序排列的向量是 [1,1,2,2]T[1,1,2,2]^\mathsf{T}。

另外两个边界案例可以进一步明确这个定义:

  • 如果文档不含任何词表词项,它会映射为零向量 [0,0,0,0]T[0,0,0,0]^\mathsf{T}。其维度仍为 4;零是坐标值,不是缺失的坐标。
  • 当 n=1n=1 时,行向量和列向量转置后都有形状 1×11\times1。单坐标情况掩盖了可见的方向差异,因此不适合用来调试形状。

只有当数值、特征标签和预期形状一致时,表示才准备就绪。第 15 课将把向量按分量相加。那项操作之所以有意义,是因为两个输入中的坐标 jj 都指向同一种信号——这正是本课建立的不变量。

检查你的理解

问题 1

令 x = [4, 0, −2]ᵀ,其有序特征为 (clicks, purchases, returns)。指出该向量的维度,并解释每个坐标。

显示分步解答

共有三个有序坐标,因此 x∈R3\boldsymbol{x}\in\mathbb{R}^{3},向量维度为 3。

按顺序把位置与特征标签匹配:

  1. x1=4x_1=4 表示四次 clicks;
  2. x2=0x_2=0 表示零次 purchases;以及
  3. x3=−2x_3=-2 表示 returns 特征在给定编码下的值为 −2-2。

第三个值为负可能需要领域背景——它可能是中心化特征或净变化特征,而不是原始计数——但这不会改变向量的维度或坐标顺序。

问题 2

使用有序词表 (ai, model, data, vector),编码“Data guides a model; data helps AI”。只统计转为小写并移除标点后的四个词表词项。

显示分步解答

转为小写并移除标点后,相关的规范化词元是

data, model, data, ai

按词表顺序而不是文档顺序计数:

x1=count⁡(ai)=1,x2=count⁡(model)=1,x3=count⁡(data)=2,x4=count⁡(vector)=0.\begin{aligned} x_1&=\operatorname{count}(\texttt{ai})=1,\\ x_2&=\operatorname{count}(\texttt{model})=1,\\ x_3&=\operatorname{count}(\texttt{data})=2,\\ x_4&=\operatorname{count}(\texttt{vector})=0. \end{aligned}

因此文档向量是 x=[1,1,2,0]T\boldsymbol{x}=[1,1,2,0]^\mathsf{T}。缺失的词表词项贡献零值;它的坐标仍然存在。

问题 3

向量 [3, 1, 0]ᵀ 使用特征顺序 (cat, dog, bird)。第二个服务要求 (bird, cat, dog)。必须发送哪些值?为什么直接不变地发送 [3, 1, 0]ᵀ 是错误的?

显示分步解答

首先把每个原始值与其标签配对:

cat:3,dog:1,bird:0.\texttt{cat}:3,\qquad \texttt{dog}:1,\qquad \texttt{bird}:0.

然后按第二个服务的顺序读取这些值:

(bird,cat,dog)⟶[0,3,1]T.(\texttt{bird},\texttt{cat},\texttt{dog}) \longrightarrow [0,3,1]^\mathsf{T}.

直接发送 [3,1,0]T[3,1,0]^\mathsf{T} 会断言 bird: 3、cat: 1、dog: 0。形状虽然通过,但每个坐标承载的特征含义都错了。

问题 4

将形状 (5,)、(1, 5) 和 (5, 1) 分别归类为 NumPy 一维数组、行数组或列数组。然后指出哪些是二维的。

显示分步解答

数一数每个形状元组中的条目:

  • (5,) 含有一个长度为 5 的轴,因此是没有明确行列方向的 NumPy 一维数组。
  • (1, 5) 含有两个轴:一行和五列,因此是行数组。
  • (5, 1) 含有两个轴:五行和一列,因此是列数组。

后两者是二维的,因为其形状元组含有两个轴大小。三者都存放五个标量值,因此仅凭存储值的数量无法决定方向。

问题 5

为什么 x.T 不能把 x = np.array([2, 2, 1, 1]) 变成列数组?给出一个确实创建形状 (4, 1) 的表达式。

显示分步解答

数组 x 的形状为 (4,),这意味着它只有一个轴。转置只能重新排列已有的轴,但没有第二个轴可与第一个交换。因此 x.T.shape 仍为 (4,)。

显式增加一个轴:

column = x[:, np.newaxis]
print(column.shape)  # (4, 1)

切片沿现有轴选取全部四个值,而 np.newaxis 创建一个长度为 1 的第二个轴。对于这个例子,x.reshape(-1, 1) 是等价的形状构造方式。

问题 6

两个句子在词表 (ai, model, data, vector) 下都映射为相同的计数向量 [1, 1, 1, 0]ᵀ。你能得出什么结论,又不能得出什么结论?

显示分步解答

坐标相等让我们能够断定编码器为两个句子保留了相同的四个计数:

ai:1,model:1,data:1,vector:0.\texttt{ai}:1,\quad \texttt{model}:1,\quad \texttt{data}:1,\quad \texttt{vector}:0.

但不能断定原句使用相同的词序、语法、额外词语或含义。计数表示丢弃了这些属性。编码向量相等只说明保留的特征相等,并不能证明源文档相同。

问题 7

一个文档不含四个词表词项,并映射为 [0, 0, 0, 0]ᵀ。向量是否失去了维度?解释这个结果并说明一个局限。

显示分步解答

没有。该向量仍有四个有序坐标,因此仍是 R4\mathbb{R}^{4} 中的元素。每个坐标都存在,只是值为零:

0=[0000].\boldsymbol{0}= \begin{bmatrix}0\\0\\0\\0\end{bmatrix}.

这个结果只能说明在编码器规则下,选定的词表特征都没有出现。它并不说明文档为空或没有意义。文档可能含有许多词表外词语,而这种表示会有意忽略它们。

资料来源

  1. Mathematics for Machine Learning companion website
  2. Mathematics for Machine Learning book PDF
  3. NumPy documentation: the N-dimensional array
  4. NumPy documentation: numpy.reshape
  5. NumPy documentation: numpy.transpose
  6. scikit-learn documentation: CountVectorizer