集成方法:产生改进机器学习结果的优雅技术
已发表: 2022-03-11集成方法是创建多个模型然后将它们组合以产生改进结果的技术。 集成方法通常会产生比单个模型更准确的解决方案。 在许多机器学习竞赛中都是这种情况,获胜的解决方案使用了集成方法。 在流行的 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 regression predictions = 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 classification stacking_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 classification stacking_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(也称为“Bagging”)这个名称总结了该策略的关键要素。 在 bagging 算法中,第一步涉及创建多个模型。 这些模型是使用与数据集的随机子样本相同的算法生成的,这些子样本是使用自举抽样方法从原始数据集中随机抽取的。 在 bootstrap 抽样中,一些原始示例出现了不止一次,并且一些原始示例不存在于示例中。 如果要创建具有 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_datasetbagging 的第二步是聚合生成的模型。 为此目的使用众所周知的方法,例如投票和平均。
整个伪代码如下所示:
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 regression return final_predictions在 bagging 中,每个子样本可以相互独立地生成。 所以生成和训练可以并行进行。
您还可以在某些算法中找到 bagging 策略的实现。 例如,随机森林算法使用 bagging 技术,但存在一些差异。 随机森林使用随机特征选择,其基本算法是决策树算法。
Boosting:将弱模型转换为强模型
术语“提升”用于描述能够将弱模型转换为强模型的一系列算法。 如果模型的错误率很高,则该模型很弱,但性能不是随机的(导致二元分类的错误率为 0.5)。 Boosting 通过使用相同的数据集训练每个模型,但其中实例的权重会根据上次预测的误差进行调整,从而逐步构建一个集成。 主要思想是迫使模型专注于困难的实例。 与 bagging 不同,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 偏见
