集成方法(产生改进的机器学习结果的优雅技术)

本文概述

  • 基于投票和平均的合奏方法
  • 堆叠多个机器学习模型
  • 自举聚合
  • 促进:将弱模型转化为强模型
  • 总结
集成方法是创建多个模型, 然后将它们组合以产生改进结果的技术。集成方法通常会比单个模型产生更准确的解决方案。在许多机器学习竞赛中就是这种情况, 其中获胜的解决方案使用集成方法。在流行的Netflix竞赛中, 获胜者使用集成方法来实现强大的协作过滤算法。另一个例子是KDD 2009, 获奖者还使用了合奏方法。你还可以找到在Kaggle比赛中使用这些方法的获胜者, 例如, 这里是CrowdFlower比赛获胜者的访谈。
在继续本文之前, 了解一些术语很重要。在整篇文章中, 我都使用术语” 模型” 来描述经过数据训练的算法的输出。然后将此模型用于进行预测。该算法可以是任何机器学习算法, 例如逻辑回归, 决策树等。这些模型用作集成方法的输入时, 称为” 基础模型” 。
在这篇博客文章中, 我将介绍合奏的分类方法, 并介绍一些广为人知的合奏方法:投票, 堆叠, 打包和增强。
基于投票和平均的合奏方法 投票和平均是最简单的两种合奏方法。它们都很容易理解和实施。投票用于分类, 平均用于回归。
集成方法(产生改进的机器学习结果的优雅技术)

文章图片
在这两种方法中, 第一步都是使用某些训练数据集创建多个分类/回归模型。可以使用同一训练数据集和相同算法的不同分割来创建每个基本模型, 或者使用具有不同算法的相同数据集或任何其他方法来创建每个基本模型。以下Python式伪代码显示了使用不同算法的相同训练数据集的用法。
train = load_csv("train.csv") target = train["target"] train = train.drop("target") test = load_csv("test.csv")algorithms = [logistic_regression, decision_tree_classification, ...] #for classification algorithms = [linear_regression, decision_tree_regressor, ...] #for regressionpredictions = matrix(row_length=len(target), column_length=len(algorithms))for i, algorithm in enumerate(algorithms): predictions[, i] = algorithm.fit(train, target).predict(test)

根据上面的伪代码, 我们为每个模型创建了预测, 并将其保存在称为预测的矩阵中, 其中每一列都包含来自一个模型的预测。
多数投票
每种模型都会对每个测试实例进行预测(投票), 最终的输出预测将获得超过一半的选票。如果没有一个预测获得超过一半的选票, 那么我们可以说集成方法无法对此实例做出稳定的预测。尽管这是一种广泛使用的技术, 但是你可以尝试投票最多的预测(即使少于投票的一半)作为最终预测。在某些文章中, 你可能会看到此方法称为” 多个投票” 。
加权投票
与多数表决不同, 在多数表决中, 每个模型都具有相同的权利, 我们可以提高一个或多个模型的重要性。在加权投票中, 你需要多次计算更好模型的预测。找到合理的权重取决于你。
简单平均
在简单的平均方法中, 对于测试数据集的每个实例, 都会计算平均预测。此方法通常会减少过拟合并创建更平滑的回归模型。下面的伪代码显示了这种简单的平均方法:
final_predictions = [] for row_number in len(predictions): final_predictions.append( mean(prediction[row_number, ]) )

加权平均
加权平均是简单平均的略微修改版本, 其中每个模型的预测值乘以权重, 然后计算其平均值。以下伪代码显示了加权平均:
weights = [..., ..., ...] #length is equal to len(algorithms) final_predictions = [] for row_number in len(predictions): final_predictions.append( mean(prediction[row_number, ]*weights) )

堆叠多个机器学习模型 堆叠, 也称为堆叠概括, 是一种集成方法, 其中使用另一种机器学习算法将模型组合在一起。基本思想是使用训练数据集训练机器学习算法, 然后使用这些模型生成新的数据集。然后, 此新数据集将用作组合器机器学习算法的输入。
堆叠过程的伪代码总结如下:
base_algorithms = [logistic_regression, decision_tree_classification, ...] #for classificationstacking_train_dataset = matrix(row_length=len(target), column_length=len(algorithms)) stacking_test_dataset = matrix(row_length=len(test), column_length=len(algorithms))for i, base_algorithm in enumerate(base_algorithms): stacking_train_dataset[, i] = base_algorithm.fit(train, target).predict(train) stacking_test_dataset[, i] = base_algorithm.predict(test)final_predictions = combiner_algorithm.fit(stacking_train_dataset, target).predict(stacking_test_dataset)

如你在上面的伪代码中所看到的, 使用基本算法的输出来生成组合器算法的训练数据集。在伪代码中, 使用训练数据集生成基本算法, 然后再次使用同一数据集进行预测。但是我们知道, 在现实世界中, 我们不会使用相同的训练数据集进行预测, 因此要克服此问题, 你可能会看到一些拆分训练数据集的实现方式。在下面, 你可以看到一个伪代码, 其中在训练基本算法之前将训练数据集分割开:
base_algorithms = [logistic_regression, decision_tree_classification, ...] #for classificationstacking_train_dataset = matrix(row_length=len(target), column_length=len(algorithms)) stacking_test_dataset = matrix(row_length=len(test), column_length=len(algorithms))for i, base_algorithm in enumerate(base_algorithms): for trainix, testix in split(train, k=10): #you may use sklearn.cross_validation.KFold of sklearn library stacking_train_dataset[testcv, i] = base_algorithm.fit(train[trainix], target[trainix]).predict(train[testix]) stacking_test_dataset[, i] = base_algorithm.fit(train).predict(test)final_predictions = combiner_algorithm.fit(stacking_train_dataset, target).predict(stacking_test_dataset)

自举聚合 Bootstrap Aggregating(也称为” 袋装” )一词概括了该策略的关键要素。在装袋算法中, 第一步涉及创建多个模型。这些模型是使用相同的算法生成的, 具有数据集的随机子样本, 这些样本是通过自举抽样方法从原始数据集中随机抽取而来的。在引导抽样中, 一些原始示例出现了多次, 而样本中没有一些原始示例。如果要创建包含m个元素的子数据集, 则应从原始数据集中选择一个随机元素m次。并且, 如果目标是生成n个数据集, 则请执行此步骤n次。
集成方法(产生改进的机器学习结果的优雅技术)

文章图片
最后, 我们有n个数据集, 每个数据集中的元素数为m。以下Python式伪代码显示了引导程序采样:
def bootstrap_sample(original_dataset, m): sub_dataset = [] for i in range(m): sub_dataset.append( random_one_element(original_dataset) ) return sub_dataset

【集成方法(产生改进的机器学习结果的优雅技术)】套袋的第二步是聚合生成的模型。为此, 使用了众所周知的方法, 例如投票和平均。
整个伪代码如下所示:
def bagging(n, m, base_algorithm, train_dataset, target, test_dataset): predictions = matrix(row_length=len(target), column_length=n) for i in range(n): sub_dataset = bootstrap_sample(train_dataset, m) predictions[, i] = base_algorithm.fit(original_dataset, target).predict(test_dataset)final_predictions = voting(predictions) # for classification final_predictions = averaging(predictions) # for regressionreturn final_predictions

在装袋中, 每个子样本可以彼此独立地生成。因此, 生成和培训可以并行进行。
你还可以在某些算法中找到装袋策略的实现。例如, 随机森林算法使用装袋技术存在一些差异。随机森林使用随机特征选择, 其基本算法是决策树算法。
相关:深度学习教程:从感知器到深度网络
促进:将弱模型转化为强模型 术语” 增强” 用于描述能够将弱模型转换为强模型的一系列算法。如果该模型具有很大的错误率, 则它是弱模型, 但是性能不是随机的(二进制分类的错误率是0.5)。 Boosting通过使用相同的数据集训练每个模型来逐步建立整体, 但根据最后一次预测的误差调整实例的权重。主要思想是迫使模型专注于困难的实例。与装袋不同, 增强是一种顺序方法, 因此你不能在此处使用并行操作。
Boosting算法的一般过程定义如下:
def adjust_dataset(_train, errors): #create a new dataset by using the hardest instances ix = get_highest_errors_index(train) return concat(_train[ix], random_select(train))models = [] _train = random_select(train) for i in range(n): #n rounds model = base_algorithm.fit(_train) predictions = model.predict(_train) models.append(model) errors = calculate_error(predictions) _train = adjust_dataset(_train, errors)final_predictions = combine(models, test)

Adjust_dataset函数返回包含最难实例的新数据集, 然后可以使用该数据集强制基础算法学习。
Adaboost是一种广为人知的算法, 它是一种增强方法。 Adaboost的创始人因其工作获得了哥德尔奖。通常, 首选决策树算法作为Adaboost的基础算法, 在sklearn库中, Adaboost的默认基础算法是决策树(AdaBoostRegressor和AdaBoostClassifier)。正如我们在上一段中讨论的那样, 相同的增量方法适用于Adaboost。在AdaBoost算法的每个步骤中收集的有关每个训练样本的” 硬度” 的信息被输入到模型中。 “ 调整数据集” 步骤不同于上述步骤, “ 合并模型” 步骤是通过使用加权投票来计算的。
总结 尽管集成方法可以通过设计复杂的算法并以高精度产生结果来帮助你赢得机器学习竞赛, 但在可解释性更重要的行业中, 它通常不是首选。但是, 这些方法的有效性是不可否认的, 在适当的应用中它们的好处是巨大的。在医疗保健等领域, 即使是机器学习算法准确性的最小改进也可能是真正有价值的。
有关:
  • 机器学习理论及其应用简介:带有示例的可视教程
  • 机器与信任:如何减轻AI偏差

    推荐阅读