使用H2O进行集成学习
介绍
集成学习就是组合多个机器学习算法,从而得到更好的预测性能。许多流行的现代机器学习算法实际上就是集成。比如说随机森林 和 Gradient Boosting Machine (GBM)都是2个集成学习器。Bagging(例如随机森林)和boosting(例如GBM)是集成方法,其采用一系列弱学习器(例如,决策树)来得到单个,强大的集成学习器。
H2O的Stacked集成算法是有监督的集成算法,通过stacking来找到分类器的最优组合方式。此方法目前支持回归和二分类任务,计划在将来的版本中提供多分类支持。
在版本3.10.3.1中,集成算法被添加到了H2O内核中,H2O将原生支持集成算法。R语言的h2oEnsemble包是一个独立于H2O对该方法的一个实现,然而对于新项目,我们建议使用原生H2O版本,如下所述。
Stacking / Super Learning
Stacking也可以称之为Super Learning 或Stacked Regression,是一类涉及训练二级“元学习器”(或称次级学习器)以找到初级学习器的最佳组合的算法。与bagging和boosting不同,stacking的目的是将强大的,多样化的学习器集合在一起。
虽然stacking的概念最初是在1992年提出的,但是在2007年一篇叫“Super Learner”的论文出版之前,还没有关于stacking的理论证明。在这篇论文中表明 Super Learner 集成代表一个渐近最优的学习系统。
一些集合方法被广泛地称为stacking,然而,Super Learner集成与其他方法的区别是,他是通过使用交叉验证来形成所谓的“level-one”数据,这数据也可以说成是次级分类器或某种“组合”算法的训练数据集。下面提供了更多关于Super Learner 算法的细节。
Super Learner Algorithm
以下步骤描述了在训练和测试Super Learner集成中涉及的各个任务。H2O自动执行以下大部分步骤,以便您可以快速轻松地构建H2O集成模型。
- 配置集成
- 指定一个包含L个初级学习器的列表(使用一组特定的模型参数)。
- 指定一个次级学习器。
- 训练集成模型
- 在训练集上训练每个初级学习器,共L个。
- 对每一个学习器中执行k折交叉验证,并记录L个分类器在每个交叉验证上的预测值。
- 每一个初级学习器上的N个交叉验证预测值可以组成一个新的N x L 矩阵,该矩阵与原始响应向量一起被称为“level-one”数据(N=训练集样本数)。
- 在“level-one”数据上训练次级学习器。这个“集成模型”包含L个初级学习器和一个次级学习器,然后可以用来在测试集上生成预测。
- 在新数据上进行预测
- 为了进行集成预测,我们首先从初级学习器上得到预测值。
- 将这些预测值送到次级学习器中从而产生集成预测。
定义一个H2O Stacked集成模型
- model_id: 指定要应用的模型自定义名称。 默认情况下,H2O会自动生成目标密钥。
- training_frame: 指定模型训练集。
- validation_frame: 指定模型验证集。
- selection_strategy: 指定选择要stacking的模型的策略。注意,
choose_all
是当前唯一的选择策略实现。 - base_models: 指定可堆叠在一起的模型ID列表。模型必须使用
nfolds
> 1进行交叉验证,它们都必须使用相同的折数进行交叉验证,并且keep_cross_validation_folds
必须设置为True。
关于基本模型:保证初级学习器之间完全相同折数的一种方法是在所有初级学习器中设置fold_assignment
=“Modulo”。目前,使用fold_assignment
=“Modulo”来训练初级学习器是一个严格的要求,但在下一个版本中将放宽,可以允许用户指定折数,或用相同的随机种子来随机产生折数。
另外在将来的版本中,将存在额外的次级学习器参数,允许用户指定所使用的次级学习器算法。目前,次级学习器固定为具有非负权重的H2O GLM。
你可以在这里看到 H2O’s Stacked Ensemble的发展进度。
例子
library(h2o)
h2o.init(nthreads = -1)
# 读入一个二分类数据
train <- h2o.importFile("https://s3.amazonaws.com/erin-data/higgs/higgs_train_10k.csv")
test <- h2o.importFile("https://s3.amazonaws.com/erin-data/higgs/higgs_test_5k.csv")
#若读不进,先将网站输入浏览器中,再在本地读取
# Identify predictors and response
y <- "response"
x <- setdiff(names(train), y)
# 指定2分类响应变量类别为因子
train[,y] <- as.factor(train[,y])
test[,y] <- as.factor(test[,y])
# 设置交叉验证折数(为了产生level-one数据来进行stacking)
nfolds <- 5
# 有如下几种方法来组合模型列表以进行堆叠:
# 1. 逐个训练模型并将它们放在一个列表里
# 2. 用h2o.grid来训练一个不同参数的模型
# 3. 用h2o.grid来训练多个不同参数的模型
# 注意: 所有的初级学习器必须具有相同的交叉验证折数,并且交叉验证预测值必须保留。
# 1. 2个模型的集成 (GBM + RF)
# Train & Cross-validate a GBM
my_gbm <- h2o.gbm(x = x,
y = y,
training_frame = train,
distribution = "bernoulli",
ntrees = 10,
max_depth = 3,
min_rows = 2,
learn_rate = 0.2,
nfolds = nfolds,
fold_assignment = "Modulo",
keep_cross_validation_predictions = TRUE,
seed = 1)
# Train & Cross-validate a RF
my_rf <- h2o.randomForest(x = x,
y = y,
training_frame = train,
ntrees = 50,
nfolds = nfolds,
fold_assignment = "Modulo",
keep_cross_validation_predictions = TRUE,
seed = 1)
# Train a stacked ensemble using the GBM and RF above
ensemble <- h2o.stackedEnsemble(x = x,
y = y,
training_frame = train,
model_id = "my_ensemble_binomial",
base_models = list(my_gbm@model_id, my_rf@model_id))
#在测试集上评估集成模型性能
perf <- h2o.performance(ensemble, newdata = test)
# 比较初级学习器在测试集上的性能
perf_gbm_test <- h2o.performance(my_gbm, newdata = test)
perf_rf_test <- h2o.performance(my_rf, newdata = test)
baselearner_best_auc_test <- max(h2o.auc(perf_gbm_test), h2o.auc(perf_rf_test))
ensemble_auc_test <- h2o.auc(perf)
print(sprintf("Best Base-learner Test AUC: %s", baselearner_best_auc_test))
print(sprintf("Ensemble Test AUC: %s", ensemble_auc_test))
#在训练集上产生预测
pred <- h2o.predict(ensemble, newdata = test)
# 2. Generate a random grid of models and stack them together
# GBM 超参数
learn_rate_opt <- c(0.01, 0.03)
max_depth_opt <- c(3, 4, 5, 6, 9)
sample_rate_opt <- c(0.7, 0.8, 0.9, 1.0)
col_sample_rate_opt <- c(0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8)
hyper_params <- list(learn_rate = learn_rate_opt,
max_depth = max_depth_opt,
sample_rate = sample_rate_opt,
col_sample_rate = col_sample_rate_opt)
search_criteria <- list(strategy = "RandomDiscrete",
max_models = 3,
seed = 1)
gbm_grid <- h2o.grid(algorithm = "gbm",
grid_id = "gbm_grid_binomial",
x = x,
y = y,
training_frame = train,
ntrees = 10,
seed = 1,
nfolds = nfolds,
fold_assignment = "Modulo",
keep_cross_validation_predictions = TRUE,
hyper_params = hyper_params,
search_criteria = search_criteria)
#使用GBM网格参数来训练一个stacked ensemble模型
ensemble <- h2o.stackedEnsemble(x = x,
y = y,
training_frame = train,
model_id = "ensemble_gbm_grid_binomial",
base_models = gbm_grid@model_ids)
# 在测试集上评估集成模型性能
perf <- h2o.performance(ensemble, newdata = test)
# 在测试集上比较初级学习器性能
.getauc <- function(mm) h2o.auc(h2o.performance(h2o.getModel(mm), newdata = test))
baselearner_aucs <- sapply(gbm_grid@model_ids, .getauc)
baselearner_best_auc_test <- max(baselearner_aucs)
ensemble_auc_test <- h2o.auc(perf)
print(sprintf("Best Base-learner Test AUC: %s", baselearner_best_auc_test))
print(sprintf("Ensemble Test AUC: %s", ensemble_auc_test))
# 在训练集上产生预测
pred <- h2o.predict(ensemble, newdata = test)
FAQ
- 集成模型总是比单个模型更好吗?
希望是这样,但并不总是如此。这就是为什么总要检查你的集成模型性能,并将其与个体初级学习器的性能进行比较。
- 怎么提高集成模型的性能
如果你发现你的集成模型性能不如最优的初级学习器,那么你可以尝试几个不同的东西。
首先,看看是否有初级学习器的表现比其他初级学习器差很多(例如,GLM)。若有,将它从集成模型中移除,并在此建模。
其次,你应该增加初级学习器的个数,特别是增加初级学习器的多样性。
未来新版本中添加了自定义次级学习器 支持,你可以尝试不同的次级学习器。
- 该算法如何处理响应变量中的高度不平衡数据
在初级学习器中指定
balance_classes
,class_sampling_factors
和max_after_balance_size
来进行过抽样或者欠抽样。
拓展阅读
- 2017年1月的Ensemble slidedeck提供了H2O中新的Stacked Ensemble方法的概述,以及与以前存在的h2oEnsemble R软件包的比较。
参考文献
David H. Wolpert. “Stacked Generalization.” Neural Networks. Volume 5. (1992)
Leo Breiman. “Stacked Regressions.” Machine Learning, 24, 49-64 (1996)
作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者a358463121专栏:http://blog.csdn.net/a358463121,如果涉及源代码请注明GitHub地址:https://github.com/358463121/。商业使用请联系作者。