许多随机机器学习算法存在一个问题,即同一算法在同一数据上运行多次会得到不同的结果。
这意味着,在进行实验来配置随机算法或比较算法时,您必须收集多个结果,并使用平均性能来总结模型的技能。
这引发了一个问题:对于给定的问题,需要进行多少次实验重复才能充分表征随机机器学习算法的技能。
通常建议进行30次或更多次重复,甚至100次。一些从业者使用数千次重复,这似乎超出了收益递减的想法。
在本教程中,您将探索可用于估算适当的重复次数以有效表征随机机器学习算法性能的统计方法。
通过我的新书 机器学习统计学 开启您的项目,其中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。

估算随机机器学习算法的实验重复次数
照片来自 oatsy40,部分权利保留。
教程概述
本教程分为4个部分。它们是:
- 生成数据。
- 基本分析。
- 重复次数的影响。
- 计算标准误差。
本教程假定您已安装了带 NumPy、Pandas 和 Matplotlib 的可用 Python 2 或 3 SciPy 环境。
需要机器学习统计学方面的帮助吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
1. 生成数据
第一步是生成一些数据。
我们将假装我们已经将一个神经网络或其他随机算法拟合了训练数据集1000次,并收集了在数据集上的最终RMSE分数。我们还将假设数据呈正态分布,这是本教程中使用类型分析的要求。
始终检查您的结果分布;大多数情况下,结果将是高斯分布。
我们将生成一个结果总体进行分析。这很有用,因为我们将知道真实的总体的均值和标准差,而在实际场景中我们是不知道的。
我们将使用均值60,标准差10。
以下代码生成了1000个随机结果的样本,并将它们保存到名为results.csv的CSV文件中。
我们使用 seed() 函数来 设置随机数生成器的种子,以确保每次运行此代码时都能始终获得相同的结果(这样您就能获得与我相同数字)。然后,我们使用 normal() 函数生成高斯随机数,并使用 savetxt() 函数以ASCII格式保存数字数组。
1 2 3 4 5 6 7 8 9 10 11 |
from numpy.random import seed from numpy.random import normal from numpy import savetxt # 定义结果的底层分布 mean = 60 stev = 10 # 从理想分布生成样本 seed(1) results = normal(mean, stev, 1000) # 保存到ASCII文件 savetxt('results.csv', results) |
现在您应该有一个名为results.csv的文件,其中包含我们模拟的随机算法测试平台的1000个最终结果。
以下是文件中的最后10行,供参考。
1 2 3 4 5 6 7 8 9 10 11 |
... 6.160564991742511864e+01 5.879850024371251038e+01 6.385602292344325548e+01 6.718290735754342791e+01 7.291188902850875309e+01 5.883555851728335995e+01 3.722702003339634302e+01 5.930375460544870947e+01 6.353870426882840405e+01 5.813044983467250404e+01 |
暂时我们先忽略我们知道这些模拟结果是如何生成的。
2. 基本分析
当我们有一组结果时,第一步是进行一些基本的统计分析,看看我们有什么。
三种有用的基本分析工具包括:
- 计算摘要统计量,如均值、标准差和百分位数。
- 使用箱线图回顾数据的分布。
- 使用直方图回顾数据的分布。
以下代码执行了此基本分析。首先加载results.csv,计算摘要统计量,并显示图表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from pandas import DataFrame from pandas import read_csv from numpy import mean from numpy import std from matplotlib import pyplot # 加载结果文件 results = read_csv('results.csv', header=None) # 描述性统计 print(results.describe()) # 箱线图 results.boxplot() pyplot.show() # 直方图 results.hist() pyplot.show() |
运行示例首先打印摘要统计信息。
我们可以看到,算法的平均性能约为60.3个单位,标准差约为9.8。
如果我们假设分数是像RMSE这样的最小化分数,我们可以看到最差性能约为99.5,最佳性能约为29.4。
1 2 3 4 5 6 7 8 |
count 1000.000000 mean 60.388125 std 9.814950 min 29.462356 25% 53.998396 50% 60.412926 75% 67.039989 max 99.586027 |
创建了一个箱线图来总结数据的分布,显示中间50%(箱体)、异常值(点)和中位数(绿线)。
我们可以看到,即使在中位数附近,结果的分布也显得合理。

模型技能的箱线图
最后,创建了结果的直方图。我们可以看到高斯分布的典型钟形曲线,这是一个好兆头,因为它意味着我们可以使用标准的统计工具。
我们没有看到任何明显的分布偏斜;它似乎围绕60左右居中。

模型技能分布的直方图
3. 重复次数的影响
我们有很多结果,确切地说是1000个。
这可能比我们需要的要多,也可能不够。
我们怎么知道?
我们可以通过绘制实验重复次数与这些重复次数的平均分数来获得初步的了解。
我们期望随着实验重复次数的增加,平均分数会迅速稳定下来。它应该产生一个最初比较嘈杂,然后有很长稳定期的图。
以下代码创建了此图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from pandas import DataFrame from pandas import read_csv from numpy import mean from matplotlib import pyplot import numpy # 加载结果文件 results = read_csv('results.csv', header=None) values = results.values # 收集累积统计量 means = list() for i in range(1,len(values)+1): data = values[0:i, 0] mean_rmse = mean(data) means.append(mean_rmse) # 累积值的折线图 pyplot.plot(means) pyplot.show() |
该图确实显示了前200次重复存在一段嘈杂的平均结果,直到它变得稳定。它似乎在600次重复后变得更加稳定。

实验重复次数与模型平均技能的折线图
我们可以放大此图的前500次重复,看看是否能更好地理解发生了什么。
我们还可以叠加最终的平均分数(1000次运行的所有运行的平均值),并尝试定位一个收益递减点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from pandas import DataFrame from pandas import read_csv from numpy import mean from matplotlib import pyplot import numpy # 加载结果文件 results = read_csv('results.csv', header=None) values = results.values final_mean = mean(values) # 收集累积统计量 means = list() for i in range(1,501): data = values[0:i, 0] mean_rmse = mean(data) means.append(mean_rmse) # 累积值的折线图 pyplot.plot(means) pyplot.plot([final_mean for x in range(len(means))]) pyplot.show() |
橙色线显示了1000次运行的平均值。
我们可以看到,100次运行可能是一个不错的停止点,否则可能400次可以获得更精确的结果,但只是略微。

实验重复次数与模型平均技能的折线图,截断至500次重复并显示最终平均值
这是一个好的开始,但我们能做得更好吗?
4. 计算标准误差
标准误差是衡量“样本均值”与“总体均值”之间差异的计算。
这与描述样本内观测值的平均变异量的标准差不同。
标准误差可以为给定的样本量提供一个指标,表明从样本均值到潜在且未知的总体均值可能存在的误差量或误差范围。
标准误差可以按以下方式计算:
1 |
standard_error = sample_standard_deviation / sqrt(number of repeats) |
也就是说,在这种情况下,它是样本模型分数标准差除以重复次数的平方根。
我们预计标准误差会随着实验重复次数的增加而减小。
根据结果,我们可以计算每个重复次数的样本均值与总体均值之间的标准误差。完整的代码列表如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from pandas import read_csv from numpy import std from numpy import mean from matplotlib import pyplot from math import sqrt # 加载结果文件 results = read_csv('results.csv', header=None) values = results.values # 收集累积统计量 std_errors = list() for i in range(1,len(values)+1): data = values[0:i, 0] stderr = std(data) / sqrt(len(data)) std_errors.append(stderr) # 累积值的折线图 pyplot.plot(std_errors) pyplot.show() |
创建了标准误差与重复次数的折线图。
我们可以看到,正如预期的那样,随着重复次数的增加,标准误差会减小。我们还可以看到会有一个可接受误差的点,例如一个或两个单位。
标准误差的单位与模型技能的单位相同。

样本均值与总体均值之间标准误差的折线图
我们可以重新创建上面的图表,并绘制0.5和1个单位作为指南,用于找到可接受的误差级别。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from pandas import read_csv from numpy import std from numpy import mean from matplotlib import pyplot from math import sqrt # 加载结果文件 results = read_csv('results.csv', header=None) values = results.values # 收集累积统计量 std_errors = list() for i in range(1,len(values)+1): data = values[0:i, 0] stderr = std(data) / sqrt(len(data)) std_errors.append(stderr) # 累积值的折线图 pyplot.plot(std_errors) pyplot.plot([0.5 for x in range(len(std_errors))], color='red') pyplot.plot([1 for x in range(len(std_errors))], color='red') pyplot.show() |
再次,我们看到相同的标准误差折线图,在标准误差为1和0.5处有红色指南线。
我们可以看到,如果标准误差为1是可以接受的,那么大约100次重复就足够了。如果标准误差为0.5是可以接受的,那么大约300-350次重复就足够了。
我们可以看到,重复次数很快就达到了标准误差的收益递减点。
再次记住,标准误差衡量的是样本模型技能分数均值与给定模型配置在随机初始条件下可能的分数真正底层总体之间的差异程度。

具有标记的样本均值与总体均值标准误差的折线图
我们还可以使用标准误差作为模型平均技能的置信区间。
例如,一个模型未知的总体均值性能有95%的可能性位于一个上限和一个下限之间。
请注意,此方法仅适用于中等及大量重复次数,例如20次或更多。
置信区间可以定义为:
1 |
sample mean +/- (standard error * 1.96) |
我们可以计算此置信区间,并将其作为误差条添加到每个重复次数的样本均值中。
完整的代码清单如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
from pandas import read_csv from numpy import std from numpy import mean from matplotlib import pyplot from math import sqrt # 加载结果文件 results = read_csv('results.csv', header=None) values = results.values # 收集累积统计量 means, confidence = list(), list() n = len(values) + 1 for i in range(20,n): data = values[0:i, 0] mean_rmse = mean(data) stderr = std(data) / sqrt(len(data)) conf = stderr * 1.96 means.append(mean_rmse) confidence.append(conf) # 累积值的折线图 pyplot.errorbar(range(20, n), means, yerr=confidence) pyplot.plot(range(20, n), [60 for x in range(len(means))], color='red') pyplot.show() |
创建了一个折线图,显示每次重复的样本均值,并带有误差条显示了每个均值捕获未知底层总体的置信区间。
绘制了一条红线,显示了实际的总体均值(由于我们在教程开始时人为设置了模型技能分数,所以我们才知道)。作为总体均值的替代,您可以添加一条在1000次或更多次运行后的最终样本均值线。
误差条遮盖了均值分数线。我们可以看到均值高估了总体均值,但95%的置信区间捕获了总体均值。
请注意,95%的置信区间意味着在此区间内的95%的样本均值将捕获总体均值,而5%的样本均值和置信区间则不会。
我们可以看到,随着重复次数的增加,95%的置信区间确实收紧了,因为标准误差减小了,但也许在500次重复之后就出现了收益递减。

样本均值与标准误差条以及总体均值的折线图
通过放大此图,突出显示20到200次重复,我们可以更清楚地了解情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
from pandas import read_csv from numpy import std from numpy import mean from matplotlib import pyplot from math import sqrt # 加载结果文件 results = read_csv('results.csv', header=None) values = results.values # 收集累积统计量 means, confidence = list(), list() n = 200 + 1 for i in range(20,n): data = values[0:i, 0] mean_rmse = mean(data) stderr = std(data) / sqrt(len(data)) conf = stderr * 1.96 means.append(mean_rmse) confidence.append(conf) # 累积值的折线图 pyplot.errorbar(range(20, n), means, yerr=confidence) pyplot.plot(range(20, n), [60 for x in range(len(means))], color='red') pyplot.show() |
在创建的折线图中,我们可以清楚地看到样本均值及其对称的误差条。此图确实更好地显示了样本均值中的偏差。

均值结果带有标准误差条和总体均值的缩放折线图
进一步阅读
关于随机算法所需的统计量和计算实验方法,将两者联系起来的资源并不多。
我发现的关于这个主题的最佳书籍是:
- 《人工智能经验方法》,Cohen,1995,
如果这篇帖子引起了您的兴趣,我强烈推荐这本书。
以下是一些您可能觉得有用的附加文章:
您知道其他好的相关材料吗?
在下面的评论中告诉我。
总结
在本教程中,您发现了可用于帮助选择用于评估随机机器学习算法的正确重复次数的技术。
您发现了一些可以立即使用的方法:
- 粗略估计30、100或1000次重复。
- 绘制样本均值与重复次数的图,并根据拐点选择。
- 绘制标准误差与重复次数的图,并根据误差阈值选择。
- 绘制样本置信区间与重复次数的图,并根据误差范围选择。
您是否在自己的实验中使用了这些方法中的任何一种?
请在评论中分享您的结果;我很想听听。
嗨,Json,
对于这种搜索问题,我们不能使用无监督学习算法,如k-means聚类或Apriori吗?
谢谢
这究竟是怎么奏效的呢?
当然,您可以多次运行k-means,说实话,k-means使用k-means++来获取初始中心,而k-means++算法是一个随机算法。
这如何帮助选择实验重复次数?
我想知道,这个技术与交叉验证有多大的关系?我的意思是,交叉验证通过训练来自同一数据集的不同样本来给出许多分数,但在您的方法中,您使用同一数据集并“多次训练同一模型”。您能稍微说明一下这种关系吗?谢谢。
是的。
CV折叠的数量通常很小,例如3-10。对于有用的统计数据来说太少了。
您可以将每个折叠的分数视为一次“重复”,然后重复整个CV过程的次数较少,而不是报告CV结果的平均值的平均值(总平均值)。
这有帮助吗?
那么,当您说“总平均值”时,它就像多次重复CV过程,然后计算它们的平均值,然后对这些平均值求平均。我说得对吗?
正确。
太棒了!非常感谢Jason!
您能澄清一下“重复”这个过程指的是什么吗?是使用相同的模型和相同的种子重复过程,还是使用不同的种子的模型?我认为是前者。我正确吗?非常感谢。
好问题。
重复的意思是,同一个算法,使用相同的数据,但不同的随机数(随机数生成器的不同种子)。
感谢您的澄清。实际上,我们应该构建一个迭代循环来使用不同的种子运行模型。但是,从您在这篇文章中的代码来看,我只找到一个种子seed(1)。
您可以只设置一次种子,然后为每个循环(重复)使用长串的随机种子。
我在实践中就是这样做的。
非常感谢。如果您能将此重复过程的代码添加到本文中,那将对读者实践此技术非常有帮助。
您可以在这里看到伪代码示例
https://machinelearning.org.cn/evaluate-skill-deep-learning-models/
非常感谢Jason分享如此精彩的博客。
我想知道我是否可以将您的帖子翻译成我的母语越南语;这样许多年轻学生都能理解。
非常感谢!
不可以。我希望保留对我自己内容的所有权。
嗨,Jason,
感谢您的这篇帖子。为什么假设结果呈正态分布?在结果非正态分布的情况下,我们如何评估置信区间?
此致
很好的问题。
我有一篇计划发布的帖子,展示了如何使用Bootstrap计算经验置信区间,当结果非高斯分布时可以使用。
嗨,Jason,
有没有基于R语言的类似教程?
谢谢你
Xuemei
抱歉,目前还没有。
Jason,感谢这篇有趣的帖子!我有一个问题,如何根据重复次数选择最佳模型?我的意思是,根据您的帖子,我们需要重复次数来显示一个模型的真实性能(准确性?),但然后,如何使用这个数字来获得我必须考虑部署的稳定模型(集成?)?提前感谢。
我通常建议使用最终模型的集成。
问得好,我在那里有所涵盖
https://machinelearning.org.cn/train-final-machine-learning-model/
我们如何计算分类问题(二元或多类)的重复次数?
无论哪种分类任务,都可以使用相同的方法(上面)。
我们是否也应该重复深度学习的实验?许多关于CNN、Transformer等的最新论文似乎不再提及实验运行次数或平均结果,所以我感到很困惑。谢谢。
嗨 fresher……在我们看来,是的!我们同意您,大多数论文都不讨论实验运行。考虑到神经网络的随机性,进行多次运行并考虑平均性能是有意义的。此外,许多论文只显示训练和测试准确性,而不提供真实验证数据集的示例来理解在“真实世界数据”上的性能。
感谢您的回复。我们将在实验中进行多次运行。🙂