在预测建模问题上建立基线性能非常重要。
基线为你稍后评估的更高级方法提供了一个比较点。
在本教程中,您将学习如何从头开始用 Python 实现基线机器学习算法。
完成本教程后,您将了解:
- 如何实现随机预测算法。
- 如何实现零规则预测算法。
通过我的新书用 Python 从零开始实现机器学习算法来启动你的项目,其中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。
- 2018 年 8 月更新:测试并更新以与 Python 3.6 配合使用。

如何使用 Python 从零开始实现基线机器学习算法
照片由 Vanesser III 提供,部分权利保留。
描述
有很多机器学习算法可供选择。实际上有数百种。
您必须知道给定算法的预测是否好。但您怎么知道呢?
答案是使用基线预测算法。基线预测算法提供了一组预测,您可以像评估您问题的任何预测一样评估它们,例如分类准确率或 RMSE。
这些算法的分数提供了在评估您问题上的所有其他机器学习算法时所需的比较点。
一旦建立,您就可以评论给定算法与朴素基线算法相比有多好,从而为给定方法实际有多好提供背景。
最常用的两个基线算法是
- 随机预测算法。
- 零规则算法。
当开始一个比传统分类或回归问题更棘手的新问题时,最好先设计一个针对您的预测问题的随机预测算法。之后,您可以改进它并设计一个零规则算法。
让我们来实现这些算法,看看它们是如何工作的。
教程
本教程分为 2 个部分
- 随机预测算法。
- 零规则算法。
这些步骤将为您处理机器学习算法的实现和基线性能计算提供所需的基础。
1. 随机预测算法
随机预测算法根据训练数据中观察到的随机结果进行预测。
这也许是最简单的实现算法。
它要求您存储训练数据中所有不同的结果值,这对于具有大量不同值的回归问题来说可能很大。
由于使用随机数来做决策,因此在算法使用之前固定随机数种子是一个好主意。这是为了确保我们获得相同的随机数集,进而确保每次运行算法时都得到相同的决策。
下面是一个名为 random_algorithm() 的函数中随机预测算法的实现。
该函数同时接收包含输出值的训练数据集和必须预测输出值的测试数据集。
该函数适用于分类和回归问题。它假定训练数据中的输出值是每行的最后一列。
首先,从训练数据中收集唯一的输出值集。然后为测试集中的每一行选择一个从该集中随机选择的输出值。
1 2 3 4 5 6 7 8 9 |
# 生成随机预测 def random_algorithm(train, test): output_values = [row[-1] for row in train] unique = list(set(output_values)) predicted = list() for row in test: index = randrange(len(unique)) predicted.append(unique[index]) return predicted |
我们可以用一个只包含输出列的简单数据集来测试这个函数。
训练数据集中的输出值是“0”或“1”,这意味着算法将从中选择的预测集是 {0, 1}。测试集也包含一列,没有数据,因为预测是未知的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
from random import seed from random import randrange # 生成随机预测 def random_algorithm(train, test): output_values = [row[-1] for row in train] unique = list(set(output_values)) predicted = list() for row in test: index = randrange(len(unique)) predicted.append(unique[index]) return predicted seed(1) train = [[0], [1], [0], [1], [0], [1]] test = [[None], [None], [None], [None]] predictions = random_algorithm(train, test) print(predictions) |
运行示例将计算测试数据集的随机预测并打印这些预测。
1 |
[0, 0, 1, 0] |
随机预测算法易于实现且运行快速,但我们可以做得更好作为基线。
2. 零规则算法
零规则算法是比随机算法更好的基线。
它利用关于给定问题的更多信息来创建一条规则以进行预测。此规则根据问题类型而有所不同。
让我们从分类问题开始,预测一个类标签。
分类
对于分类问题,一条规则是预测训练数据集中最常见的类值。这意味着,如果训练数据集有 90 个类“0”的实例和 10 个类“1”的实例,它将预测“0”并获得 90/100 或 90% 的基线准确率。
这比随机预测算法要好得多,后者平均只能获得 82% 的准确率。有关如何计算此随机搜索的估计值,请参见下文
1 2 |
= ((0.9 * 0.9) + (0.1 * 0.1)) * 100 = 82% |
下面是一个名为 zero_rule_algorithm_classification() 的函数,它针对分类情况实现了这一点。
1 2 3 4 5 6 |
# 分类的零规则算法 def zero_rule_algorithm_classification(train, test): output_values = [row[-1] for row in train] prediction = max(set(output_values), key=output_values.count) predicted = [prediction for i in range(len(test))] return predicted |
该函数利用了带有键属性的 max() 函数,这有点巧妙。
给定训练数据中观察到的类值列表,max() 函数接受一组唯一的类值,并为集合中的每个类值调用类值列表的计数。
结果是它返回在训练数据集中观察到的类值列表中具有最高计数的类值。
如果所有类值的计数都相同,那么我们将选择数据集中观察到的第一个类值。
一旦我们选择了一个类值,它就会用于为测试数据集中的每一行进行预测。
下面是一个使用虚构数据集的示例,该数据集包含 4 个类“0”的示例和 2 个类“1”的示例。我们期望该算法为测试数据集中的每一行选择类值“0”作为预测。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from random import seed from random import randrange # 分类的零规则算法 def zero_rule_algorithm_classification(train, test): output_values = [row[-1] for row in train] prediction = max(set(output_values), key=output_values.count) predicted = [prediction for i in range(len(test))] return predicted seed(1) train = [['0'], ['0'], ['0'], ['0'], ['1'], ['1']] test = [[None], [None], [None], [None]] predictions = zero_rule_algorithm_classification(train, test) print(predictions) |
运行此示例将进行预测并将它们打印到屏幕上。正如预期的那样,选择了类值“0”并进行了预测。
1 |
['0', '0', '0', '0', '0', '0'] |
现在,让我们看看回归问题的零规则算法。
回归
回归问题需要预测一个实数值。
一个好的默认预测实数值是预测中心趋势。这可以是均值或中位数。
一个好的默认值是使用训练数据中观察到的输出值的均值(也称为平均值)。
这可能比随机预测具有更低的误差,后者将返回任何观察到的输出值。
下面是一个执行此操作的函数,名为 zero_rule_algorithm_regression()。它通过计算观察到的输出值的均值来工作。
1 |
mean = sum(value) / total values |
计算后,将为训练数据中的每一行预测均值。
1 2 3 4 5 6 7 8 |
from random import randrange # 回归的零规则算法 def zero_rule_algorithm_regression(train, test): output_values = [row[-1] for row in train] prediction = sum(output_values) / float(len(output_values)) predicted = [prediction for i in range(len(test))] return predicted |
这个函数可以用一个简单的例子来测试。
我们可以构造一个已知均值为 15 的小型数据集。
1 2 3 4 5 6 7 8 9 10 |
10 15 12 15 18 20 mean = (10 + 15 + 12 + 15 + 18 + 20) / 6 mean = 90 / 6 mean = 15 |
下面是完整的例子。我们期望测试数据集中的每一行都将预测均值 15。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from random import seed from random import randrange # 回归的零规则算法 def zero_rule_algorithm_regression(train, test): output_values = [row[-1] for row in train] prediction = sum(output_values) / float(len(output_values)) predicted = [prediction for i in range(len(test))] return predicted seed(1) train = [[10], [15], [12], [15], [18], [20]] test = [[None], [None], [None], [None]] predictions = zero_rule_algorithm_regression(train, test) print(predictions) |
运行示例将计算并打印预测的输出值。正如预期的那样,测试数据集中的每一行都预测了均值 15。
1 |
[15.0, 15.0, 15.0, 15.0, 15.0, 15.0] |
扩展
以下是一些您可以作为本教程的扩展进行研究和实现的基线算法。
- 替代中心趋势,其中预测中位数、众数或其他中心趋势计算而不是均值。
- 移动平均线,用于时间序列问题,其中预测最后 n 条记录的均值。
回顾
在本教程中,您发现了在机器学习问题上计算性能基线的重要性。
您现在知道
- 如何为分类和回归问题实现随机预测算法。
- 如何为分类和回归问题实现零规则算法。
你有什么问题吗?
在评论中提出您的问题,我将尽力回答。
嗨,Jason,
感谢您的文章。
猜测,在
zero_rule_algorithm_classification
和zero_rule_algorithm_regression
中,预测值应该从 len(test) 生成,而不是 len(train)。是的,抓得好。已修复。
谢谢 Grigoriy。
你好,Jason!
我不太明白上面的代码!
from random import seed
from random import randrange
def random_algorithm(train, test)
output_values = [row[-1] for row in train]
unique = list(set(output_values))
predicted = list()
for row in test
index = randrange(len(unique))
predicted.append(unique[index])
return predicted
seed(1)
train = [[0], [1], [0], [1], [0], [1]]
test = [[None], [None], [None], [None]]
predictions = random_algorithm(train, test)
print(predictions)
def、row[-1] 和那些东西是什么?
我才刚开始学习 ML 一周。
我应该从哪里开始才能完全理解这个页面?
谢谢!
你好,
row[-1] 指的是 Python 列表中最后一个元素。
您最好阅读有关 Python 语法的资料。
使用随机预测时,难道不应该总是 50% 吗? 82% 是针对每次样本预测 90%:10% 的情况。
您的数据通常不是在两个类之间 50/50 平衡的。
您可能拥有不平衡的数据,您可能有两个以上的类别。
训练集中的数据总是希望是平衡的(50/50)吗?平衡的训练集对测试集上的分类器性能有什么影响?
这取决于具体问题。您可以进行敏感性分析,并针对您的数据具体回答这个问题,实际上,我鼓励您这样做。
嗨,Jason,
非常感谢这篇精彩的文章。
我认为 Wei Zhang 的问题是基于你上面提供的随机预测算法没有考虑训练集中出现的次数,而是只查找唯一元素,然后使用均匀分布随机生成输出值。如果我错了,请纠正我,但遵循这种方法,准确率方程变成(假设数据是 90-10 分布):0.9*0.5 + 0.1*0.5 = 0.5 或 50%
是的,我相信你是对的。
我将安排时间更新这篇文章。
from random import seed
from random import randrange
上面在 zero_rule_algorithm_regression() 中并没有真正使用。
谢谢,你可能可以忽略那些导入。
在上面的回归示例中
答案是 [15.0, 15.0, 15.0, 15.0],而不是 [15.0, 15.0, 15.0, 15.0,15.0,15.0]
因为 test 数据集的长度是 4,而不是 6
是的,我也是这么认为的。长度是 4。
你能解释一下你是怎么计算 82% 的吗?
在此先感谢您
我确实确切地展示了,你遇到的问题是什么?
我有很多值需要建模,例如(蓝、红、绿、黄)。
我如何计算两种方法的总准确率?我是否只需计算每个值与完整集合相比的准确率,然后取平均值?
例如,100 个值中有 10 个蓝色,意味着对蓝色的零规则是 10%,然后我对每个值都这样做吗?
我甚至不确定如何处理随机情况,因为我的训练集中有这么多值。我是否只需要将预测数组与我的训练集进行比较?
是的,每个类的准确率都可以报告。
您还可以创建混淆矩阵。
https://machinelearning.org.cn/confusion-matrix-machine-learning/
你好 Jason,
我想知道我们是否可以在随机预测算法中找到 RMSE、MAE 等?(就像我们在 Weka 中的 ZeroR 那样)
是的,您可以计算每个指标。
你好 Jason,
感谢您的帖子。
这对于如何创建简单算法很有用。
我认为在第二次创建 zero_rule_algorithm 函数时代码中有一个小错误。
prediction 变量基于 train 变量,我认为它应该是 test 变量。
“predicted = [prediction for i in range(len(train))]”
不客气。
谢谢!已修复。
嗨,Jason,
我是一名 ML 新手,现在我正在学习使用神经网络和深度学习进行人脸识别。我使用 FaceNet 模型训练了我的数据集,并想通过基准和基线比较来检查模型性能,但我不知道从哪里开始。您是否有任何教程可以帮助我或给我一些关于此的想法?
谢谢。
是的,请参阅本教程
https://machinelearning.org.cn/how-to-develop-a-face-recognition-system-using-facenet-in-keras-and-an-svm-classifier/
感谢布朗利博士的精彩帖子!我看到了零规则算法如何比随机算法在准确率等指标上更好。但是对于精度、召回率、f1 等依赖于阳性类别预测的指标,我认为随机算法更有意义,因为零规则将使这些指标等于零。采用两种算法中的最高分数来为多个指标创建基线是否有意义?基本上,为准确率运行零规则算法,为精度、召回率等运行随机算法,然后您就有多个指标的基线?感谢分享您的知识。
好问题,请看这个
https://machinelearning.org.cn/naive-classifiers-imbalanced-classification-metrics/
太棒了,谢谢!
不客气。
布朗利博士您好,
我对随机预测算法在示例中的准确率是如何计算出来的感到非常困惑。
((0.9 * 0.9) + (0.1 * 0.1)) * 100
看起来这里其他人明白了,但我对这里的数字背景感到迷茫。
我唯一理解的是,0.9 = 90/100 个类 0 的出现次数,0.1 = 10/100 个类 1 的出现次数。
为什么我们要将 0.9 * 0.9 相乘?或者为什么会发生 0.1 * 0.1?我真的很迷茫 🙁
好问题,这篇教程更好地解释了随机猜测分类器预期性能之外的概率。
https://machinelearning.org.cn/dont-use-random-guessing-as-your-baseline-classifier/
还有这个。
https://machinelearning.org.cn/how-to-develop-and-evaluate-naive-classifier-strategies-using-probability/