集成模型predict()返回行数异常及预测存储合理性问询
caretEnsemble集成模型预测行数异常及单模型预测存储问题
操作步骤
- 使用
caretEnsemble::caretList()在鸢尾花(iris)数据集的10个随机抽取的80%子样本上训练多个模型,剩余20%作为保留集。 - 使用
caretEnsemble::caretEnsemble()对模型列表进行glm加权平均得到集成模型。 - 用
caret::predict()提取各单个模型及集成模型的预测结果,希望存入原iris数据集。
问题
单个模型predict返回结果行数为150(与iris数据集行数一致),但集成模型predict返回280行。
代码示例
# Packages library(tidyverse) library(caret) library(caretEnsemble) # Seed set.seed(123) # Data datasets::iris %>% select(1:3) -> iris # Folds for training (80% of iris, 10 resamples) folds <- createDataPartition(iris$Petal.Length, times = 10, p = 0.8, list = TRUE) # Train controls train.control <- trainControl(method = "cv", index = folds, savePredictions = TRUE) # List of models (generalized linear model, random forest) models <- caretList(iris[,1:2], iris[,3], methodList=c("glm", "rf"), trControl = train.control, tuneLength = 10) # Option 1: No specific train controls ens <- caretEnsemble(models) ens$ens_model$resample %>% nrow() # 25 predict(ens$ens_model) # 280 # Option 2: Train controls same as in caretList ens.2 <- caretEnsemble(models, trControl = train.control) ens.2$ens_model$resample %>% nrow() # 10 predict(ens.2$ens_model) # 280 # Compare to individual models predict(models$glm) # 150 predict(models$rf) # 150 iris$pred_glm <- predict(models$glm)
疑问
- 为何集成模型
predict()始终返回280行,远超数据集的150行? - 将单个模型的预测结果存入原数据集的方法是否存在严重缺陷、是否符合方法学规范?即是否仅存入了测试集的预测结果,还是意外混入了训练集的预测?
解答
1. 集成模型返回280行预测的原因
caretEnsemble训练的集成模型,是基于基模型交叉验证过程中的out-of-sample预测结果训练的加权模型。当你直接调用predict(ens$ens_model)而不指定newdata参数时,caret默认返回该集成模型在自身训练过程中保存的所有预测记录——也就是基模型在10次CV折叠中所有测试样本的预测结果总和。由于部分样本可能被多次选为测试集,最终总条数为280。
如果需要得到对原始150行iris数据集的预测,必须显式指定newdata参数,示例:
predict(ens$ens_model, newdata = iris[,1:2]) # 返回150行结果
2. 单模型预测存入原数据集的合理性分析
直接用predict(models$glm)得到的150行结果,是用最终训练好的基模型(基于全部150行数据训练的最优模型)对整个数据集的预测,并非仅包含CV测试集的结果——它同时包含了训练集和测试集样本的预测值。
这种做法本身没有“严重缺陷”,但要明确用途:
- 如果只是需要模型对全量数据的预测结果(比如用于后续分析),是可行的;
- 如果是要评估模型的泛化能力(比如计算预测误差),绝对不能用这个结果,因为训练集样本的预测会存在过拟合,无法反映模型真实性能。
如果需要每个样本在CV过程中作为测试集时的out-of-sample预测(即“留一”式的测试结果),应该从基模型的pred属性中提取,示例代码:
# 提取glm模型在CV中的所有测试集预测,并匹配到原数据集 cv_preds <- models$glm$pred %>% group_by(rowIndex) %>% slice_head(n=1) %>% # 若样本多次作为测试集,取第一次结果 select(rowIndex, pred) iris <- iris %>% mutate(pred_glm_cv = cv_preds$pred[match(row_number(), cv_preds$rowIndex)])
内容的提问来源于stack exchange,提问作者Dr. Fabian Habersack
相关产品推荐
相关产品推荐

