朴素分类器 (Naive Classifier) 是一种简单的分类模型,它对问题几乎不做任何假设,其性能可以作为所有其他在数据集上评估的模型进行比较的基准。
朴素分类器有不同的策略可以使用,有些比其他策略好,具体取决于数据集和性能度量的选择。最常见的性能度量是分类准确率,常见的朴素分类策略包括随机猜测类别标签、从训练数据集中随机选择标签以及使用多数类别标签。
开发一个小的概率框架来计算给定朴素分类策略的预期性能,并进行实验来确认理论预期是有用的。这些练习不仅能帮助我们理解朴素分类算法的普遍行为,还能帮助我们理解为分类任务建立性能基准的重要性。
在本教程中,您将学习如何为机器学习开发和评估朴素分类策略。
完成本教程后,您将了解:
- 朴素分类模型的性能为所有其他模型是否具有技能提供了基准。
- 与随机猜测和预测随机观察到的类标签等其他朴素分类器模型相比,多数类分类器具有更高的准确率。
- 通过 scikit-learn 库中的 DummyClassifier 类,可以在预测建模项目中使用朴素分类策略。
开始您的项目,阅读我的新书 机器学习概率,其中包括分步教程和所有示例的Python源代码文件。
让我们开始吧。

如何使用概率开发和评估朴素分类器策略
照片由 Richard Leonard 拍摄,部分版权保留。
教程概述
本教程分为五个部分;它们是:
- 朴素分类器
- 随机猜测预测
- 随机选择类别预测
- 多数类预测
- scikit-learn 中的朴素分类器
朴素分类器
分类预测建模问题是指根据模型的输入预测类别标签。
分类模型在训练数据集上拟合,在测试数据集上评估,性能通常报告为正确预测数量与总预测数量的比例,称为准确率。
给定一个分类模型,您如何知道该模型是否具有技能?
这是每个分类预测建模项目中的常见问题。答案是将给定分类器的结果与基准或朴素分类器模型进行比较。
朴素分类模型是一种不使用任何复杂性来做出预测的模型,通常会做出随机或恒定的预测。这些模型之所以称为朴素,是因为它们不使用任何领域知识或任何学习来做出预测。
基准分类器在分类任务上的性能为该问题上所有其他模型的预期性能提供了下限。例如,如果一个分类模型比朴素分类器表现更好,那么它就具有一定的技能。如果一个分类模型表现不如朴素分类器,那么它就没有技能。
应该使用哪种分类器作为朴素分类器?
这是初学者常有的困惑,并且采用了不同的朴素分类器。
一些常见的选择包括
- 随机预测类别。
- 从训练数据集中随机选择类别进行预测。
- 从训练数据集中预测多数类别。
问题在于,并非所有朴素分类器都是平等的,有些比其他分类器表现更好。因此,我们应该在我们所有的分类预测建模项目中使用表现最好的朴素分类器。
我们可以使用简单的概率来评估不同朴素分类器模型的性能,并确认应该始终用作本机分类器的策略。
在开始评估不同策略之前,让我们定义一个人为设定的两类分类问题。为了使其更有趣,我们将假设每个类别的观察数量不相等(例如,问题是不平衡的),其中类别 0 有 25 个示例,类别 1 有 75 个示例。
我们可以用 Python 中的一个小示例来具体说明,如下所示。
1 2 3 4 5 6 7 8 |
# 汇总测试数据集 # 定义数据集 class0 = [0 for _ in range(25)] class1 = [1 for _ in range(75)] y = class0 + class1 # 汇总分布 print('类别 0: %.3f' % (len(class0) / len(y) * 100)) print('类别 1: %.3f' % (len(class1) / len(y) * 100)) |
运行示例创建数据集并总结每个类别中的示例分数,显示类别 0 和类别 1 分别为 25% 和 75%,正如我们直观预期那样。
1 2 |
类别 0: 25.000 类别 1: 75.000 |
最后,我们可以定义一个概率模型来评估朴素分类策略。
在这种情况下,我们有兴趣计算给定二元分类模型的分类准确率。
- P(yhat = y)
这可以通过模型预测每个类值的概率乘以观察到每个类发生的概率来计算。
- P(yhat = y) = P(yhat = 0) * P(y = 0) + P(yhat = 1) * P(y = 1)
这计算了模型在数据集上的预期性能。它提供了一个非常简单的概率模型,我们可以用它来计算朴素分类器模型在一般情况下的预期性能。
接下来,我们将使用这个人为设定的预测问题来探索朴素分类器的不同策略。
想学习机器学习概率吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
随机猜测预测
也许最简单的策略是为所需的每个预测随机猜测一个可用类别。
我们将此称为随机猜测策略。
使用我们的概率模型,我们可以计算此模型在我们人为设定的数据集上的平均表现。
对每个类别进行随机猜测是每个可能类别标签上的均匀概率分布,或者在二类问题的情况下,每个类别的概率为 0.5。此外,我们知道数据集的类别 0 和类别 1 的预期概率,因为我们人为设定了问题;它们分别是 0.25 和 0.75。因此,我们计算此策略的平均性能如下:
- P(yhat = y) = P(yhat = 0) * P(y = 0) + P(yhat = 1) * P(y = 1)
- P(yhat = y) = 0.5 * 0.25 + 0.5 * 0.75
- P(yhat = y) = 0.125 + 0.375
- P(yhat = y) = 0.5
此计算表明,在我们人为设定的问题上,预测均匀随机类别标签的性能为 0.5 或 50% 的分类准确率。
这可能令人惊讶,但很高兴它突显了系统地计算朴素策略的预期性能的好处。
我们可以通过一个小实验来确认此估算是否正确。
该策略可以实现为一个函数,该函数随机选择一个 0 或 1 作为每次需要的预测。
1 2 3 4 5 |
# 猜测随机类别 def random_guess(): if random() < 0.5: return 0 return 1 |
然后,可以为数据集所需的每个预测调用此函数,并评估准确率
1 2 3 |
... yhat = [random_guess() for _ in range(len(y))] acc = accuracy_score(y, yhat) |
这是一个单次试验,但准确率在每次使用该策略时都会有所不同。
为了解决这个问题,我们可以重复实验 1,000 次,并报告该策略的平均性能。我们预期平均性能会与我们上面计算的预期性能相匹配。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 随机猜测朴素分类器示例 from numpy import mean from numpy.random import random from sklearn.metrics import accuracy_score # 猜测随机类别 def random_guess(): if random() < 0.5: return 0 return 1 # 定义数据集 class0 = [0 for _ in range(25)] class1 = [1 for _ in range(75)] y = class0 + class1 # 多次重复的平均性能 results = list() for _ in range(1000): yhat = [random_guess() for _ in range(len(y))] acc = accuracy_score(y, yhat) results.append(acc) print('平均值: %.3f' % mean(results)) |
运行示例执行了 1,000 次实验,并报告了该策略的平均准确率。
由于算法的随机性,您的具体结果会有所不同。
在这种情况下,我们可以看到预期性能非常接近计算性能。根据 大数定律,进行此实验的次数越多,我们的估计值就越接近我们计算的理论值。
1 |
平均值: 0.499 |
这是一个好的开始,但如果我们利用一些关于训练数据集组成的基本信息来制定策略呢?我们将在下一节中探讨这一点。
随机选择类别预测
另一种朴素分类器的方法是利用训练数据集。
也许最简单的方法是使用训练数据集中的观测值作为预测。具体来说,我们可以随机选择训练集中的观测值,并为每次请求的预测返回它们。
这是有道理的,我们可能会期望这种对训练数据集的原始使用会比随机猜测产生稍好的朴素准确率。
我们可以通过使用概率框架计算该方法的预期性能来找出答案。
如果我们以均匀概率分布选择训练数据集中的示例,我们将从每个类别中抽取示例,其发生的概率与它们在训练数据集中的发生概率相同。也就是说,我们将以 25% 的概率抽取类别 0 的示例,以 75% 的概率抽取类别 1 的示例。这也将是模型独立预测的概率。
有了这些知识,我们就可以将这些值插入到概率模型中。
- P(yhat = y) = P(yhat = 0) * P(y = 0) + P(yhat = 1) * P(y = 1)
- P(yhat = y) = 0.25 * 0.25 + 0.75 * 0.75
- P(yhat = y) = 0.0625 + 0.5625
- P(yhat = y) = 0.625
结果表明,使用从训练数据集中均匀随机选择的类别作为预测,比简单地在我们的数据集中均匀随机猜测类别,会产生更好的朴素分类器,准确率为 62.5%,而之前为 50%,提升了 12.2%。
不错!
让我们再次通过一个小型模拟来确认我们的计算。
下面的 `random_class()` 函数通过从训练数据集中选择和返回一个随机类别标签来实现此朴素分类策略。
1 2 3 |
# 预测随机选择的类别 def random_class(y): return y[randint(len(y))] |
然后,我们可以使用上一节的相同框架来评估模型 1,000 次,并报告这些试验的平均分类准确率。我们预计此经验估计值会与我们的预期值非常接近。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 随机选择类别朴素分类器示例 from numpy import mean from numpy.random import randint from sklearn.metrics import accuracy_score # 预测随机选择的类别 def random_class(y): return y[randint(len(y))] # 定义数据集 class0 = [0 for _ in range(25)] class1 = [1 for _ in range(75)] y = class0 + class1 # 多次重复的平均值 results = list() for _ in range(1000): yhat = [random_class(y) for _ in range(len(y))] acc = accuracy_score(y, yhat) results.append(acc) print('平均值: %.3f' % mean(results)) |
运行示例执行了 1,000 次实验,并报告了该策略的平均准确率。
由于算法的随机性,您的具体结果会有所不同。
在这种情况下,我们可以看到预期性能再次非常接近计算性能:模拟中为 62.4%,而我们上面计算为 62.5%。
1 |
平均值: 0.624 |
也许我们在预测类别标签时可以做得比均匀分布更好。我们将在下一节中探讨这一点。
多数类预测
在上一节中,我们探讨了一种根据训练数据集中观察到的标签的均匀概率分布来选择类别标签的策略。
这使得预测概率分布与每个类别的观察概率分布相匹配,并且比均匀分布的类别标签有所改进。特别是对于这个不平衡数据集,一个缺点是预期一个类别比另一个类别出现的次数更多,而随机预测类别(即使是有偏差的)会导致过多的错误预测。
相反,我们可以预测多数类别,并确保准确率至少与训练数据集中多数类别的构成一样高。
也就是说,如果训练集中的 75% 的示例是类别 1,并且我们将类别 1 预测给所有示例,那么我们知道我们的准确率至少为 75%,这比我们在上一节中所做的随机选择类别要好。
我们可以通过使用我们的概率模型计算该方法的预期性能来确认这一点。
此朴素分类策略预测类别 0 的概率为 0.0(不可能),预测类别 1 的概率为 1.0(确定)。因此
- P(yhat = y) = P(yhat = 0) * P(y = 0) + P(yhat = 1) * P(y = 1)
- P(yhat = y) = 0.0 * 0.25 + 1.0 * 0.75
- P(yhat = y) = 0.0 + 0.75
- P(yhat = y) = 0.75
这证实了我们的预期,并表明该策略将在我们的人为设定数据集上比前一个策略带来额外的 12.5% 的提升。
同样,我们可以通过模拟来确认此方法。
多数类别可以通过统计学方法,即分布中最常见的观测值,来计算。
可以使用 SciPy 的 `mode()` 函数。它返回两个值,第一个值是我们可以返回的模式。下面的 `majority_class()` 函数实现了此朴素分类器。
1 2 3 |
# 预测多数类别 def majority_class(y): return mode(y)[0] |
然后,我们可以在人为设定的数据集上评估该策略。我们不需要多次重复实验,因为该策略没有随机成分,并且算法在相同数据集上的表现每次都会相同。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 多数类别朴素分类器示例 from scipy.stats import mode from sklearn.metrics import accuracy_score # 预测多数类别 def majority_class(y): return mode(y)[0] # 定义数据集 class0 = [0 for _ in range(25)] class1 = [1 for _ in range(75)] y = class0 + class1 # 进行预测 yhat = [majority_class(y) for _ in range(len(y))] # 计算准确率 accuracy = accuracy_score(y, yhat) print('准确率: %.3f' % accuracy) |
运行示例报告了多数类别朴素分类器在该数据集上的准确率。
准确率与由概率框架计算的预期值 75% 和训练数据集的构成相匹配。
1 |
准确率: 0.750 |
这种多数类别朴素分类器是计算您的分类预测建模项目中的基准性能的方法。
它同样适用于类别标签数量相等的那些数据集,以及类别数多于两类的问题,例如多类别分类问题。
现在我们已经发现了表现最好的朴素分类模型,我们可以看看在下一个项目中如何使用它。
scikit-learn 中的朴素分类器
scikit-learn 机器学习库提供了一个多数类别朴素分类算法的实现,您可以在下一个分类预测建模项目中使用它。
它作为 DummyClassifier 类的一部分提供。
要使用朴素分类器,必须定义该类并将“strategy”参数设置为“most_frequent”,以确保预测多数类别。然后,该类可以在训练数据集上拟合,并用于在测试数据集或其他重采样模型评估策略上进行预测。
1 2 3 4 5 6 7 |
... # 定义模型 model = DummyClassifier(strategy='most_frequent') # 拟合模型 model.fit(X, y) # 进行预测 yhat = model.predict(X) |
实际上,DummyClassifier 很灵活,也允许使用其他两种朴素分类器。
具体来说,将“strategy”设置为“uniform”将执行我们首先测试的随机猜测策略,而将“strategy”设置为“stratified”将执行我们其次测试的随机选择类别策略。
- 随机猜测:将“strategy”参数设置为“uniform”。
- 选择随机类别:将“strategy”参数设置为“stratified”。
- 多数类别:将“strategy”参数设置为“most_frequent”。
我们可以通过在我们的人为设定的数据集上进行测试来确认 DummyClassifier 是否如预期那样,使用多数类别朴素分类策略。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# scikit-learn 中多数类别朴素分类器示例 from numpy import asarray from sklearn.dummy import DummyClassifier from sklearn.metrics import accuracy_score # 定义数据集 X = asarray([0 for _ in range(100)]) class0 = [0 for _ in range(25)] class1 = [1 for _ in range(75)] y = asarray(class0 + class1) # 重塑用于 sklearn 的数据 X = X.reshape((len(X), 1)) # 定义模型 model = DummyClassifier(strategy='most_frequent') # 拟合模型 model.fit(X, y) # 进行预测 yhat = model.predict(X) # 计算准确率 accuracy = accuracy_score(y, yhat) print('准确率: %.3f' % accuracy) |
运行示例准备数据集,然后定义并使用多数类别策略在数据集上拟合 DummyClassifier。
评估模型预测的分类准确率证实了模型表现符合预期,得分 75%。
1 |
准确率: 0.750 |
此示例为将来计算您自己的分类预测建模项目中的朴素分类器基准性能提供了一个起点。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
总结
在本教程中,您学习了如何为机器学习开发和评估朴素分类策略。
具体来说,你学到了:
- 朴素分类模型的性能为所有其他模型是否具有技能提供了基准。
- 与随机猜测和预测随机观察到的类标签等其他朴素分类器模型相比,多数类分类器具有更好的准确率。
- 通过 scikit-learn 库中的 DummyClassifier 类,可以在预测建模项目中使用朴素分类策略。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
你好 Jason,
我有一些问题。
首先关于归一化和标准化
我何时应该使用归一化,何时使用标准化进行数据预处理?
有什么规则吗?
我正在处理波士顿住房数据集。
第二个问题是关于回归。
以下模型的输出是什么?
它是一个具体值(例如特定价格)还是一个值/价格系列(连续数量)?
我正在处理波士顿住房数据集。
model.add(Dense(64,activation=’relu’,input_dim=train_data.shape[1]))
model.add(Dense(1))
最后一个问题是关于绘图
您是否有关于训练后如何评估回归预测的代码示例?
致以诚挚的问候和感谢。
Marco
好问题,这会有帮助
https://machinelearning.org.cn/faq/single-faq/what-is-the-difference-between-standardization-and-normalization
是的,对输出进行缩放也是一个好主意。
是的,您可以使用误差(例如 RMSE)来评估回归中的预测。这将有助于
https://machinelearning.org.cn/regression-tutorial-keras-deep-learning-library-python/
非常感谢您的回答。
还有一个关于归一化/标准化的一个问题。
我是否也需要对输出 y 进行归一化/标准化?或者我可以保持原样?
谢谢
Marco
我建议同时测试有和无,并使用导致模型具有最佳技能的方法。
你好 Jason,
我仍在处理波士顿住房数据集。
我有以下模型代码
model = models.Sequential()
model.add(layers.Dense(8, activation=’relu’, input_shape=[X_train.shape[1]]))
model.add(layers.Dense(16, activation=’relu’))
model.add(layers.Dense(1))
model.compile(optimizer=’rmsprop’, loss=’mse’, metrics=[‘mae’])
history = model.fit(X_train_scaled, y_train, validation_split=0.2, epochs=100)
model.evaluate(X_test_scaled, y_test)
输出如下:
[26.68399990306181, 3.7581424339144838]
3.7581424339144838 是什么?如果以价格(以千美元计)来说,它是真实价格和预测价格之间的差异吗?
而 26.6839… 是什么?简单来说? 🙂
我猜它是真实价格和预测价格之间所有差异的平均值(?)
如何绘制它们?
谢谢,
Marco
输出是均方误差和平均绝对误差。
您可以对 mse 值取平方根,将其恢复到原始单位。mae 已经以原始单位表示。
嗨,Jason,
这是一篇很棒的文章,提供了对朴素分类器性能的出色的概率洞察。做得好!!
谢谢,很高兴对您有帮助。
写起来很有趣!
你好 Jason,
我有一个与以下代码相关的问题
import numpy as np
np.random.seed(123)
这是什么意思?我应该把它放在代码的什么位置?
我何时/为何要使用它?
非常感谢,
Marco
我们正在设置随机数生成器
https://machinelearning.org.cn/introduction-to-random-number-generators-for-machine-learning/
我正试图让教程中的示例可重现,以便您能获得与我相同的结果。
你好 Jason,
我仍在处理 IMDB 数据集。
主要代码来自 Kears 网站(https://github.com/keras-team/keras/blob/master/examples/imdb_lstm.py)。
我在示例末尾编写了以下代码片段,但它没有提供很好的预测。
结果是 0.7625497 (1 好, 0 不太好)。
我想知道为什么?
非常感谢,
Marco
这是我在这里回答的一个常见问题
https://machinelearning.org.cn/faq/single-faq/can-you-read-review-or-debug-my-code
你好 Jason,
还有一个问题是关于 [0] 的使用。
有时候我发现以下代码
prediction = model.predict(x_testtext)[0][0]
这是什么意思?为什么使用它?
非常感谢,
Marco
本教程中我们不这样进行预测。
总的来说,这是对预测结果的数组索引。您可以在这里了解更多关于数组索引的信息
https://machinelearning.org.cn/index-slice-reshape-numpy-arrays-machine-learning-python/
你好 Jason,
您知道是否存在一个可视化工具(开源或非开源)可以在不编程的情况下开发机器学习模型吗?
谢谢,
Marco
是的,您可以使用 Weka,从这里开始
https://machinelearning.org.cn/start-here/#weka
你好 Jason,
我还有一个问题。
到目前为止,我已经看到了许多关于使用 Keras 进行监督学习的例子。
Keras 是否也适用于无监督学习?
您有什么简单的例子吗?
谢谢,
Marco
是的,主要是将无监督学习问题表述为监督学习,例如生成模型和自编码器。
这是一个例子
https://machinelearning.org.cn/lstm-autoencoders/
朴素贝叶斯对于单分类问题有多适用?
我能否获得更多关于如何处理这类只有单个标签的目标问题的见解?
我建议为特定的预测建模问题测试一套不同的模型。
朴素贝叶斯可能非常有效。
请注意,在本帖中我们讨论的是朴素分类器,而不是朴素贝叶斯。
你好 Jason,
我正在研究正则化。您是否有关于(例如)dropout、早停等方面的代码示例?
谢谢,
Marco
是的,有很多例子。也许从这里开始
https://machinelearning.org.cn/introduction-to-regularization-to-reduce-overfitting-and-improve-generalization-error/
你好 Jason,
您是否有关于 sklearn classification_report 的作用以及如何使用的文章?
谢谢,
Marco
没有,但您可以直接调用它并查看输出。
您具体遇到了什么问题?
你好 Jason,
我有几个问题想问您。
是否可以一起使用 Keras 和 Sklearn?也就是说,构建一个模型,然后使用 Sklearn 函数(例如混淆矩阵、分类报告)来评估结果?
上一个问题是关于精度、召回率、f1 分数和支持(它们是什么)的含义,以及它们是否对 Keras 有用。
谢谢你,
Marco
是的。
Keras 有一个用于在 sklearn 中使用神经网络的包装器。我在博客上有示例。
如果您只想使用 sklearn 指标,则不需要包装器,例如
https://machinelearning.org.cn/how-to-calculate-precision-recall-f1-and-more-for-deep-learning-models/
还有一个问题
我应该何时使用 Keras,何时使用 Scikit-learn 进行预测(Scikit-learn 模型似乎更容易构建/使用)?
谢谢,
Marco
Sklearn 模型通常比神经网络更简单。
你好 Jason,
只是一个问题,我正在阅读一本关于 Keras 的书《Python 深度学习》。
我想知道为什么他们使用公式(即一些代码)来归一化(或标准化),而不是使用 sklearn.preprocessing 函数?
结果是否相同?这是一种更快捷的执行方式吗?
此致,
Marco
我猜这只是一个偏好。
早上好,Jason!
对问题的绝佳解释,基线似乎总是能帮助排除简单问题(并避免对 KPI 进行过于乐观的估计)。
一个问题:这些朴素分类器策略与您在另一篇文章中描述的零规则算法基本相同吗?(“如何从头开始使用 Python 实现基线机器学习算法”)如果不是,有什么区别?
此致!
谢谢。
是的,基本相同。您可能希望根据用于评估解决方案的指标来选择不同的策略。
嗨,Jason,
感谢您提供的精彩教程。但是,我对“准确率”的计算感到困惑。
准确率的定义是
> 分类模型在训练数据集上进行拟合,在测试数据集上进行评估,性能通常报告为正确预测的数量与所做的总预测数量的比例,称为准确率。
但是,在上面的演示代码中,准确率是使用
acc = accuracy_score(y, yhat)
计算的,其中y
是训练集。那么我能否说上面代码计算的准确率是在训练集上而不是在测试集上?谢谢!
你好 Leo……以下信息可能有助于澄清
https://machinelearning.org.cn/model-prediction-versus-interpretation-in-machine-learning/