找到一个准确的机器学习模型并不是项目的终点。
在本文中,您将了解如何在 R 中最终确定机器学习模型,包括:对未见过的数据进行预测、从头开始重建模型以及保存模型以备将来使用。
使用我的新书 《R 机器学习精通》 快速启动您的项目,其中包含分步教程和所有示例的R 源代码文件。
让我们开始吧。

在 R 中最终确定机器学习模型。
照片由 Christian Schnettelker 拍摄,保留部分权利。
最终确定机器学习模型
一旦您的测试环境中有一个准确的模型,您就基本完成了。但还没有。
仍有许多任务需要完成以最终确定您的模型。创建准确模型以用于数据集的所有想法都是为了对未见过的数据进行预测。
可能有三个任务需要您关注:
- 对未见过的数据进行新预测。
- 使用所有训练数据创建一个独立的模型。
- 将模型保存到文件,以便稍后加载和进行新数据预测。
一旦您最终确定了模型,就可以开始使用它了。您可以使用 R 模型直接使用。您还可以找出学习算法发现的关键内部表示(例如线性模型中的系数),并在另一个平台的新预测算法实现中使用它们。
在下一节中,您将了解如何在 R 中最终确定机器学习模型。
需要更多关于R机器学习的帮助吗?
参加我为期14天的免费电子邮件课程,了解如何在您的项目中使用R(附带示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
在 R 中最终确定预测模型
Caret 是一个出色的工具,可用于查找好的甚至最佳的机器学习算法及其参数。
但是,在发现一个足够准确的模型供您使用之后,您该怎么做?
一旦您在 R 中找到了一个好的模型,您就有三个主要关注点:
- 使用您调优的 caret 模型进行新预测。
- 使用整个训练数据集创建一个独立的模型。
- 将独立模型保存/加载到文件。
本节将指导您如何在 R 中完成这些任务。
1. 对新数据进行预测
您可以使用 `predict.train()` 函数使用通过 caret 调优的模型进行新预测。
在以下配方中,数据集被分为验证数据集和训练数据集。验证数据集也可以是存储在单独文件中的新数据集,并加载为数据框。
使用 LDA 找到了数据的良好模型。我们可以看到 caret 在 `finalModel` 变量中提供了对训练运行的最佳模型的访问。
我们可以通过调用 `predict` 并使用 `train` 的拟合来使用该模型进行预测,它将自动使用最终模型。我们必须通过 `newdata` 参数指定用于预测的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# 加载库 library(caret) library(mlbench) # 加载数据集 data(PimaIndiansDiabetes) # 创建 80%/20% 的训练和验证数据集 set.seed(9) validation_index <- createDataPartition(PimaIndiansDiabetes$diabetes, p=0.80, list=FALSE) validation <- PimaIndiansDiabetes[-validation_index,] training <- PimaIndiansDiabetes[validation_index,] # 训练模型并总结模型 set.seed(9) control <- trainControl(method="cv", number=10) fit.lda <- train(diabetes~., data=training, method="lda", metric="Accuracy", trControl=control) print(fit.lda) print(fit.lda$finalModel) # 估计在验证数据集上的技能 set.seed(9) predictions <- predict(fit.lda, newdata=validation) confusionMatrix(predictions, validation$diabetes) |
运行示例,我们可以看到训练数据集上的估计准确率为 76.91%。使用 `fit` 中的 `finalModel`,我们可以看到在保留的验证数据集上的准确率为 77.78%,与我们的估计非常相似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
重采样结果 Accuracy Kappa Accuracy SD Kappa SD 0.7691169 0.45993 0.06210884 0.1537133 ... 混淆矩阵和统计数据 Reference Prediction neg pos neg 85 19 pos 15 34 Accuracy : 0.7778 95% CI : (0.7036, 0.8409) No Information Rate : 0.6536 P-Value [Acc > NIR] : 0.000586 Kappa : 0.5004 Mcnemar's Test P-Value : 0.606905 Sensitivity : 0.8500 Specificity : 0.6415 Pos Pred Value : 0.8173 Neg Pred Value : 0.6939 Prevalence : 0.6536 Detection Rate : 0.5556 Detection Prevalence : 0.6797 Balanced Accuracy : 0.7458 'Positive' Class : neg |
2. 创建独立模型
在此示例中,我们调整了一个随机森林模型,其中 `mtry` 的值为 3 种,`ntree` 设置为 2000。通过打印 `fit` 和 `finalModel`,我们可以看到 `mtry` 的最佳值为 2。
现在我们知道了好的算法(随机森林)和好的配置(mtry=2, `ntree=2000`),我们可以直接使用所有训练数据来创建最终模型。我们可以在 Caret 模型列表 中查找 caret 使用的“`rf`”随机森林实现,并注意到它使用了 `randomForest` 包,进而使用了 `randomForest()` 函数。
该示例直接创建一个新模型,并使用它来预测新数据,在此情况下模拟为验证数据集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# 加载库 library(caret) library(mlbench) library(randomForest) # 加载数据集 data(Sonar) set.seed(7) # 创建 80%/20% 的训练和验证数据集 validation_index <- createDataPartition(Sonar$Class, p=0.80, list=FALSE) validation <- Sonar[-validation_index,] training <- Sonar[validation_index,] # 训练模型并总结模型 set.seed(7) control <- trainControl(method="repeatedcv", number=10, repeats=3) fit.rf <- train(Class~., data=training, method="rf", metric="Accuracy", trControl=control, ntree=2000) print(fit.rf) print(fit.rf$finalModel) # 使用所有训练数据创建最终的独立模型 set.seed(7) finalModel <- randomForest(Class~., training, mtry=2, ntree=2000) # 使用最终模型对“新数据”进行预测 final_predictions <- predict(finalModel, validation[,1:60]) confusionMatrix(final_predictions, validation$Class) |
我们可以看到最佳配置的估计准确率为 85.07%。我们可以看到在所有训练数据集上训练的最终独立模型预测验证数据集的准确率为 82.93%。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
随机森林 167 个样本 60 个预测变量 2 个类别:'M', 'R' 无预处理 重采样:交叉验证(10 折,重复 3 次) 样本量汇总:151, 150, 150, 150, 151, 150, ... 跨调优参数的重采样结果 mtry Accuracy Kappa Accuracy SD Kappa SD 2 0.8507353 0.6968343 0.07745360 0.1579125 31 0.8064951 0.6085348 0.09373438 0.1904946 60 0.7927696 0.5813335 0.08768147 0.1780100 Accuracy 用于选择最佳模型,使用最大的值。 最终用于模型的值是 mtry = 2。 ... 调用 randomForest(x = x, y = y, ntree = 2000, mtry = param$mtry) 随机森林类型:分类 树的数量:2000 每次拆分尝试的变量数:2 OOB 估计错误率:14.37% 混淆矩阵 M R class.error M 83 6 0.06741573 R 18 60 0.23076923 ... 混淆矩阵和统计数据 Reference Prediction M R M 20 5 R 2 14 Accuracy : 0.8293 95% CI : (0.6794, 0.9285) No Information Rate : 0.5366 P-Value [Acc > NIR] : 8.511e-05 Kappa : 0.653 Mcnemar's Test P-Value : 0.4497 Sensitivity : 0.9091 Specificity : 0.7368 Pos Pred Value : 0.8000 Neg Pred Value : 0.8750 Prevalence : 0.5366 Detection Rate : 0.4878 Detection Prevalence : 0.6098 Balanced Accuracy : 0.8230 'Positive' Class : M |
一些更简单的模型,如线性模型,可以输出它们的系数。这很有用,因为您可以根据这些系数,用您选择的语言实现简单的预测过程,并使用系数在其他平台上获得相同的精度。随着表示复杂性的增加,这会变得更加困难。
3. 保存和加载您的模型
您可以将最佳模型保存到文件中,以便稍后加载并进行预测。
在此示例中,我们将 Sonar 数据集分为训练数据集和验证数据集。我们将验证数据集作为新数据来测试最终模型。我们使用训练数据集和最佳参数训练最终模型,然后将其保存到名为 `final_model.rds` 的文件中,该文件位于本地工作目录中。
模型已被序列化。稍后可以通过调用 `readRDS()` 来加载它,并将加载的对象(在此例中为随机森林拟合)分配给一个变量名。然后,加载的随机森林用于对新数据(在此例中为验证数据集)进行预测。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# 加载库 library(caret) library(mlbench) library(randomForest) library(doMC) registerDoMC(cores=8) # 加载数据集 data(Sonar) set.seed(7) # 创建 80%/20% 的训练和验证数据集 validation_index <- createDataPartition(Sonar$Class, p=0.80, list=FALSE) validation <- Sonar[-validation_index,] training <- Sonar[validation_index,] # 使用所有训练数据创建最终的独立模型 set.seed(7) final_model <- randomForest(Class~., training, mtry=2, ntree=2000) # 将模型保存到磁盘 saveRDS(final_model, "./final_model.rds") # 稍后... # 加载模型 super_model <- readRDS("./final_model.rds") print(super_model) # 使用最终模型对“新数据”进行预测 final_predictions <- predict(super_model, validation[,1:60]) confusionMatrix(final_predictions, validation$Class) |
我们可以看到验证数据集上的准确率为 82.93%。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
混淆矩阵和统计数据 Reference Prediction M R M 20 5 R 2 14 Accuracy : 0.8293 95% CI : (0.6794, 0.9285) No Information Rate : 0.5366 P-Value [Acc > NIR] : 8.511e-05 Kappa : 0.653 Mcnemar's Test P-Value : 0.4497 Sensitivity : 0.9091 Specificity : 0.7368 Pos Pred Value : 0.8000 Neg Pred Value : 0.8750 Prevalence : 0.5366 Detection Rate : 0.4878 Detection Prevalence : 0.6098 Balanced Accuracy : 0.8230 'Positive' Class : M |
总结
在本文中,您学习了三个用于处理最终预测模型的配方:
- 如何使用 caret 调优的最佳模型进行预测。
- 如何使用 caret 调优期间找到的参数创建独立模型。
- 如何保存和稍后加载独立模型并使用它进行预测。
您可以尝试这些配方以更好地理解它们。您还可以将它们用作模板,并将它们复制粘贴到您当前或下一个机器学习项目中。
下一步
您是否尝试过这些食谱?
- 启动您的 R 交互式环境。
- 键入或复制粘贴上述食谱并进行尝试。
- 使用 R 中的内置帮助来了解有关所用函数的更多信息。
您有问题吗?在评论中提问,我将尽力回答。
您好。我一直在研究示例和一些我自己的模型,我有一个关于预处理我的数据的问题。
在训练模型时,我使用了 `preProcess` 参数来居中和缩放数据。
当我有一个新的数据集要在训练后运行我的模型时,模型知道也要预处理该数据吗?还是我必须在应用模型之前手动缩放和居中新数据集?保存和重新加载最终模型后呢?
这是文档中不太清晰的地方之一。
您好 John,问得好。
最安全的方法是单独管理数据缩放,并保存数据的缩放版本以及未来缩放新数据所需的系数。
根据 caret 的文档,在训练期间应用的任何预处理都将应用于之后对新数据调用 `predict()`。
http://topepo.github.io/caret/model-training-and-tuning.html#preproc
我希望这在您保存训练模型时会得到保留,但我建议您进行测试(保存前后的结果是否与包含预处理的模型相匹配)。
将此应用于非分类问题是否存在问题?
会有什么不同?
没有明显的区别。
嗯…
Error: Metric Accuracy not applicable for regression models (错误:回归模型不适用 Accuracy 指标)
Error in `[.data.frame`(validation, , 1:60) : undefined columns selected (错误:未定义选定的列)
1. 和 2. 已修复,但仍然收到错误
Error in confusionMatrix.default(final_predictions, validation$n5) (错误:confusionMatrix.default(final_predictions, validation$n5))
数据不能有比参考值更多的级别。
如果我打印 `final_predictions`,我会得到
3 6 9 11 18 19 21 26 29 39 47 50 61 63 74 92 94 95 97 99 101 104 111 114
M R M R R R M R M R M R R R R R R R R M M R M M
117 120 126 129 137 138 145 146 148 155 160 164 170 171 173 191 206
M M M M M M M M M M M M M R M M M
最后一个数据点的行索引是 206。Sonar 的原始数据结束索引是 208。
那么未见的数据在哪里?行索引是否相互独立?
如何使用示例 2 预测未来一个时间步的未见数据?
Jason 医生,感谢这篇宝贵的文章。
我可能有点跑题了,但我最近一直在想,是否有可能将训练好的模型保存为某种标准格式,以便(1)可以通过网络发送,以及(2)即使由不同的语言(例如 Java)解析?
您是否了解 R 或(可能)其他机器学习/统计套件的类似之处?
如果问题被认为不相关,敬请原谅。
我相信存在标准模型格式,但我不是专家。
请参阅预测模型标记语言
https://en.wikipedia.org/wiki/Predictive_Model_Markup_Language
Jason 您好 – 感谢您的示例!这对您来说非常及时和有用。
很高兴听到这个消息!
嗨 Jason
很棒的网站!感谢您提供非常有价值的信息。
我有一个关于“独立模型”的小问题。为什么在使用 caret 模型后还需要使用它?我认为它们是等效的(例如,在这个“rf”方法示例中,caret 使用了 randomForest 模型),我现在有点困惑。
祝好,
克里斯
Caret 是模型的包装器,可以帮助我们找到要使用的模型。
一旦我们知道要使用哪个模型,我们就可以直接使用它,而无需 caret 包装器(如果我们愿意的话)。
谢谢!
嗨,Jason,
出色的工作,对我们正在学习的人来说非常有用。只有一个问题。假设我有 100 个数据点,我将其分为训练和测试(80% 和 20%)。我拟合模型,看到准确率为 75%。我的问题是如何实现这个模型,以便当第 101 和第 102 个数据点到达时,这个模型能够运行并为我提供一些分类?
我认为这篇帖子展示了如何保存模型并加载它以对新数据进行预测。
也许这篇帖子会让事情更清楚。
https://machinelearning.org.cn/train-final-machine-learning-model/
你好,Jason。
上面的“最终确定机器学习模型”文章很有帮助,我迫不及待想尝试一下。但是,我注意到它只进行了一次预测。是否有办法根据标准一次获得多个预测,并将它们作为列表给出?例如:
项目 1…结果
项目 2…结果
是的,`predict` 函数默认支持此功能。
尊敬的先生,
我正在做分布式系统负载均衡的论文,我需要根据实时数据集中的过去负载信息来预测未来传入的任务。我该如何将此技术应用于我的工作中?
这可能是您开始的好地方。
https://machinelearning.org.cn/start-here/#timeseries
您好 Jason,我有一个问题,也许您可以帮助我。
我正在使用 caret,我需要打印随机森林最佳模型的函数,我说的是所有的树,有 100 棵。
我知道使用 `model$finalModel` 可以打印神经网络或 rpart 树的函数,但此命令不打印随机森林的所有树或提升树的函数。
您知道如何做到这一点吗?
谢谢
抱歉,我以前从未从随机森林中打印过所有树。也许有第三方工具可以帮助?
Hey Jason!感谢您的文章。我有一个问题。
我为今年的学生入学预测项目构建了一个高度准确的随机森林模型。现在我已保存模型,并希望将此模型用于去年的数据。但是,去年的数据变量数量已发生变化。如何处理这种情况?是否有任何方法可以缩放此模型以适应新情况?
谢谢!
这个过程将帮助你系统地解决问题
https://machinelearning.org.cn/start-here/#process
谢谢 Jason!
各位好!什么 ML 工具(回归模型)适合预测呼叫中心呼叫量?
这个过程将帮助你解决你的预测建模问题
https://machinelearning.org.cn/start-here/#process
嗨,Jason,
非常感谢这篇精彩的文章!
我想知道以下过程(基本上是您在这篇文章中所做的)是否被认为是 ML 和 DS 中的最佳实践或常见实践?
1. 执行交叉验证来调整超参数
2. 使用优化后的超参数训练整个训练数据集以达到最佳准确度?
另外,在第3部分关于保存和加载模型时,我遇到了R中doMC包的问题,并且我知道doMC在Windows上无法使用。您能为我提供一个替代的解决方案吗?
非常感谢。
是的,您可以在这里了解更多
https://machinelearning.org.cn/train-final-machine-learning-model/
doMC在Windows上可能不受支持。也许暂时将其注释掉?
嗨,Jason,
如果我有一个大型的已保存模型。是否有更快的读取模型的方法?readRDS()需要5秒以上才能读取一个大小为51,000 KB的.rds文件。
非常感谢。
我不知道,抱歉。
你好。在选择最佳模型之后,我如何加载它,在哪里可以找到我的结果?例如,我想预测股票明天的价格。我如何加载我的最优神经网络,如何输入新的输入,以及在哪里可以找到我的实际结果?
谢谢你
我在上面的教程中展示了如何加载模型并进行预测。
一篇非常好的文章,非常有帮助,我想问你一个关于将我的“R语言-电信用户流失”预测模型部署到我的生产环境中的问题,我清楚保存独立程序以及如何在新测试数据上进行预测,我最近刚入职,所以我想了解这方面的信息,你能在这方面帮助我吗?或者请分享关于如何使用“预测模型”的相关链接。
我有一些建议可能会有所帮助
https://machinelearning.org.cn/deploy-machine-learning-model-to-production/
嗨,杰森,
我可以使用这段代码来处理时间序列数据集吗?
谢谢您。
也许可以。
嗨,杰森,
你能给我一些关于你在R中使用时间序列数据的机器学习教程吗?
谢谢您。
这是我在这里回答的一个常见问题
https://machinelearning.org.cn/faq/single-faq/do-you-have-material-on-time-series-in-r
我们应该使用所有训练数据还是所有数据(包括训练和验证数据)来训练独立的模型?
由于训练和验证数据都具有“真实”标签,我们是否应该使用所有带有真实标签的数据来训练最终的独立模型,还是只使用训练数据?我的想法是我们应该使用所有带有真实标签的数据来训练最终模型,以便预测未知数据。我说对了吗?您能确认一下吗?
一旦选择了模型/配置,就用所有可用的带标签数据对其进行拟合。
你好,
我创建了一个神经网络,用于将文本分类为有效或无效。它在我训练的环境中表现得非常好,但当我保存模型并将其带入新环境时,它的表现却不同。我已经给了它相同的数据进行预测,但结果却完全不同。
您知道这是为什么吗?
听起来模型过拟合了训练数据。
这可能有帮助
https://machinelearning.org.cn/introduction-to-regularization-to-reduce-overfitting-and-improve-generalization-error/
你好Jason,又一个非常有帮助的教程!
这对我测试和保存的一系列12个模型都运行良好。
然而,对于xgboost模型,当我重新加载它进行预测时,它在Rstudio的全局环境中显示为长度为0,大小为0 B,当我尝试运行时,出现了以下错误:“task 1 failed – “object ‘m2predict’ not found””。但是,此模型的RDS文件在我的硬盘上显示为386,450 KB。
我发现似乎有其他专门针对xgboost的函数(xgb.save?)这对于将来很有用。
除了重新训练模型,有没有办法让现有的RDS文件中的xgboost模型工作,或者将其转换为xgb.save文件类型?
提前感谢任何建议!
你好Jason,我找到了根本原因!
这与RDS无关。RDS似乎工作正常。
问题与基础模型中的变量名被堆叠到XGBoost中有关。
一切都好了。
再次感谢您的精彩教程!
做得好,很高兴听到这个消息。
也许可以尝试从命令行而不是在R studio中运行您的脚本?
你好Jason,我使用了R的clickstream包(对解析后的日志文件),它是一个统计模型,可以预测用户接下来会点击哪个链接。
我对模型的部署以及新数据到来时模型的更新感到很困惑,我想当新数据进来时,模型应该用所有数据(新的和旧的)进行训练,对吗?那么在这种情况下,我该怎么做呢?
附注:我是R的新手,正在自学数据科学,任何帮助都将不胜感激。
抱歉,我对那个包不熟悉。
通常,模型在可用数据上拟合,然后部署用于在新数据上进行预测。
流式数据可能非常不同,我在这方面不是专家。
嗨,Jason,
在上面的例子中,Sonar数据集只包含数值变量(没有因子)。
我的数据集同时包含因子和数值变量。正因为如此,通过“saveRDS”保存的森林在用“readRDS”重新加载森林以生成预测时会出错。
错误消息是“新数据中的预测变量类型与训练数据不匹配”。但我很确定并且多次检查了类型是相同的。
如果我将所有变量都转换为数值,就像您的例子一样,错误就会消失。
有什么建议吗?谢谢。
有些模型可能需要很长时间才能训练好。当模型在生产环境中实现时,时间因素是如何处理的?
提前感谢。
模型只训练一次,然后用于预测。
重新训练模型应该是一个罕见且计划性的事件——尽管这取决于领域以及它多久变化一次以至于需要更新模型。
一旦你训练了一个模型并得到了混淆矩阵,你怎么知道哪些变量对模型贡献最大(或具有最大的预测效果)?例如,回归分析会告诉你哪些变量是结果更好的预测因子。这在机器学习模型中可行吗?我认为Python中有一个“eli5.show_prediction”函数可以做到这一点,但我不知道R中有类似的函数。
其次,在使用机器学习时,我们可以控制数据中的依赖关系吗?如果我们有一个包含三个层级的数据集(例如,个体内的测试分数,学校内的测试分数),你能像使用多层模型那样控制依赖关系吗?
是的,一些模型,如决策树,会提供变量重要性得分。大多数模型不提供。
也许吧。你可以选择你要建模的内容,例如,跨测试/人员/学校。
嗨 Jason
非常好的文章。
如果我想将预测结果以csv格式查看,该怎么办?
这样,我就可以逐行比较实际数据和预测数据。
请帮助我。谢谢。
谢谢。
你可以进行预测,然后将预测结果保存到CSV文件中。
我做了,但是csv文件只保存了ID和预测值,我认为这些值只在“predict”中存在。我怎么能将它们与测试文件中的其他变量一起保存?
是的,创建一个新的矩阵或数据框,然后将其保存到文件中。如果这对您来说是新的,您可能需要查看文档。
Jason,您的工作非常出色。
我有几个Caret训练的模型,当它们被保存(saveRDS,压缩)时,它们的大小是100-200+ MB。我现在将它们部署到Shiny,它们需要很长时间才能加载,而且经常失败。
有没有办法减小模型大小,或者更好的办法是,有没有一个predict函数可以让我只传入方法和参数,而不包含所有训练/预处理/样本数据?
哇,这些模型真大!
也许模型也保存了整个训练数据集,你可以检查对象或API,看看是否是这种情况,然后清除它。
在某些情况下,直接使用/编写带有学习系数的predict函数(例如回归模型)可以非常有效。