拥有一两种在某个问题上表现尚可的算法是一个好的开始,但有时您可能会被激励,希望在可用的时间和资源下获得最佳结果。
在这篇文章中,您将回顾一些可以用来榨取额外性能并提升机器学习算法结果的方法。
在调优算法时,您必须对测试工具给出的结果有高度的信心。这意味着您应该使用能够减少您用来评估算法运行的性能指标方差的技术。我建议使用交叉验证,并设置一个相当高的折数(具体数字取决于您的数据集)。

音叉
照片归属于 eurok,保留部分权利
您将在这篇文章中学到的三种策略是:
- 算法调优
- 集成方法
- 极限特征工程
算法调优
首先要做的是,从那些您已知在您的问题上表现良好的算法中获得更好的结果。您可以通过探索和微调这些算法的配置来实现这一点。
机器学习算法是参数化的,修改这些参数会影响学习过程的结果。可以将每个算法参数想象成图上的一个维度,参数的取值是轴上的点。三个参数会构成一个算法可能配置的立方体,而n个参数则会构成一个算法可能配置的n维超立方体。
算法调优的目标是为您的问题找到该超立方体中的最佳点或点集。您将针对您的测试工具进行优化,因此再次强调,花时间构建一个可信赖的测试工具的重要性不容低估。
您可以使用自动化方法来解决这个搜索问题,这些方法在可能性空间上施加一个网格,并抽样出好的算法配置可能所在的位置。然后,您可以在优化算法中使用这些点来锁定最佳性能。
您可以对多个表现良好的方法重复此过程,并探索每种方法所能达到的最佳效果。我强烈建议这个过程是自动化的,并且粒度要相对粗糙,因为您很快就会达到收益递减的点(性能只增加百分之几),而这些微小的提升可能无法转化到生产系统中。
算法的参数越是经过调优,算法就越会偏向于训练数据和测试工具。这种策略可能很有效,但也可能导致模型更脆弱,对您的测试工具过拟合,在实践中表现不佳。
集成方法
集成方法旨在结合多种方法的结果以获得更好的性能。当您有多个“足够好”的模型,且每个模型专门处理问题的不同部分时,集成方法效果很好。
这可以通过多种方式实现。您可以探索的三种集成策略是:
- Bagging(套袋法):更正式的名称是自助聚合(Bootstrapped Aggregation),即通过在训练数据的不同子集上训练,让相同的算法对问题有不同的视角。
- Boosting(提升法):在相同的训练数据上训练不同的算法。
- Blending(混合法):更正式的名称是堆叠泛化或堆叠(Stacked Generalization or Stacking),即将多个模型的预测作为输入,交给一个新的模型,该模型学习如何将这些预测组合成一个总的预测。
在您用尽了更传统的方法之后,再转向集成方法是一个好主意。这有两个很好的理由:它们通常比传统方法更复杂,而且传统方法为您提供了一个可以改进并从中汲取灵感来创建集成模型的良好基准。

集成学习
照片归属于 ancasta1901,保留部分权利
极限特征工程
前两种策略着眼于从机器学习算法中获得更多。而这种策略则是关于揭示问题中更多的结构,供算法学习。在数据准备阶段,我们学习了特征分解和聚合,以便更好地为机器学习算法规范化数据。在这种策略中,我们将这一思想推向极致。我称之为极限特征工程,但其实“特征工程”这个术语就足够了。
把您的数据想象成内嵌了复杂的多维结构,机器学习算法知道如何找到并利用这些结构来做决策。您希望最好地将这些结构暴露给算法,以便算法能发挥最大作用。一个困难在于,其中一些结构可能过于密集或过于复杂,算法在没有帮助的情况下难以找到。您也可能凭借领域专业知识对这类结构有所了解。
将属性广泛地分解为多个特征。从技术上讲,您使用这种策略所做的是将依赖关系和非线性关系简化为更简单的独立线性关系。
这可能是一个陌生的概念,所以这里有三个例子:
- 分类(Categorical):您有一个分类属性,其值为 [红, 绿, 蓝],您可以将其拆分为3个二元属性:红、绿、蓝,并为每个实例在每个属性上赋予1或0的值。
- 实数(Real):您有一个实数值,范围从0到1000。您可以创建10个二元属性,每个属性代表一个值的区间(例如,0-99为区间1,100-199为区间2,等等),并为每个实例在对应的区间上分配一个二元值(1/0)。
我建议您一步一步地执行这个过程,对每一次修改都创建一个新的测试/训练数据集,然后在这个数据集上测试算法。这将帮助您直观地了解数据库中的哪些属性和特征向算法暴露了更多或更少的信息,以及这对性能指标的影响。您可以用这些结果来指导进一步的极限分解或聚合。
总结
在这篇文章中,您学习了三种用于提升机器学习算法在您的问题上表现的策略:
- 算法调优,将发现最佳模型视为在模型参数空间中的搜索问题。
- 集成方法,将多个模型的预测结果结合起来。
- 极限特征工程,将数据准备中看到的属性分解和聚合推向极致。
资源
如果您想更深入地研究这个主题,请查看以下资源。
- 《黑客的机器学习》,第12章:模型比较
- 《数据挖掘:实用的机器学习工具与技术》,第7章:转换:输入与输出的工程化
- 《统计学习基础:数据挖掘、推断与预测》,第16章:集成学习
更新
关于从算法中获得更多效果的20个技巧和窍门,请参阅这篇文章:
内容非常清晰,我真正感兴趣的是第二种方法,集成方法。通过这种方法,可以调用许多人工智能算法来解决一个问题,但组织不同的算法似乎很难。就我所知,最常用的方法仍然是选择和创造更多有用的特征(极限特征工程)或在算法调优后选择最佳算法。
我想再问一些关于写博客的问题。您的网站看起来非常棒,我非常喜欢。我想问的是:
1. 如何让插入的图片像您文章中那样,居中并带边框,底部还能显示更多信息?
2. 您是如何编写数学公式的,有什么好的LaTeX插件推荐吗?
非常感谢您的耐心。期待您的回复。
谢谢!
我使用WordPress和Canvas插件,它为我完成了所有的格式化工作。我没有任何LaTeX插件,我的网站上通常也没有数学公式。
在现实世界中,Jason,我认为我们会根据手头问题和数据集的时间与复杂性,使用这三种方法中的一种或全部。这种方法绝对不是线性的——正如软件工程中那句老话“视情况而定”。这是一篇很好的文章。我喜欢您将机器学习与软件工程师联系起来的方式。谢谢您。
Sravan,说得好。
随便问个问题——
我想预测一行数据的结果,模型的准确率是50%,那么如果我连续重新预测3次,准确率会发生什么变化?
会变成87.5% (50+25+12.5)吗?
还是会保持50%?
嗨,Jason,
首先,感谢这篇精彩的文章。我有一个关于极限特征工程的问题。在“实数”的例子中,您说有时将连续特征转换为二元特征(在您的例子中是10个二元特征)是有益的。我理解这在实践中是有益的,但您能详细解释一下为什么工程化的二元特征对于某些机器学习算法来说比原始特征更好吗?为什么工程化的特征更容易让某些机器学习算法发现数据中的模式?如果您能提供一个简单的例子就太好了。谢谢。
有些算法会为不同的分类变量建模。通过将它们二元化,我们把复杂性从模型中抽离出来,放到了输入表示中,这意味着模型需要做的工作更少了。
你好 Jason,
一如既往,解释非常简单明了。我有一个关于Boosting的问题,您提到“在相同的训练数据上训练不同的算法”。据我所知,AdaBoost算法最初为所有训练数据点赋予相同的权重,然后训练一个分类器。被错误分类的数据点随后获得更高的权重,并被包含在用于下一个分类器的训练数据中。例如,请看 http://mccormickml.com/2013/12/13/adaboost-tutorial/(决定哪些数据点应被包含以训练下一个分类器的第三个方程)。
您提到的Boosting与AdaBoost有什么不同吗?
我对boosting的描述有些草率了。我在这里介绍了adaboost:
https://machinelearning.org.cn/boosting-and-adaboost-for-machine-learning/
感谢Jason提供的信息。我有一个关于算法调优的问题。
数据的“类型”会影响参数的行为吗?
换句话说,假设一个算法有n个参数,对于给定的训练集,增加参数n1会得到更好的预测分数。
如果我们使用不同类型的数据,增加n1仍然有帮助吗?
这真的取决于您正在处理的具体数据。
我建议尝试一些改变,并评估它们对模型能力的影响。
谢谢。
感谢Jason的好文章。我个人觉得第三种策略(极限特征工程)是所有策略中最难的。这可能是因为它最耗时,但也往往是最有帮助的。集成方法也是一个很好的辅助手段。
在您介绍的这些技术中,哪一种对您最有帮助?
不错。
集成方法对我帮助很大。主要是基于对问题/数据集的不同视角构建的模型的集成。
我认为分类值也参与了归一化过程,您希望确保所有数值和分类列的值都落在-1、0、1的范围内。使用pd.get_dummies()或键值对有助于分类列的归一化。总而言之,我经常单独测试参数中每个特征的准确性,以确定哪些特征应该构成我的输入,从而提高准确性。非常有益的文章,祝贺。
这取决于您的数据准备步骤。如果分类变量经过了独热编码,就不需要对它们进行缩放。