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

AI 数据集的集合记号:隶属关系、划分与泄漏

通过发现并修复 AI 训练、验证和测试划分中的重叠,学习集合、隶属关系、并集、交集和分割。

分享这篇文章

假设一个图像分类器在验证数据上取得了 96% 的分数。随后有人发现,img-04 同时被用于训练和验证。这个分数看似精确,但其中一个示例已经不再是未见过的示例。

集合为陈述和检验这一失败提供了一种简洁方式。集合记录哪些对象属于某个集合。由此,交集揭示重叠,并集检查覆盖范围,而分割描述把每个示例干净地分配给且只分配给一个数据集划分。

学完本课后,你将能够阅读隶属关系和集合构造记号,计算常见的集合运算,并为训练、验证和测试 ID 实现第一道审计。这个内容推进了第 1 课中介绍的变量、模型和学习图景的数据一侧。

隶属关系把集合变成真假命题

集合是一个隶属关系明确的对象集合。如果 DD 是小型数据集中所有示例 ID 的集合,可以写成

D={img-01,img-02,img-03,img-04}.D=\{\text{img-01},\text{img-02},\text{img-03},\text{img-04}\}.

花括号表示“包含这些元素的集合”。命题

img-02D\text{img-02}\in D

读作“img-02 是 DD 的一个元素”。符号 \notin 否定这一命题,因此 img-09D\text{img-09}\notin D

有限集合中不同元素的数量称为它的基数,写作 D|D|。在上面的例子中,D=4|D|=4

集合构造记号描述规则,而不是冗长列表

对于真实数据集,列出每一个元素并不实际。集合构造记号用条件定义隶属关系:

Dcat={xD:label(x)=cat}.D_{\text{cat}} = \{x\in D : \operatorname{label}(x)=\text{cat}\}.

从左到右读作:“DcatD_{\text{cat}}DD 中满足 xx 的标签为 cat 的示例 xx 的集合。”冒号表示“使得”。竖线 | 也常在相同位置使用。

冒号后的条件像过滤器一样工作。对于

D={img-01,img-02,img-03,img-04},D=\{\text{img-01},\text{img-02},\text{img-03},\text{img-04}\},

如果 img-01 和 img-04 的标签是 cat,那么

Dcat={img-01,img-04}.D_{\text{cat}}=\{\text{img-01},\text{img-04}\}.

这个记号把正在考虑的全集(这里是 DD)与隶属规则分开。如果没有 xDx\in D,“所有猫图像”可能指现实中存在的每一张猫图像,而不是这个项目可用的示例。

三种运算审计数据集划分

TTVVEE 分别表示训练、验证和测试 ID 集合。三种运算回答不同的工程问题。

运算记号数据集问题
交集TVT\cap V哪些 ID 同时出现在两个集合中?
并集TVT\cup V哪些不同的 ID 至少出现在一个集合中?
差集TVT\setminus V哪些训练 ID 不在验证集中?

空集写作 \varnothing,不包含任何元素。因此,TV=T\cap V=\varnothing 表示训练集和验证集没有共享 ID。这样的集合称为不相交

干净的划分就是一个分割

假设完整数据集是 DD。当训练集、验证集和测试集满足两个要求时,它们构成 DD分割

第一,它们的并集覆盖整个数据集:

TVE=D.T\cup V\cup E=D.

第二,每一对集合都不相交:

TV=,TE=,VE=.\begin{aligned} T\cap V &= \varnothing,\\ T\cap E &= \varnothing,\\ V\cap E &= \varnothing. \end{aligned}

覆盖范围防止示例消失;两两不相交防止示例出现在两个划分中。合在一起,它们说明 DD 的每个元素恰好属于一个部分。

数据集划分实验。每行是一个稳定的样本 ID。消除所有重叠,同时让七个 ID 都恰好归属一次。
将样本分配到训练集、验证集和测试集
样本训练验证测试
img-01虎斑猫
img-02金毛寻回犬
img-03城市公交车
img-04红色自行车
img-05麻雀
img-06帆船
img-07橡树

这还不是一个划分 请修复标出的重叠项或未覆盖 ID。

Dtrain
{img-01, img-02, img-03, img-04}
Dvalidation
{img-04, img-05}
Dtest
{img-06, img-07}

重叠: {img-04}

未覆盖:

初始状态覆盖全部七个 ID,但没有通过分割测试,因为 img-04 同时属于 TTVV。取消这两个成员关系中的任意一个,就能产生有效分割。然后尝试让某个 ID 在所有集合中都不被选中:重叠消失了,但覆盖条件失败。

Python 集合对应这项审计

Python 官方文档把set 类型定义为由可哈希对象组成的无序不同元素集合。它支持上面使用的并集、交集、差集、隶属关系和不相交运算。

all_ids = {f"img-{i:02d}" for i in range(1, 8)}
train_ids = {"img-01", "img-02", "img-03", "img-04"}
validation_ids = {"img-04", "img-05"}
test_ids = {"img-06", "img-07"}

overlap = (
    (train_ids & validation_ids)
    | (train_ids & test_ids)
    | (validation_ids & test_ids)
)
covered = train_ids | validation_ids | test_ids
missing = all_ids - covered

is_partition = not overlap and not missing and covered == all_ids

print(sorted(overlap))
print(sorted(missing))
print(is_partition)

经过验证的输出是:

['img-04']
[]
False

运算符 & 计算交集,| 计算并集,- 计算差集。只有重叠集合为空时,not overlap 才为真。

为了重复使用这项检查,把条件明确写出来:

def is_partition(universe, *parts):
    covered = set().union(*parts)
    total_memberships = sum(len(part) for part in parts)
    no_overlap = total_memberships == len(covered)
    return no_overlap and covered == universe

如果某个 ID 出现在两个部分中,单独大小之和就会超过并集大小。如果某个 ID 缺失,并集就会不同于全集。

不相交 ID 是防止泄漏的必要条件,而非充分条件

开头的重叠是一种数据泄漏:训练边界之外的信息影响了模型构建或评估。Scikit-learn 的泄漏指南解释了这种泄漏如何让评估看起来过于乐观,并建议在拟合预处理步骤前分离数据。

空的 ID 交集只能捕获 ID 的精确复用,并不能证明评估集真正独立。两个不同的 ID 可能指向同一张照片的缩放副本。一个视频的帧可能被分到训练和验证两边。同一位患者、客户或未来时间段的记录,即使行 ID 不同,也可能携带共享信息。

数学与实现之间还有另一个边界:Python 集合不保留序列位置,并会丢弃重复值。训练时保留有序样本列表,并为隶属关系检查派生稳定 ID 集合。

第 5 课将加入索引和下标,让我们区分示例的身份与它在批次或张量中的位置。一旦数据集本身有清晰的隶属边界,这一区分就更容易表述。

检查你的理解

问题 1

令 D = {a, b, c}。判断 b ∈ D 以及 d ∉ D 是否成立。

显示分步解答

检查 DD 中列出的元素。

  • bb 出现在花括号中,因此 bDb\in D 为真。
  • dd 没有出现,因此 dDd\notin D 为真。

隶属关系只询问元素是否属于集合;它在书面列表中的位置无关紧要。

问题 2

对于 D = {1, 2, 3, 4, 5},计算 E = {x ∈ D : x 是偶数}。

显示分步解答

根据“xx 是偶数”这一条件检查 DD 的每个元素:

1,2,3,4,5.\begin{aligned} 1&\mapsto\text{否}, & 2&\mapsto\text{是},\\ 3&\mapsto\text{否}, & 4&\mapsto\text{是},\\ 5&\mapsto\text{否}. && \end{aligned}

只保留满足规则的元素:

E={2,4}.E=\{2,4\}.

这个条件过滤的是已声明的全集 DD,并不会加入 6 这样的其他偶数。

问题 3

令 T = {a, b, c, d} 且 V = {d, e}。求 T ∩ V、T ∪ V 和 |T ∪ V|。

显示分步解答

交集包含同时出现在两个集合中的元素。只有 dd 符合:

TV={d}.T\cap V=\{d\}.

并集包含出现在任一集合中的每个不同元素:

TV={a,b,c,d,e}.T\cup V=\{a,b,c,d,e\}.

因此 TV=5|T\cup V|=5。也可以由下面的式子得到相同结果:

T+VTV=4+21=5.|T|+|V|-|T\cap V|=4+2-1=5.

减法去掉了 dd 的第二次计数。

问题 4

数据集 D = {1, 2, 3, 4} 被划分为 T = {1, 2}、V = {3} 和 E = {4}。证明这三个集合构成一个分割。

显示分步解答

先检查覆盖范围:

TVE={1,2}{3}{4}=D.T\cup V\cup E=\{1,2\}\cup\{3\}\cup\{4\}=D.

再检查每一对集合:

TV=,TE=,VE=.\begin{aligned} T\cap V &= \varnothing,\\ T\cap E &= \varnothing,\\ V\cap E &= \varnothing. \end{aligned}

并集覆盖 DD 的每个元素,并且没有元素出现在两个部分中。两个分割要求都满足。

问题 5

训练/验证 ID 审计报告 T ∩ V = ∅。为什么这不能证明不存在任何数据泄漏?

显示分步解答

这个等式只证明没有某个精确的被审计元素同时属于两个集合。如果元素是行 ID,两行不同的记录仍可能包含同一图像的副本、同一视频的帧或同一个人的记录。

推理边界是:

TIDVID=⇏所有信息来源都相互独立.\begin{aligned} T_{\text{ID}}\cap V_{\text{ID}} &= \varnothing\\ &\not\Rightarrow \substack{\text{所有信息来源}\\\text{都相互独立}.} \end{aligned}

应审计与泄漏风险相匹配的分组单位,例如患者 ID 或源视频 ID;当不同 ID 可能包含近重复内容时,还要加入相似性检查。

问题 6

调试这个分割检查:return not (train & validation) and not (train & test)。缺少什么条件?

显示分步解答

这段代码检查了两个交集,但遗漏了验证集/测试集这一对,也遗漏了对全集覆盖范围的检查。

完整的三方检查需要:

no_overlap = not (
    (train & validation)
    or (train & test)
    or (validation & test)
)
covered = (train | validation | test) == all_ids
return no_overlap and covered

第一项保证两两不相交,第二项保证没有数据集 ID 被留在未分配状态。分割需要同时满足两者。

资料来源

  1. Mathematics for Machine Learning companion website
  2. Mathematics for Machine Learning book PDF
  3. Python documentation: set and frozenset types
  4. Scikit-learn documentation: data leakage