r - 调整 LASSO 模型并使用 tidymodels 进行预测
问题描述
我想为 LASSO 算法执行惩罚选择并使用tidymodels
. 我将使用波士顿住房数据集来说明这个问题。
library(tidymodels)
library(tidyverse)
library(mlbench)
data("BostonHousing")
dt <- BostonHousing
我首先将数据集拆分为训练/测试子集。
dt_split <- initial_split(dt)
dt_train <- training(dt_split)
dt_test <- testing(dt_split)
recipe
使用包定义预处理。
rec <- recipe(medv ~ ., data = dt_train) %>%
step_center(all_predictors(), -all_nominal()) %>%
step_dummy(all_nominal()) %>%
prep()
模型和工作流程的初始化。我用glmnet
引擎。mixture = 1
意味着我选择 LASSO 惩罚,penalty = tune()
意味着我稍后将使用交叉验证来选择最佳惩罚参数lambda
。
lasso_mod <- linear_reg(mode = "regression",
penalty = tune(),
mixture = 1) %>%
set_engine("glmnet")
wf <- workflow() %>%
add_model(lasso_mod) %>%
add_recipe(rec)
准备分层 5 折交叉验证和惩罚网格:
folds <- rsample::vfold_cv(dt_train, v = 5, strata = medv, nbreaks = 5)
my_grid <- tibble(penalty = 10^seq(-2, -1, length.out = 10))
让我们运行交叉验证:
my_res <- wf %>%
tune_grid(resamples = folds,
grid = my_grid,
control = control_grid(verbose = FALSE, save_pred = TRUE),
metrics = metric_set(rmse))
我现在能够从网格中获得最佳惩罚并更新我的工作流程以获得最佳惩罚:
best_mod <- my_res %>% select_best("rmse")
print(best_mod)
final_wf <- finalize_workflow(wf, best_mod)
print(final_wf)
== Workflow ===================================================================================================================
Preprocessor: Recipe
Model: linear_reg()
-- Preprocessor ---------------------------------------------------------------------------------------------------------------
2 Recipe Steps
* step_center()
* step_dummy()
-- Model ----------------------------------------------------------------------------------------------------------------------
Linear Regression Model Specification (regression)
Main Arguments:
penalty = 0.0278255940220712
mixture = 1
Computational engine: glmnet
到现在为止还挺好。现在我想将工作流应用于训练数据以获得我的最终模型:
final_mod <- fit(final_wf, data = dt_train) %>%
pull_workflow_fit()
现在问题来了。
final_mod$fit
是一个elnet
和glmnet
对象。它包含 75 个惩罚参数值的网格上的完整正则化路径。因此,前面的惩罚调整步骤几乎没有用。所以预测步骤失败:
predict(final_mod, new_data = dt)
返回错误:
Error in cbind2(1, newx) %*% nbeta :
invalid class 'NA' to dup_mMatrix_as_dgeMatrix
当然,我可以glmnet::cv.glmnet
用来获得最好的惩罚,然后使用该方法predict.cv.glmnet
,但我需要一个通用的工作流程,能够使用相同的界面处理多个机器学习模型。在文档中parsnip::linear_reg
有关于 glmnet 引擎的注释:
对于 glmnet 模型,无论给予惩罚的值如何,完整的正则化路径总是合适的。此外,还可以选择将多个值(或不传递值)传递给惩罚参数。在这些情况下使用 predict() 方法时,返回值取决于惩罚值。使用 predict() 时,只能使用单个惩罚值。当预测多个惩罚时,可以使用 multi_predict() 函数。它返回一个带有名为 .pred 的列表列的 tibble,其中包含一个包含所有惩罚结果的 tibble。
但是,我不明白我应该如何继续使用该tidymodels
框架获得调整后的 LASSO 模型的预测。该multi_predict
函数会引发与 相同的错误predict
。
解决方案
你真的很接近让一切正常工作。
让我们读入数据,将其拆分为训练/测试并创建重采样折叠。
library(tidymodels)
library(tidyverse)
library(mlbench)
data("BostonHousing")
dt <- BostonHousing
dt_split <- initial_split(dt)
dt_train <- training(dt_split)
dt_test <- testing(dt_split)
folds <- vfold_cv(dt_train, v = 5, strata = medv, nbreaks = 5)
现在让我们创建一个预处理配方。(请注意,prep()
如果您使用的是workflow()
; 如果您的数据很大,这可能会变慢,所以最好不要这样做,直到workflow()
稍后为您处理。)
rec <- recipe(medv ~ ., data = dt_train) %>%
step_center(all_predictors(), -all_nominal()) %>%
step_dummy(all_nominal())
现在让我们制作我们的模型,将它与我们的配方放在一起workflow()
,并使用网格调整工作流程。
lasso_mod <- linear_reg(mode = "regression",
penalty = tune(),
mixture = 1) %>%
set_engine("glmnet")
wf <- workflow() %>%
add_model(lasso_mod) %>%
add_recipe(rec)
my_grid <- tibble(penalty = 10^seq(-2, -1, length.out = 10))
my_res <- wf %>%
tune_grid(resamples = folds,
grid = my_grid,
control = control_grid(verbose = FALSE, save_pred = TRUE),
metrics = metric_set(rmse))
这是我们得到的最好的惩罚:
best_mod <- my_res %>% select_best("rmse")
best_mod
#> # A tibble: 1 x 2
#> penalty .config
#> <dbl> <chr>
#> 1 0.0215 Preprocessor1_Model04
在这里,我们做的事情与您所做的有点不同。我将用最好的惩罚来完成我的工作流程,然后将最终的工作流程与训练数据相匹配。这里的输出是一个合适的工作流。我不想把底层模型拉出来,因为模型需要预处理才能正常工作;它被训练期望预处理发生。
相反,我可以predict()
直接使用经过培训的工作流程:
final_fitted <- finalize_workflow(wf, best_mod) %>%
fit(data = dt_train)
predict(final_fitted, dt_train)
#> # A tibble: 379 x 1
#> .pred
#> <dbl>
#> 1 18.5
#> 2 24.2
#> 3 23.3
#> 4 21.6
#> 5 37.6
#> 6 21.5
#> 7 16.7
#> 8 15.6
#> 9 21.3
#> 10 21.3
#> # … with 369 more rows
predict(final_fitted, dt_test)
#> # A tibble: 127 x 1
#> .pred
#> <dbl>
#> 1 30.2
#> 2 25.1
#> 3 19.6
#> 4 17.0
#> 5 13.9
#> 6 15.4
#> 7 13.7
#> 8 20.8
#> 9 31.1
#> 10 21.3
#> # … with 117 more rows
由reprex 包(v1.0.0)于 2021-03-16 创建
如果您调整工作流程,那么您通常希望最终确定、适应和预测工作流程。如果您在工作流程中使用非常简单的预处理器(例如可以传递给的公式),则可能会出现例外情况fit()
;我举了一个例子,你可以在这里做到这一点。
推荐阅读
- streaming - 如何让`mpv --stream-record`使用icecast标题作为文件名?
- c# - 在长度等于 P *(元素总和)的数组中查找子数组
- javascript - 使用空项目安装 vue-cli 时出现问题
- javascript - 如何使用“包含”参数在可放置 Div 中包含拖动的克隆元素
- r - 如何在 kable pdf 输出中跨行拆分整个单词以防止文本与下一个单元格重叠
- java - 'Access-Control-Allow-Origin' 标头包含多个值 ', *',但在 spring boot stomp 配置中只允许一个值
- android - 如何更改 WPA 中 P2P-DEVICE-FOUND 事件的 DeviceCapability?
- jsonpath - 如何匹配 JsonPath 中的值
- sonos - 在不暂停音乐的情况下将播放器添加到现有组?
- jenkins - 如果我在 AWS EKS 上配置了 Jenkins 主服务器,如何通过 JNLP 设置 Windows 从属代理