[译]基于模型的机器学习 - 4.2 一个用于分类的模型
为一个数据项预测标签(例如“回复”或“不回复”)的问题称为分类(classification)。执行分类的系统被称为分类器(classifier),它们大概是当今使用最广泛的机器学习算法。可用的分类算法有许多种,而对某个特定的预测任务,有些会比另一些效果更好。解决分类问题的一种常见做法是尝试几种不同的分类算法,看看哪一种效果最好。这种做法忽略了分类算法在相同数据上做出不同预测的根本原因:每个算法都隐含地对数据做出了不同的假设。遗憾的是,这些假设被隐藏在每个算法的内部。
你可能会惊讶地得知,许多分类算法都可以被解释为在某个概率模型中进行近似推断。因此,与其运行一个分类算法,我们不如构建相应的模型,并使用一个推断算法来做分类。我们为什么要这样做,而不直接使用分类算法呢?因为一种基于模型的分类方法给我们带来若干好处:
- 分类器中的假设被显式化。这有助于我们理解分类器在做什么,从而让我们可以改进使用它的方式以获得更好的预测准确率。
- 我们可以修改模型来提升其准确率,或赋予它超出原分类器能力之外的新能力。
- 我们可以使用标准的推断算法来同时训练模型和做出预测。这在修改模型时特别有用,因为训练和预测算法会与修改后的模型保持同步。此外,不同的算法在速度与准确率之间有不同的权衡。我们可以选择最适合我们需求的算法,同时保留我们所有的建模假设。
这些好处并不小——在本章中,你将看到这三点如何都对交付一个成功的系统至关重要。我们将展示如何从零开始、通过对给定数据项时标签如何产生做出一系列假设,来构建一个广泛使用的分类器的模型。随后我们将展示如何扩展这个最初的分类模型,以实现邮件分类系统所需的各种能力。在模型演化的整个过程中,我们将使用一个标准的推断算法(期望传播)来做训练和预测。
在构建模型之前,我们需要理解一个带有固定假设集的分类器怎么可能被应用于许多不同的问题。这之所以可能,是因为分类器要求把输入数据变换成一种与分类器中所编码假设相匹配的形式。这种变换是通过一组特征(一个特征集,feature set)实现的,其中一个特征(feature)是一个作用于数据项、返回一个或多个值的函数,这些值通常是二元或连续的值。在我们的模型中,我们将使用返回 0.0 到 1.0 范围内连续值的特征。例如,我们的第一个特征在用户被列在邮件的收件人(To)栏时返回 1.0,否则返回 0.0——我们把它称为 ToLine 特征。喂给分类器的正是这些特征值,而非数据项本身。因此,我们不是去改变分类器中的假设,而是使用特征来变换数据,以匹配已经内建于分类器中的假设。
分类器做出的另一个重要简化是,它只在相应的特征值已知的前提下对标签变量做出预测。因为它总是以这些已知的特征值为条件,模型只需要表示条件概率 $P(\mathrm{label}|\mathrm{features})$,而非联合分布 $P(\mathrm{label},\mathrm{features})$。因为它表示的是一个条件概率,这类模型被称为条件模型(conditional model)。构建一个条件模型是方便的,因为我们不需要对所条件化的数据(特征值)建模,而只需对给定这些值时标签的概率建模。这就引出了我们的第一个建模假设。
- 对于任何一封邮件,特征值总是可以计算出来。
我们说“总是”,就是指总是:在训练期间、在做预测时、对系统曾遇到的每一封邮件都是如此。尽管方便,但“特征值总是可以计算出来”这个假设使得处理缺失数据变得困难。例如,如果一封邮件的发件人未知,那么任何需要发件人的特征都无法计算。严格来说,这将意味着我们无法做出预测。在实践中,人们通常会在真实值不可用时提供一个默认的特征值,尽管这样做并不正确。例如在发件人的情形中,这相当于把所有发件人缺失的邮件都当作来自某个特定的“未知”发件人。正确的做法应当是对特征值做一个联合模型,并在任何缺失值上求边缘——但是,如果数据很少缺失,这种更简单的做法往往已经足够好——事实上这就是我们在这里将采用的做法。
一个单特征分类模型
我们将从构建一个仅使用一个特征来预测用户是否会回复一封邮件的模型开始:这个特征就是用户是否在收件人栏中(ToLine 特征)。由于我们构建的是条件模型,我们只需要考虑从特征值生成标签(用户是否回复了该邮件)的过程。因此,我们试图生成的变量是一个二元标签,如果用户回复了邮件则为真,否则为假——我们把这个变量称为 repliedTo。这个 repliedTo 变量正是我们在训练模型时会观测到、并在做预测时会推断的变量。
要直接从连续的特征值定义生成这个二元 repliedTo 变量的过程会很困难,因为它本身不是一个连续变量。相反,我们引入一个连续的中间变量,我们把它称为 score(分数)。我们将假设,对于回复概率较高的邮件,score 会更高,而对于回复概率较低的邮件,score 会更低。假设如下:
- 每封邮件都有一个关联的连续
score,当用户回复该邮件的概率较高时,score更高。
注意,与概率不同,连续的 score 值不要求介于 0 和 1 之间,而可以取任意连续值。这使它成为一个更容易建模的量,因为我们不必操心把它的值约束在 0 到 1 之间。
现在我们准备对一封邮件的特征值如何影响其 score 做一个假设。
- 如果一封邮件的特征值变化 $x$,那么其
score将变化 $\mathit{weight}\times x$,其中weight是某个固定的连续权重。
这个假设是说,一封邮件的 score 要么在特征值增大时总是更高(如果权重为正)、要么在特征值增大时总是更低(如果权重为负)、要么不受特征值影响(如果权重为零)。score 变化量的大小由权重的大小控制:更大的权重意味着特征值的某个特定变化会产生更大的 score 变化。记住,根据我们之前的假设,更高的 score 意味着更高的回复概率,更低的 score 意味着更低的回复概率。
为构建一个表示上述假设的因子图,我们首先需要一个连续的 featureValue 变量来保存每封邮件的特征值(因此它将位于跨越各邮件的一个板内)。由于这个变量总是被观测到,我们在因子图中总是把它显示为带阴影的(图 4.1)。我们还为假设中提到的特征权重引入一个连续的 weight 变量。因为这个权重是固定的,它对所有邮件都相同,因此位于各邮件板之外。随后我们可以通过用一个确定性乘法因子把 featureValue 乘以 weight、并把结果存入连续的 score 变量,来对上述假设建模。以这种方式建模的单个特征的因子图如图 4.1 所示。
图 4.1:单个特征的因子图。每封邮件有一个 featureValue,它被乘以一个单一的公共 weight,得到该邮件的 score。正权重意味着 score 随特征值增大而增大。负权重意味着 score 随特征值增大而减小。更高的 score 对应更高的邮件被回复概率。
在绘制因子图时,我们不得不为 weight 假设某个先验分布。在这里,我们假设权重从一个零均值的高斯分布中抽取,因此它取正值和取负值的可能性相等。
- 一个特征的权重取正值和取负值的可能性相等。
我们还把这个先验分布取为方差为 1.0 的高斯(因此标准差也为 1.0)。这个选择意味着权重最常落在 -1.0 到 1.0 的范围内,偶尔会落在此范围之外的 -2.0 到 2.0 之间,非常偶尔地甚至落在那个范围之外(正如我们在图 3.4 中看到的)。我们同样可以为方差选任何值,这会导致不同的权重取值范围,因此这里并没有隐含的假设。这个选择的效果将取决于与权重相乘得到 score 的特征值,也取决于我们如何使用 score,这一点我们接下来会看。
现在我们有了一个连续的 score 变量,它对更可能被回复的邮件更高、对更不可能被回复的邮件更低。接下来我们需要把 score 转换为一个二元的 repliedTo 变量。做到这一点的一个简单方法是对 score 做阈值化——如果它高于某个阈值,则 repliedTo 为真,否则为假。我们可以通过添加一个连续的 threshold 变量,并使用上一章遇到的确定性 GreaterThan 因子来做到这一点:
图 4.2:图 4.1 的因子图经过扩展,使得如果 score 大于一个 threshold,二元 repliedTo 变量就为真,否则为假。
这里我们为 threshold 选择了一个 $\text{Gaussian}(0,10)$ 先验——我们稍后会讨论这个先验的选择。现在,假设我们尝试在某位用户的训练集上训练这个单特征模型。我们可以像往常一样使用概率推断来训练模型。首先我们固定每封邮件的 repliedTo 值(通过查看用户实际是否回复了该邮件),并固定 ToLine featureValue——它总是可用的,因为我们可以从邮件的收件人栏计算它。给定每封邮件这两个观测值,我们就可以通过推断 weight 和 threshold 的后验分布来训练。
遗憾的是,如果我们尝试在这个模型上运行推断,那么我们尝试的任何推断算法都会失败。这是因为某些观测值在模型下具有零概率。换句话说,我们模型所编码的数据生成过程根本不可能生成出这些观测到的数据值。当你的数据在你的模型下具有零概率时,这是模型有误的确凿信号!
问题在于模型极度过度自信。对于任何 weight 和 threshold 值,只要 score 大于 threshold,它总是以 100% 的确定性预测 repliedTo 为真,否则以 100% 的确定性预测 repliedTo 为假。如果我们把回复概率对 score 作图,它会在 score 越过 threshold 时突兀地从 0% 跳到 100%(见图 4.3 中的蓝线)。只有当我们能够找到某个完美分类训练集的 weight 和 threshold——换句话说,给所有被回复的训练邮件一个高于阈值的 score、给所有未被回复的邮件一个低于阈值的 score——我们才能成功训练这样一个模型。举例来说,如果用户回复了每一封他们在收件人栏中的邮件、且没有回复其他每一封邮件,那么这就是可能的。只要有哪怕一封邮件不符合这一情形,那么它的观测标签在模型下就会具有零概率。例如,假设一封未被回复的邮件有一个高于阈值的 score——预测将是 repliedTo 以概率 1.0 为真,因此其为假的概率为零。但在这种情况下 repliedTo 被观测为假,其概率为零,因此在模型下是不可能的。
图 4.3:对于图 4.2 的无噪声模型、以及一个在阈值化前向 score 添加高斯噪声的有噪声 score 模型,随 score 相对于阈值变化时预测回复概率的曲线图。对于无噪声模型,回复概率在 score 越过阈值时突兀地从 0.0 变为 1.0。相反,对于有噪声模型,回复概率在一段 score 取值范围内(从约 -8 到 +8)从接近 0.0 平滑地变化到接近 1.0。
回过头看,假设 4.2 说过,对于 score 更高的邮件,回复概率总是更高。但事实上,在我们当前的模型中,这个假设并不成立——如果我们有两个正的 score、一个比另一个高,它们都会有相同的 100% 回复概率。所以我们的模型实际上编码的是这样一个假设:回复概率随 score 增大而突兀地从 0 跳到 100%——正是这个过强的假设导致了训练失败。
当模型不能完美表示数据时,向它添加噪声会有帮助。
为更好地表示假设 4.2,我们需要让回复概率随 score 增大而平滑增大。图 4.3 中的红色曲线展示了 score 与回复概率之间平滑得多的关系。这条曲线你也许会觉得眼熟,它是一个高斯分布的累积密度函数,就像我们在上一章图 3.9 中看到的那样。我们想改变模型来使用这条平滑曲线。我们可以通过在对 score 做阈值化之前向它添加一个服从高斯分布的随机值来实现这一点。这些被称为“噪声”值,因为它们把干净的 0% 或 100% 预测变得“有噪声”。现在,即使 score 低于阈值,其带噪声版本高于阈值的概率也有一小点(反之亦然),从而模型可以容忍被错误分类的训练样本。这种情况发生的确切概率将取决于 score 低于阈值多少、以及所添加的高斯噪声把它推到阈值以上的概率。这个概率由高斯噪声的累积密度函数给出,于是你就得到了图 4.3 中所示的曲线。
由于预测概率在一段 score 取值范围内从 0.0 平滑变化到 1.0,模型现在可以改变其预测的置信度,而不再总是预测 0% 或 100%。这一变化发生所跨越的取值范围(曲线的陡峭程度)由高斯噪声的方差决定。图 4.3 中的曲线对应的噪声方差为 10,这也是我们将在模型中使用的值,原因我们稍后会讨论。那么,让我们添加一个新的连续变量 noisyScore,并给它一个均值在 score、方差为 10 的高斯分布。这给出图 4.4 的因子图。
图 4.4:带一个特征的分类模型的因子图。该模型使用一个高斯因子在对某个特定 score 预测 repliedTo 时引入不确定性。
在选择 10 这个方差时,我们设定了 score 需要变化多少才能改变预测概率。记住,我们的权重通常在 -1.0 到 1.0 范围内,有时在 -2.0 到 2.0 范围内,偶尔在此范围之外。看看图 4.3,你可以看到,要把预测概率从 50% 这种“不知道”的预测改变到比如说 85% 这种自信的预测,意味着 score 需要变化约 3.0。如果我们选择 -1.0 到 1.0 范围内的特征值(我们会这样做),这意味着我们正在做出以下假设:
- 单个特征通常对回复概率有较小的影响,有时有中等的影响,偶尔有较大的影响。
这个假设防止我们的分类模型过快地对其预测变得过度自信。例如,假设系统看到几封具有某个特定特征值(比如 ToLine=1.0)的邮件,它们随后都被回复了。对于下一封 ToLine=1.0 的邮件,系统预测“回复”时应当有多自信?噪声方差的选择编码了我们对这种置信度的假设。把噪声方差设为一个较高的值意味着系统需要看到大量邮件才能为某个特征学到一个大的权重,因此会做出信心不足的预测。把噪声方差设得太低会有相反的效果,系统在仅几封训练邮件之后就会做出自信的预测。方差为 10 是一个合适的中间值,避免了做出信心不足或过度自信的预测。
现在我们可以尝试在我们某位用户(比如 User35CB8E5)的邮件上训练这个新模型。正如在第 3 章中一样,我们可以使用期望传播来执行推断。这分别给出 weight 和 threshold 上的高斯分布:Gaussian(3.77, 0.028) 和 Gaussian(7.63, 0.019)。
现在我们可以使用这些高斯分布对一封(或若干封)新邮件做出预测,方法是使用在线学习,正如我们在第 3 章中看到的。为此,我们用学到的后验分布替换 weight 和 threshold 上的先验。然后我们固定每封邮件的特征值并运行推断,以计算 repliedTo 上的边缘分布。由于我们模型中只有一个特征、且它只有两个可能取值,模型对回复概率只能做出两种可能的预测,每个特征值各一种。给定上述 weight 和 threshold 的高斯分布,ToLine 特征两个取值下预测的回复概率如表 4.2a 所示。正如我们可能预期的,用户在收件人栏中(ToLine=1.0)时预测的回复概率高于用户不在收件人栏中(ToLine=0.0)时。
为检查这些预测概率是否合理,我们可以计算训练集中每个特征值下实际被回复的邮件比例。预测概率应当接近这些比例。每个特征值下被回复和未被回复的邮件计数、以及由这些计数算出的回复比例如表 4.2b 所示。
(a)
(b)
表 4.2:(a) 我们的单特征模型对每个特征值预测的回复概率。(b) 对每个特征值:User35CB8E5 的邮件中被回复的邮件数、未被回复的邮件数、以及被回复的邮件比例。令人欣慰的是,这些比例接近学到的模型的预测概率。
这些算出的比例与预测概率非常接近,这让我们有些把握,相信我们已经从数据集中正确地学习了。实际上,我们提供了一种冗长的方式来学习表 4.2a 中给出的条件概率表!然而,如果我们想在模型中使用多个特征,那么我们就不能使用条件概率表,因为随着特征数量的增加,它会变得大到无法管理。相反,我们将使用 score 变量来提供一种不同的、可扩展的组合特征的方法,我们将在下一节看到。
本页引入概念回顾
分类(classification):为给定数据项预测固定数量标签之一的任务。例如,预测用户是否会回复某封特定邮件,或网站访问者是否会点击某个特定链接。因此,在分类中,目标是对模型中的一个离散变量做出预测。
分类器(classifiers):执行分类的系统,换句话说,为数据项预测一个标签(如果分类器是概率性的,则预测标签上的一个分布)的系统。分类器大概是当今最广为人知、使用最广泛的机器学习系统。
特征集(feature set):一组特征,它们一起被用来把一个数据项变换成更适合与某个特定模型或算法一起使用的形式。特征集通常与分类器一起使用,但也可以与许多其他类型的模型和算法一起使用。
特征(feature):一个在给定数据项时计算出一个值的函数。特征可以返回单个二元或连续值,也可以返回多个值。特征通常作为特征集的一部分使用,把数据项变换成更适合与某个特定模型或算法一起使用的形式。
条件模型(conditional model):一个表示条件概率而非联合概率的模型。条件模型要求所条件化变量的值总是已知。条件模型的优点是模型可以更简单,因为它不需要对所条件化的变量建模。
下一节:建模多个特征
- 本文作者:BeanHsiang
- 本文链接:https://beanhsiang.github.io/post/2026-08-11-mbml-emailclassifier_a_model_for_classification/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。