一旦你定义了你的问题并准备好了数据,你就需要将机器学习算法应用于数据以解决你的问题。
你可能会花费大量时间来选择、运行和调整算法。你需要确保有效地利用时间,以更接近你的目标。
在这篇文章中,你将逐步了解一个流程,用于快速测试算法,并发现你的问题中是否存在可供算法学习的结构,以及哪些算法是有效的。

测试框架
照片归属于 NASA 韦伯望远镜,保留部分权利
测试框架
你需要定义一个测试框架。测试框架是你用来训练和测试算法的数据,以及你用来评估其性能的性能度量。良好地定义测试框架非常重要,这样你就可以专注于评估不同的算法并深入思考问题。
测试框架的目标是能够快速、一致地针对所解决问题的公平表示来测试算法。在框架上测试多种算法的结果,将是针对所选性能度量,对各种算法在该问题上性能的估计。你将知道哪些算法可能值得在该问题上进行调优,哪些则不应再考虑。
结果还会让你了解该问题的可学习性。如果各种不同的学习算法在该问题上普遍表现不佳,这可能表明算法可学习的结构不足。这可能是因为所选数据中确实缺乏可学习的结构,也可能是一个机会,可以尝试不同的数据变换来向学习算法揭示结构。
性能度量
性能度量是你评估问题解决方案的方式。它是你对训练好的模型在测试数据集上所做预测的测量。
性能度量通常专门针对你正在处理的问题类别,例如分类、回归和聚类。许多标准的性能度量会给你一个对你的问题领域有意义的分数。例如,分类准确率用于分类问题(正确预测总数除以总预测数,再乘以100,将其转换为百分比)。
你可能还希望得到更详细的性能 breakdown,例如,在垃圾邮件分类问题中,你可能想了解误报(false positives),因为好的邮件被标记为垃圾邮件将无法被阅读。
有许多标准的性能度量可供选择。你很少需要自己设计新的性能度量,因为通常可以找到或调整一个最能捕捉所解决问题需求的度量。可以参考你发现的类似问题以及它们使用的性能度量,看看是否可以采用。
测试和训练数据集
从转换后的数据中,你需要选择一个测试集和一个训练集。算法将在训练数据集上进行训练,并将在测试集上进行评估。这可能像随机分割数据一样简单(66% 用于训练,34% 用于测试),也可能涉及更复杂的抽样方法。
训练好的模型在训练期间不会接触到测试数据集,在该数据集上做的任何预测都旨在表明模型在一般情况下的性能。因此,你需要确保你选择的数据集能够代表你正在解决的问题。
交叉验证
一种比使用测试和训练数据集更复杂的方法是,使用整个转换后的数据集来训练和测试给定的算法。你可以在测试框架中使用的一种实现此目的的方法叫做交叉验证。
它首先将数据集分成若干个大小相等的实例组(称为“折”)。然后,模型在除一个留出的折之外的所有折上进行训练,准备好的模型在那个留出的折上进行测试。这个过程会重复,以便每个折都有机会被留出并充当测试数据集。最后,在所有折上对性能度量进行平均,以估计算法在该问题上的能力。
例如,一个3折交叉验证将涉及训练和测试模型3次
- #1:在第1+2折上训练,在第3折上测试
- #2:在第1+3折上训练,在第2折上测试
- #3:在第2+3折上训练,在第1折上测试
折的数量可以根据数据集的大小而变化,但常见的数量是3、5、7和10折。目标是在训练集和测试集的数据大小和代表性之间取得良好的平衡。
当你刚开始时,坚持使用简单的训练和测试数据划分(例如66%/34%),一旦你更有信心,再转向交叉验证。
测试算法
当你开始处理一个问题并定义了一个你满意的测试框架时,就该对各种机器学习算法进行抽样检查了。抽样检查很有用,因为它能让你非常迅速地看到数据中是否存在任何可学习的结构,并估计哪些算法可能对该问题有效。
抽样检查还有助于你发现测试框架中的任何问题,并确保所选的性能度量是合适的。
第一个进行抽样检查的最佳算法是随机算法。接入一个随机数生成器来生成适当范围内的预测。这应该是你取得的最差的“算法结果”,并将成为评估所有改进的基准。
选择5-10种适合你问题的标准算法,并在你的测试框架中运行它们。我所说的标准算法,是指没有特殊配置的流行方法。适合你的问题意味着,如果你有一个回归问题,这些算法可以处理回归。
从我们已经回顾过的算法分组中选择方法。我喜欢包含一个多样化的组合,并从各种算法类型中抽取10-20种不同的算法。根据我使用的库,我可能会抽样检查多达50多种流行方法,以快速找出有前途的方法。
如果你想运行很多方法,你可能需要重新审视数据准备过程,并减小所选数据集的大小。这可能会降低你对结果的信心,所以要用不同大小的数据集进行测试。你可能喜欢用较小的数据集进行算法抽样检查,用较完整的数据集进行算法调优。
总结
在这篇文章中,你了解了建立一个值得信赖的测试框架的重要性,该框架涉及选择测试和训练数据集以及一个对你的问题有意义的性能度量。
你还学习了使用测试框架对问题上的多种机器学习算法进行抽样检查的策略。你发现这个策略可以快速揭示你的数据集中是否存在可学习的结构(如果没有,你可以重新进行数据准备),以及哪些算法在该问题上普遍表现良好(这些算法可能成为进一步研究和调优的候选者)。
资源
如果你想深入研究这个主题,可以从下面的资源中了解更多信息。
- 数据挖掘:实用的机器学习工具与技术,第5章:可信度:评估所学到的知识
嗨,Jason,
我真的很想结合参数调优来思考这个问题。我联系了一些同事,想和他们讨论一下,也想听听你的想法。
“我的问题是:是否可以采用这种方法结合网格搜索来调整这些模型的参数?我觉得这在理论上是好的,但不确定如何同时协调各个模型不同的参数。
我可以采取的另一种方法是:使用测试框架来识别开箱即用性能最佳的算法,为我的项目选择它,然后使用网格搜索进行调优。”
这两种方法中,哪一种与你的工作流程相似?如果都不是,你对此有何看法?
嘿 Mark,好问题。
对于一个小问题,我会对开箱即用的算法进行抽样检查,可能还会检查一些流行的参数组合。对于更大的问题和竞赛,我会对所有流行的算法进行网格搜索,然后对表现好的算法进行“超级网格搜索”。
这是一个时间/投资回报率的权衡,你必须根据问题的规模和重要性来决定。
好的,假设我有一个足够大的问题,可以承受时间成本。我之前甚至不确定是否能轻松/可能地同时对一堆流行的算法使用网格搜索。我想我只需要正确评估参数并构建一个结构来考虑网格搜索的差异。
谢谢回复,Jason。非常感谢。
嘿 Mark,
像 scikit-learn 和 R 这样的平台都具有参数调优功能(网格/随机搜索)。你会希望使用交叉验证来对给定模型的鲁棒性进行公平的估计。
你可以很大程度上自动化这个过程,因为你可以将参数搜索限制在众所周知的参数范围内(来自论文/经验),至少在抽样检查阶段是这样。
抽样检查的目的不是为了得到最好的结果,只是为了指示最好的结果可能在哪里——哪些方法通常更擅长于发现问题中的结构。一旦找到,你就可以对那个较小的子集进行调优、集成和高级特征工程。
你好,Jason。
你能告诉我是否有一种方法可以像测试黑盒一样测试机器学习算法吗?
让我们考虑一个例子,我有两个应用程序,它们使用机器学习算法来解决某个任务。我无法访问应用程序的源代码,甚至不知道内部使用了哪些算法。我唯一能做的就是调整输入数据并验证输出。我需要测试并选择更适合解决该任务的应用程序。
乍一看,测试方法很简单:使用相同的数据集比较两个应用程序的准确性。然而,我担心应用程序的准确性可能会变化。例如:应用程序A在少量训练数据上表现更好;在更大量的训练数据上,应用程序B比A给出更好的结果;随着训练数据的进一步增长,应用程序B开始受到,比如说,过拟合的影响。
很明显,我测试的时间越长,我得到的洞察就越深入。但我不能永远测试下去——我需要在某个点停下来。所以,我的问题更多是,如何确定一个足够大的数据集大小,以确保使用该数据集我能选择出长期来看最好的应用程序?
此致,
Mikle
这是一个困难的开放性问题,Mikle。使用交叉验证来估计准确性是可行的做法,并且可以测试这两种方法的极限。我喜欢的一个好测试是,准确性是平稳下降,还是随着数据集大小而扩展。
据我所知,交叉验证也包括一个验证步骤,与训练和测试一起……
嗨,Jason,
我有一个关于交叉验证的问题。假设你在训练前创建了一个保留的测试集。然后在训练集上运行k折交叉验证并生成一个性能度量。这个性能度量表示什么?它仍然代表模型的泛化能力,还是代表训练过程的质量?
此致,
Yohahn
这个博客上最近的一篇文章提供了一个Python测试框架的例子:https://machinelearning.org.cn/compare-machine-learning-algorithms-python-scikit-learn/
嗨 Jason,
有没有什么测试技术/方法来测试一个算法?如果有,能请你列举几个或者指引我找到它们的途径吗?
此致,
Rahul
嗨 Rahul,如果你指的是测试实现的正确性,我建议使用单元测试和回归测试。
谢谢,Jason,这是一篇信息量非常大的帖子。我刚接触机器学习,正在通过像你这样的帖子获取信息。我有一个地区事故发生的数据,大约有200条记录,包含位置、时间和严重性信息。我想预测未来每小时的事故情况。对此你有什么建议?数据量足够做预测吗?我应该使用什么方法?
提前感谢,
Vaibhav
这个过程将帮助你解决你的预测建模问题
https://machinelearning.org.cn/start-here/#process
嗨 Jason,我有一个关于交叉验证的问题。假设我有一个用于回归问题的训练集 O 和一个测试数据集 P。原始特征太少,不足以支持预测,所以我想添加一些统计特征(如均值、中位数)。我的问题是,我应该在什么时候生成统计特征?在交叉验证之前还是之后?
假设我将训练集 O 分为训练集 T 和验证集 V。
1) 如果我们在交叉验证前添加统计特征,我认为我们可能在验证集 V 上得到很好的拟合,但在测试数据集上可能会有高方差。
2) 如果我们在交叉验证后添加统计特征,我认为我们可能会丢失一些信息,从而可能导致在测试数据集上出现高偏差(训练集 O 的大小非常小)。
我说得对吗?我该怎么办?
提前感谢!
在交叉验证前生成统计特征意味着我使用整个训练数据集O来生成统计特征,然后进行交叉验证。
在交叉验证后生成统计特征意味着我将O分成T和V,使用T生成统计特征,并将转换应用于V。
好问题,应该在每个交叉验证折叠内部生成新特征,只使用该折叠的训练数据,而不使用该折叠中保留的测试数据。
这将是一项耗时的工作。但我认为这会满足我的需求。谢谢,Jason。
不客气。
在您题为“如何评估机器学习算法”的文章中(https://machinelearning.org.cn/how-to-evaluate-machine-learning-algorithms),有以下段落
如果你想运行很多方法,你可能需要重新审视数据准备过程,并减小所选数据集的大小。这可能会降低你对结果的信心,所以要用不同大小的数据集进行测试。你可能喜欢用较小的数据集进行算法抽样检查,用较完整的数据集进行算法调优。
该段落位于标题为“测试算法”的部分。
对我来说,似乎有一些相关但未描述的材料,例如,可能需要减少数据集的大小;为什么会出现这种情况?为什么需要用不同大小的数据集进行测试,等等?
数据集的大小可能会影响机器学习算法所近似的函数的质量。
我一直在对各种数据集中的连续数据变量执行主成分分析。我的问题是,由于一些数据特征可能包含分类或布尔形式的数据值,PCA 对分类模型的有效性如何?
我应该考虑PCA吗?还是有其他方法可以用于分类算法?
PCA 是一种用于监督学习的数据准备方法。它本身不是一种监督学习算法。
嗨,Jason,
PCA将如何影响含有分类变量的数据集?使用PCA来提高算法性能是否足够有效?
据我所知,PCA 仅适用于实数值数据。
谢谢 Jason 的博客。我有一个问题关于
“当你刚开始时,坚持使用简单的训练和测试数据划分(例如66%/34%),一旦你更有信心,再转向交叉验证”
我们是选择训练/验证/测试方法还是交叉验证方法?或者我们可以将这些方法混合使用吗?
例如,假设我们预留20%的数据用于测试,并在剩下的80%数据上运行交叉验证。这样做可以吗?还是我们应该在整个数据集上运行交叉验证?
哪一种是更好的方法?
我正在对一组数据进行实验,通过在80%的数据上使用交叉验证,我得到了约0.8的分数(我在sklearn中对MLP使用了随机搜索(*))
然而,当我用相同的参数(*)处理剩下的20%数据时,我得到的预测值约为0.2。这就是为什么我不确定混合使用这些方法是否更好。
通常你会用一种方法来评估模型技能,而不是结合使用它们。
一般来说,机器学习算法是随机的,所以你会在相同的数据上用相同的算法得到不同的结果
https://machinelearning.org.cn/randomness-in-machine-learning/
一个解决方案是多次重复实验,并取平均模型技能,更多关于这个策略的信息请看这里
https://machinelearning.org.cn/evaluate-skill-deep-learning-models/
非常感谢您的回复。我会阅读那些帖子的。
非常感谢您的参考资料,我一直在找这个。帮助很大!
不客气。
我看到David Langer的一个视频里,他使用caret包在不同的模型上应用了10次10折交叉验证。我的意思是,他同时在交叉验证不同的模型,并进行超参数的网格搜索(即在train()函数中使用method="some_model")。我的问题是,像他那样将这两个步骤(交叉验证和网格搜索)结合起来可以吗?还是我应该分两步来做。首先,交叉验证不同的模型,然后再进行超参数的网格搜索。谢谢
这是你的选择。
一篇非常好的文章,Jason。
我认为创建一个测试框架非常适合一些函数式编程原则,主要是高阶函数,其中每个步骤(数据抽样、算法和评估指标)都可以委托给其他函数。当然,它不会是一个纯函数,因为在相同条件下多次运行可能会因为抽样到数据的不同子集而产生不同的结果。
你对此有何看法?你认为像模板方法这样的编程模式会有益吗?提前感谢!
有趣,我还没想过这可能如何融入编程模式。
或许你可以试试看效果如何。
非常有趣,我在 techtarget 上留下了我的评论 https://searchitchannel.techtarget.com/feature/Machine-learning-use-cases-attract-IT-service-providers
自动化全球前三的工具,我们深入研究了准确性和时间消耗的基准测试。
好的。
Jason,
如果我的训练集在某个学习器上的准确率高于交叉验证(CV)的准确率,那么我的模型肯定是过拟合了。为了解决这个过拟合问题,我使用嵌套交叉验证(nested CV)在我的训练数据上进行调优。对于学习器,我通过嵌套CV得到的最佳超参数组合,我用它在整个数据集(训练+测试)上进行训练,并观察准确率(或损失)。此外,我还执行自助法重采样(bootstrap resampling)程序来近似我的模型在未见数据上的表现(泛化误差)。在我对我的学习器有信心之后,我才用它在未动过的测试数据上进行预测。我遵循的步骤正确吗?如果我在任何步骤有错,请纠正我。
我不同意你一定是在过拟合。如果你通过样本外性能进行模型选择,过拟合就变得无关紧要了。
假设它确实是过拟合,那么在我完成嵌套交叉验证(nestedCv)之后,在我最终确定我的模型之前,正确的步骤是什么?
在你选择了一个模型之后,过拟合是模型性能不佳的一个可能原因。它是一种你可以用来理解性能不佳的模型或者像神经网络那样增量学习的模型的诊断工具。
你可以简单地选择一个具有更好样本外性能的模型,它就不会“过拟合”。
然而,如果你认为你看到的性能不佳是由于过拟合造成的,过拟合可以通过多种方式解决,最常见的是通过正则化。比如根据模型复杂度在损失函数中增加一个惩罚项。
嗨,jason
我希望你纠正一下SVM和KNN算法之间的区别
对不起,我没明白。能请你详细说明一下吗?
我有一个简单的问题,适用于您上面列出的两种方法。在将数据分为训练集和测试集之后,我想知道是否可以根据在测试集上的表现来停止训练模型(即字面上选择在测试集上表现最好的模型,而测试数据并不进入训练过程)。我曾遇到一篇论文(记不清是哪篇了),只提到将数据分为80(训练):20(保留/测试),并没有进一步解释将训练集再分为训练集和验证集。谢谢 Jason!
是的,这被称为早停法
https://machinelearning.org.cn/early-stopping-to-avoid-overtraining-neural-network-models/
嗨,Jason,
我是机器学习新手,有点困惑。我的理解是,你训练你的模型并在训练集上拟合它(使用80/20划分),然后测试准确性(y_predict vs y_test)。最后,你可以使用K折交叉验证来进一步确定模型的准确性。
然而,您的文章听起来像是您应该要么使用训练/测试集划分法,要么使用交叉验证法来训练模型。
“一种比使用测试和训练数据集更复杂的方法是使用整个转换后的数据集来训练和测试给定的算法。你可以在测试框架中使用的一种实现此目的的方法叫做交叉验证”
我的理解是,交叉验证仅用于了解模型的技能——而不是用它来正式训练模型。
能否请您澄清一下?
谢谢,
你会使用训练/测试集划分或k折交叉验证来评估一个数据集上的模型,而不是两者都用。
如果你有很多数据,你可以保留一些数据作为最终的测试集,剩下的用于模型选择。这是理想的情况,但在实践中很少能实现,因为我们通常没有足够的数据。
为了用k折交叉验证评估一个模型,我们必须拟合k个模型,你可以在这里了解更多
https://machinelearning.org.cn/k-fold-cross-validation/
嗨,Jason,
在数据转换之后进行训练-测试集划分(和交叉验证),你是不是犯了数据泄露的错误?
另外,如果你只是用交叉验证来相互比较算法,那么在这种情况下,数据泄露是否可以原谅?前提是你已经保留了一个外部的测试集,该测试集没有参与任何数据准备/转换过程,以便获得一个合适的性能指标。
谢谢
Cian
是的,请看这个
https://machinelearning.org.cn/data-preparation-without-data-leakage/