0

Is it possible to extract, say, a model of class glm from a tidymodel built with recipe and logistic_reg() %>% set_engine("glm")?

I'd like to use packages from the easystats project, which require "normal", non-tidy models. The workflow extractor function (pull_workflow_fit()) returns an object of class `"_glm" "model_fit", which doesn't seem to be compatible.

I understand I can generate a model using glm() and the same formula as in the recipe, but it seems to me the fitted parameters differ. Thanks!

Marco B
  • 121
  • 6

2 Answers2

1

The easystats package suite supports tidymodels since the last updates:

library(tidymodels)

data(two_class_dat)

glm_spec <- logistic_reg() %>%
  set_engine("glm") 

norm_rec <- recipe(Class ~ A + B, data = two_class_dat) %>%
  step_normalize(all_predictors())

workflow() %>%
  add_recipe(norm_rec) %>%
  add_model(glm_spec) %>%
  fit(two_class_dat) %>%
  pull_workflow_fit() %>% 
  parameters::model_parameters()
#> Parameter   | Log-Odds |   SE |         95% CI |     z |      p
#> ---------------------------------------------------------------
#> (Intercept) |    -0.35 | 0.10 | [-0.54, -0.16] | -3.55 | < .001
#> A           |    -1.11 | 0.17 | [-1.44, -0.79] | -6.64 | < .001
#> B           |     2.80 | 0.21 | [ 2.40,  3.22] | 13.33 | < .001


workflow() %>%
  add_recipe(norm_rec) %>%
  add_model(glm_spec) %>%
  fit(two_class_dat) %>%
  pull_workflow_fit() %>% 
  parameters::model_parameters() %>% 
  plot()



workflow() %>%
  add_recipe(norm_rec) %>%
  add_model(glm_spec) %>%
  fit(two_class_dat) %>%
  pull_workflow_fit() %>% 
  parameters::model_parameters() %>% 
  parameters::print_md()
Parameter Log-Odds SE 95% CI z p
(Intercept) -0.35 0.10 (-0.54, -0.16) -3.55 < .001
A -1.11 0.17 (-1.44, -0.79) -6.64 < .001
B 2.80 0.21 (2.40, 3.22) 13.33 < .001


workflow() %>%
  add_recipe(norm_rec) %>%
  add_model(glm_spec) %>%
  fit(two_class_dat) %>%
  pull_workflow_fit() %>% 
  performance::model_performance()
#> # Indices of model performance
#> 
#> AIC     |     BIC | Tjur's R2 |  RMSE | Sigma | Log_loss | Score_log | Score_spherical |   PCP
#> ----------------------------------------------------------------------------------------------
#> 679.950 | 693.970 |     0.460 | 0.362 | 0.925 |    0.426 |      -Inf |           0.003 | 0.733

Created on 2021-04-25 by the reprex package (v2.0.0)

Daniel
  • 7,252
  • 6
  • 26
  • 38
0

You can extract out the underlying model object (whether that was created by glm or ranger or keras or anything) from a parsnip object using $fit.

library(tidymodels)

data(two_class_dat)

glm_spec <- logistic_reg() %>%
  set_engine("glm") 

norm_rec <- recipe(Class ~ A + B, data = two_class_dat) %>%
  step_normalize(all_predictors())

glm_fit <- workflow() %>%
  add_recipe(norm_rec) %>%
  add_model(glm_spec) %>%
  fit(two_class_dat) %>%
  pull_workflow_fit()

What is in that fitted object?

## this is a parsnip object
glm_fit
#> parsnip model object
#> 
#> Fit time:  5ms 
#> 
#> Call:  stats::glm(formula = ..y ~ ., family = stats::binomial, data = data)
#> 
#> Coefficients:
#> (Intercept)            A            B  
#>     -0.3491      -1.1063       2.7966  
#> 
#> Degrees of Freedom: 790 Total (i.e. Null);  788 Residual
#> Null Deviance:       1088 
#> Residual Deviance: 673.9     AIC: 679.9

## this is a glm object
glm_fit$fit
#> 
#> Call:  stats::glm(formula = ..y ~ ., family = stats::binomial, data = data)
#> 
#> Coefficients:
#> (Intercept)            A            B  
#>     -0.3491      -1.1063       2.7966  
#> 
#> Degrees of Freedom: 790 Total (i.e. Null);  788 Residual
#> Null Deviance:       1088 
#> Residual Deviance: 673.9     AIC: 679.9

Created on 2021-02-04 by the reprex package (v1.0.0)

The fitted parameters will definitely not differ from calling the model directly. If you think you are finding different fitted parameters, then something may be going awry is how you are calling the model.

Julia Silge
  • 10,848
  • 2
  • 40
  • 48
  • 1
    Hi, and thanks for your solution! May I say that this aspect could use a little more elaboration in `tidymodel`'s documentation? It allows you to easily switch between `tidymodels` and other ecosystems such as `easystats` which do not support tidy-style. I followed `tidymodels` tutorial to the letter but I don't think this "interoperability" feature ever came up, even though it may seem obvious to expert users. – Marco B Feb 06 '21 at 13:50
  • Thanks for that feedback! We'll look into making that more clear. – Julia Silge Feb 07 '21 at 17:58