向量作为 AI 数据:特征如何把文档变成数字
学习读取行向量和列向量,手动并用 NumPy 构建文档特征向量,并发现形状或特征顺序错误。
“AI 模型使用数据。AI 模型使用向量。”(译文)读者看到的是一个句子,数值模型需要一组包含数字的固定位置。一种简单的编码方式是统计选定的词,得到
这四个数字本身并不能说明问题。只有当编码规则规定位置 1 统计 ai、位置 2 统计 model、位置 3 统计 data、位置 4 统计 vector 时,它们才有用。按顺序排列的数字及其坐标含义共同构成一个特征向量。
学完本课,你将能够读取行向量和列向量,把坐标解释为特征,手动并用 NumPy 编码一个小文档,还能诊断数值正确但特征顺序或数组形状错误的代码。
**学习成果:**读取行向量和列向量,并把坐标解释为特征。
本课回到第 5 课:AI 的张量索引。在那里,索引回答“哪个位置?”这里,这些位置作为一个表示一起移动。官方 Mathematics for Machine Learning companion 在第 2.2 节介绍了行向量和列向量记法。下面的文档、编码规则、计算、代码、图示和评估题均为原创。
向量同时需要数值和坐标含义
上标 表示转置,它把行显示切换为列显示,或把列显示切换为行显示。粗体 表示整个向量;普通符号 表示一个坐标。因此
包含相同的四个坐标值,但方向不同。
对于 AI 数据,坐标通常代表约定好的特征,而不是没有名称的槽位。特征是提供给模型的一种可测量属性。它可以是词频、像素强度、温度读数或学习得到的信号。如果 表示特征 ,编码器 可以把项目 映射为
这个方程分开说明两项工作。编码器决定如何测量每个特征;向量则以固定顺序保留所得测量值。若后续模型要一致地比较或组合这些值,每个文档都必须在同一坐标使用同一特征。
逐坐标构建文档向量
编码以下文档:
AI models use data. AI models use vectors.
使用以下有序词表:
在这个刻意缩小的例子中,规范化规则将文本转为小写、移除标点,把 models 改为 model,并把 vectors 改为 vector。由于 use 在固定词表中没有对应坐标,因此忽略它。真实文本系统需要有文档记录的分词器和词表;这里展示这个玩具规则,是为了让每个计数都能审计。
规范化后的词元是
ai, model, use, data, ai, model, use, vector
现在逐个坐标计算:
因此,
| 坐标 | 特征 | 计数 | 含义 |
|---|---|---|---|
| 1 | ai | 2 | 规范化后的词元 ai 出现两次。 |
| 2 | model | 2 | 两个 models 实例变成 model。 |
| 3 | data | 1 | 规范化后的词元 data 出现一次。 |
| 4 | vector | 1 | 词元 vectors 变成 vector。 |
图示让表示契约变得可见:每个计数都沿着自己的特征标签进入对应坐标。该列向量有四个条目,因此形状是 。它仍然表示一个文档,而不是四个文档。
固定坐标为何让数值学习成为可能
如果某坐标对一个文档表示 data,对另一个文档却表示 vector,模型就无法让该坐标承担一致的行为。因此,特征映射在各个样本之间固定两件事:
- 坐标的数量;以及
- 每个坐标所对应的特征。
对于任意两个文档 和 ,位置 的值必须是同一种测量 :
这正是常见文本向量化软件背后的机制。官方 scikit-learn CountVectorizer 文档把词表描述为从词项到特征索引的映射。它的 transform 方法使用该词表,创建形状为 (n_samples, n_features) 的文档—词项计数数组:每一行对应一个文档,每一列对应词表中的一个特征。
计数向量之所以有用,恰恰在于它是有选择的。它保留选定特征出现的次数,丢弃原始词序、句子边界以及不在词表中的词元。以下两个文档
ai model data
data model ai
在这种编码下都会映射为 。向量相等表示保留下来的计数相等,并不表示原文或含义相等。
行和列是形状,而不是阅读方向
抽象向量 属于 。数学通常把它的坐标显示为 的列矩阵:
转置这个列显示会得到行向量:
第一种形状有四行一列;第二种有一行四列。两种方向都不会改变坐标与特征的对应关系。第一项仍属于 ai,第二项仍属于 model,依此类推。
| 表示 | 写法 | 形状 | 方向 |
|---|---|---|---|
| 列向量 | 四行一列 | ||
| 行向量 | 一行四列 | ||
| 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)。
三个看起来正确的数组可能描述不同的数据
形状只是契约的一半,特征顺序提供另一半。假设一个流水线声明
并存储 。另一个流水线声明
却直接传入相同的数字序列而不重新排序。在 下,第一坐标声称 data 出现两次,这对该文档是错误的。数组长度和 dtype 都符合预期,因此仅靠形状验证无法发现语义错误。
从 改为 时,必须让每个值和其标签一起移动:
所以按 顺序排列的向量是 。
另外两个边界案例可以进一步明确这个定义:
- 如果文档不含任何词表词项,它会映射为零向量 。其维度仍为 4;零是坐标值,不是缺失的坐标。
- 当 时,行向量和列向量转置后都有形状 。单坐标情况掩盖了可见的方向差异,因此不适合用来调试形状。
只有当数值、特征标签和预期形状一致时,表示才准备就绪。第 15 课将把向量按分量相加。那项操作之所以有意义,是因为两个输入中的坐标 都指向同一种信号——这正是本课建立的不变量。
检查你的理解
问题 1
令 x = [4, 0, −2]ᵀ,其有序特征为 (clicks, purchases, returns)。指出该向量的维度,并解释每个坐标。
显示分步解答
共有三个有序坐标,因此 ,向量维度为 3。
按顺序把位置与特征标签匹配:
- 表示四次 clicks;
- 表示零次 purchases;以及
- 表示 returns 特征在给定编码下的值为 。
第三个值为负可能需要领域背景——它可能是中心化特征或净变化特征,而不是原始计数——但这不会改变向量的维度或坐标顺序。
问题 2
使用有序词表 (ai, model, data, vector),编码“Data guides a model; data helps AI”。只统计转为小写并移除标点后的四个词表词项。
显示分步解答
转为小写并移除标点后,相关的规范化词元是
data, model, data, ai按词表顺序而不是文档顺序计数:
因此文档向量是 。缺失的词表词项贡献零值;它的坐标仍然存在。
问题 3
向量 [3, 1, 0]ᵀ 使用特征顺序 (cat, dog, bird)。第二个服务要求 (bird, cat, dog)。必须发送哪些值?为什么直接不变地发送 [3, 1, 0]ᵀ 是错误的?
显示分步解答
首先把每个原始值与其标签配对:
然后按第二个服务的顺序读取这些值:
直接发送 会断言 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]ᵀ。你能得出什么结论,又不能得出什么结论?
显示分步解答
坐标相等让我们能够断定编码器为两个句子保留了相同的四个计数:
但不能断定原句使用相同的词序、语法、额外词语或含义。计数表示丢弃了这些属性。编码向量相等只说明保留的特征相等,并不能证明源文档相同。
问题 7
一个文档不含四个词表词项,并映射为 [0, 0, 0, 0]ᵀ。向量是否失去了维度?解释这个结果并说明一个局限。
显示分步解答
没有。该向量仍有四个有序坐标,因此仍是 中的元素。每个坐标都存在,只是值为零:
这个结果只能说明在编码器规则下,选定的词表特征都没有出现。它并不说明文档为空或没有意义。文档可能含有许多词表外词语,而这种表示会有意忽略它们。