【问题标题】:How to extract predictors from parsnip fit object如何从防风草拟合对象中提取预测变量
【发布时间】:2022-11-21 19:49:28
【问题描述】:

我有以下预测模型:

library(tidymodels)

data(ames)

set.seed(4595)
data_split <- initial_split(ames, strata = "Sale_Price", prop = 0.75)

ames_train <- training(data_split)
ames_test  <- testing(data_split)

rec <- recipe(Sale_Price ~ ., data = ames_train)
norm_trans <- rec %>%
  step_zv(all_predictors()) %>%
  step_nzv(all_predictors())  %>% 
  step_corr(all_numeric_predictors(), threshold = 0.1)

# Preprocessing 
norm_obj <- prep(norm_trans, training = ames_train)
rf_ames_train <- bake(norm_obj, ames_train) %>%
  dplyr::select(Sale_Price, everything()) %>%
  as.data.frame()
dim(rf_ames_train )


rf_xy_fit <- rand_forest(mode = "regression") %>%
  set_engine("ranger") %>%
  fit_xy(
    x = rf_ames_train,
    y = log10(rf_ames_train$Sale_Price)
  )

请注意,在预处理步骤之后,特征数量从 74 减少到 33。

dim(rf_ames_train )
# 33

目前,我必须在函数中显式传递预测变量:

preds <- colnames(rf_ames_train) 
my_pred_function <- function (fit = NULL, test_data = NULL, predictors = NULL) {
  
  test_results <- test_data %>%
    select(Sale_Price) %>%
    mutate(Sale_Price = log10(Sale_Price)) %>%
    bind_cols(
      predict(fit, new_data = ames_test[, predictors])
    )
  test_results
  
}

my_pred_function(fit = rf_xy_fit, test_data = ames_test, predictors = preds)

在上面的函数调用中显示为predictors = preds。

实际上,我必须将rf_xy_fit和preds保存为两个RDS文件,然后再读取它们。这样容易出错,也很麻烦。

我想绕过这个明确的传递。有什么方法可以直接从rf_xy_fit 中提取吗?

【问题讨论】:

    标签: r tidymodels r-recipes r-ranger parsnip


    【解决方案1】:

    在这种情况下,您将受益于使用 workflows 包。这允许您将预处理代码与模型拟合代码结合起来

    library(tidymodels)
    
    data(ames)
    
    set.seed(4595)
    # Notice how I did log transformation before doing the splitting to assure that it is not on both testing and training data sets.
    
    ames <- ames %>%
      mutate(Sale_Price = log10(Sale_Price))
             
    data_split <- initial_split(ames, strata = "Sale_Price", prop = 0.75)
    
    ames_train <- training(data_split)
    ames_test  <- testing(data_split)
    
    rec <- recipe(Sale_Price ~ ., data = ames_train)
    norm_trans <- rec %>%
      step_zv(all_predictors()) %>%
      step_nzv(all_predictors())  %>% 
      step_corr(all_numeric_predictors(), threshold = 0.1)
    
    rf_spec <- rand_forest(mode = "regression") %>%
      set_engine("ranger")
    
    rf_wf <- workflow() %>%
      add_recipe(norm_trans) %>%
      add_model(rf_spec)
    
    rf_fit <- fit(rf_wf, ames_train)
    
    predict(rf_fit, new_data = ames_train)
    #> # A tibble: 2,197 × 1
    #>    .pred
    #>    <dbl>
    #>  1  5.09
    #>  2  5.12
    #>  3  5.01
    #>  4  4.99
    #>  5  5.12
    #>  6  5.07
    #>  7  4.90
    #>  8  5.09
    #>  9  5.13
    #> 10  5.08
    #> # … with 2,187 more rows
    

    创建于 2022-11-21 reprex v2.0.2

    【讨论】:

    • 谢谢。但我想提取test数据中的特征,例如ames_test,以便我可以将它与rf_spec 一起使用。具体来说,我想将它包装在我的 OP 中的函数中。我怎样才能做到这一点?
    【解决方案2】:

    根据您的评论补充 Emils 的回答...

    请记住,大多数 R 建模函数都需要原始功能集,即使其中一些根本没有使用。这是 R 的公式 /model.matrix() 机器的副产品。

    对于食谱,这取决于您使用的步骤。

    您可以在没有它们的情况下改装最终模型,但您可能无法获得完全相同的模型。在许多情况下,获取功能子集的过程取决于最初通过的数量。

    我正在为此开发一个 tidymodels api,但是 caret 有一个可以获取模型实际使用的预测变量列表。看例子:

    library(caret)
    #> Loading required package: ggplot2
    #> Loading required package: lattice
    library(tidymodels)
    
    
    tidymodels_prefer()
    options(pillar.advice = FALSE, pillar.min_title_chars = Inf)
    
    
    data(ames)
    
    set.seed(4595)
    
    ames <- ames %>%
      mutate(Sale_Price = log10(Sale_Price))
    
    data_split <- initial_split(ames, strata = "Sale_Price", prop = 0.75)
    
    ames_train <- training(data_split)
    ames_test  <- testing(data_split)
    
    rec <- recipe(Sale_Price ~ ., data = ames_train)
    norm_trans <- rec %>%
      step_zv(all_predictors()) %>%
      step_nzv(all_predictors())  %>% 
      step_corr(all_numeric_predictors(), threshold = 0.1)
    
    rf_spec <- rand_forest(mode = "regression") %>%
      set_engine("ranger")
    
    rf_wf <- workflow() %>%
      add_recipe(norm_trans) %>%
      add_model(rf_spec)
    
    rf_fit <- fit(rf_wf, ames_train)
    
    # get predictor set:
    rf_features <- 
      rf_fit %>% 
      extract_fit_engine() %>% 
      predictors()  #<- the caret funciton
    
    head(rf_features)
    #> [1] "MS_SubClass"  "MS_Zoning"    "Lot_Frontage" "Lot_Shape"    "Lot_Config"  
    #> [6] "Neighborhood"
    
    # You get an error here: 
    ames_test %>% 
      select(all_of(rf_features)) %>% 
      predict(rf_fit, new_data = .)
    #> Error in `validate_column_names()`:
    #> ! The following required columns are missing: 'Lot_Area', 
    #> 'Street', 'Alley', 'Land_Contour', 'Utilities', 'Land_Slope',
    #> 'Condition_2', 'Year_Built', 'Year_Remod_Add', 'Roof_Matl', 
    #> 'Mas_Vnr_Area', 'Bsmt_Cond', 'BsmtFin_SF_1', 'BsmtFin_Type_2', 
    #> 'BsmtFin_SF_2', 'Bsmt_Unf_SF', 'Total_Bsmt_SF', 'Heating', 
    #> 'First_Flr_SF', 'Second_Flr_SF', 'Gr_Liv_Area', 'Bsmt_Full_Bath', 
    #> 'Full_Bath', 'Half_Bath', 'Bedroom_AbvGr', 'Kitchen_AbvGr', 
    #> 'TotRms_AbvGrd', 'Functional', 'Fireplaces', 'Garage_Cars',
    #> 'Garage_Area', 'Wood_Deck_SF', 'Open_Porch_SF', 'Enclosed_Porch',
    #> 'Three_season_porch', 'Screen_Porch', 'Pool_Area', 'Pool_QC',
    #> 'Misc_Feature', 'Misc_Val', 'Mo_Sold', 'Latitude'.
    

    由 reprex package (v2.0.1) 创建于 2022-11-21

    此错误来自工作流包,但底层建模包也会出错。

    【讨论】:

      猜你喜欢
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 2012-12-30
      • 2020-03-23
      • 1970-01-01
      • 2014-08-16
      • 2023-01-26
      • 2020-09-24
      相关资源
      最近更新 更多