| Function | Works |
|---|---|
tidypredict_fit(), tidypredict_sql(),
parse_model()
|
✔ |
tidypredict_to_column() |
✔ |
tidypredict_test() |
✔ |
tidypredict_interval(),
tidypredict_sql_interval()
|
✗ |
parsnip |
✔ |
How it works
A RuleFit model is a regularized linear model over two kinds of terms: rules extracted from a boosted tree ensemble, and the original predictors entered linearly. Both kinds translate cleanly, so the whole model becomes a single formula.
Under the hood
The parser reads the fitted glmnet coefficients and the
rules they belong to. Each rule becomes a dplyr::if_else()
indicator multiplied by its coefficient, and the linear terms are added
on top.
pm <- parse_model(model)
str(pm, 2)
#> List of 2
#> $ general:List of 6
#> ..$ model : chr "xrf"
#> ..$ version: num 2
#> ..$ type : chr "regression"
#> ..$ is_glm : num 1
#> ..$ family : chr "gaussian"
#> ..$ link : chr "identity"
#> $ terms :List of 19
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> ..$ :List of 4
#> - attr(*, "class")= chr [1:3] "parsed_model" "pm_regression" "list"The parsed model is transformed into a dplyr, a.k.a.
Tidy Eval, formula.
tidypredict_fit(model)
#> 21.4354600220349 + (hp * -0.00485570018743864) + (ifelse(cyl ==
#> "4", 1, 0) * 0.728811208763373) + (ifelse(cyl == "8", 1,
#> 0) * -2.52977053354706) + (ifelse(wt < 2.31999993, 1, 0) *
#> 5.00384814595596) + (ifelse(wt < 2.46499991, 1, 0) * ifelse(wt >=
#> 2.31999993, 1, 0) * 0.298737461778169) + (ifelse(wt >= 2.46499991,
#> 1, 0) * ifelse(cyl == "8", 1, 0) * ifelse(cyl != "6", 1,
#> 0) * -7.15444309275421e-05) + (ifelse(hp >= 123, 1, 0) *
#> ifelse(hp >= 180, 1, 0) * ifelse(wt < 3.77999997, 1, 0) *
#> -1.22640584347711) + (ifelse(hp >= 123, 1, 0) * ifelse(hp >=
#> 180, 1, 0) * ifelse(wt >= 3.77999997, 1, 0) * -2.74340613610864) +
#> (ifelse(hp < 123, 1, 0) * ifelse(wt >= 2.31999993, 1, 0) *
#> ifelse(hp < 97, 1, 0) * 0.426427270712896) + (ifelse(hp >=
#> 123, 1, 0) * ifelse(wt >= 5.25, 1, 0) * ifelse(hp < 230,
#> 1, 0) * -4.49107556200436) + (ifelse(hp >= 123, 1, 0) * ifelse(wt >=
#> 5.25, 1, 0) * ifelse(hp >= 230, 1, 0) * 0.0860692216034999) +
#> (ifelse(hp < 123, 1, 0) * ifelse(hp < 91, 1, 0) * 2.53529034445322) +
#> (ifelse(hp < 123, 1, 0) * ifelse(hp >= 91, 1, 0) * ifelse(wt <
#> 1.61500001, 1, 0) * 0.811364276852491) + (ifelse(hp >=
#> 123, 1, 0) * ifelse(wt < 5.25, 1, 0) * ifelse(wt < 3.84500003,
#> 1, 0) * -0.493065242179932) + (ifelse(wt >= 3.43499994, 1,
#> 0) * ifelse(hp < 205, 1, 0) * ifelse(hp >= 175, 1, 0) * 0.905140727759907) +
#> (ifelse(wt >= 3.43499994, 1, 0) * ifelse(hp >= 205, 1, 0) *
#> ifelse(hp >= 230, 1, 0) * -0.794841172984618) + (ifelse(wt <
#> 3.43499994, 1, 0) * ifelse(wt < 1.93499994, 1, 0) * 2.60840030568605) +
#> (ifelse(wt >= 3.43499994, 1, 0) * ifelse(hp < 205, 1, 0) *
#> ifelse(hp < 175, 1, 0) * -2.08593440027407)From there, the Tidy Eval formula can be used anywhere it can be
evaluated. tidypredict provides three paths:
- Use directly inside
dplyr,mutate(df, !! tidypredict_fit(model)) - Use
tidypredict_to_column(model)to add it to a piped command set - Use
tidypredict_sql(model, con)to retrieve the SQL statement
df %>%
tidypredict_to_column(model) %>%
glimpse()
#> Rows: 32
#> Columns: 12
#> $ mpg <dbl> 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19…
#> $ cyl <fct> 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4,…
#> $ disp <dbl> 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146.7, …
#> $ hp <dbl> 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180,…
#> $ drat <dbl> 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.…
#> $ wt <dbl> 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.190, …
#> $ qsec <dbl> 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00, …
#> $ vs <dbl> 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,…
#> $ am <dbl> 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,…
#> $ gear <dbl> 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4,…
#> $ carb <dbl> 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2,…
#> $ fit <dbl> 20.90133, 20.90133, 22.43786, 20.90133, 18.46795, 18.839…How it performs
tidypredict_test(model, df)
#> tidypredict test results
#> Difference threshold: 1e-12
#>
#> All results are within the difference thresholdClassification
Binary classification models, family = "binomial", are
supported and return the probability of the second outcome level through
the logistic link.
df_bin <- mtcars
df_bin$vs <- factor(df_bin$vs)
model_bin <- xrf(
vs ~ wt + mpg,
df_bin,
family = "binomial",
xgb_control = list(nrounds = 5, max_depth = 3)
)
tidypredict_test(model_bin, df_bin)
#> tidypredict test results
#> Difference threshold: 1e-12
#>
#> All results are within the difference thresholdparsnip
tidypredict also supports xrf model objects
fitted via the parsnip package, using
rule_fit() from the rules package with the
"xrf" engine.
library(parsnip)
library(rules)
parsnip_model <- rule_fit(
mode = "regression",
trees = 5,
tree_depth = 3,
penalty = 0.1
) |>
set_engine("xrf") |>
fit(mpg ~ wt + hp + cyl, data = df)
tidypredict_test(parsnip_model, df)
#> tidypredict test results
#> Difference threshold: 1e-12
#>
#> All results are within the difference thresholdLimitations
- Multinomial models are not supported; only
family = "gaussian"andfamily = "binomial"are. - Prediction intervals are not supported.
- Functions and interactions written inside the model formula are not
supported. Prepare those columns with
dplyrbefore fitting. - The underlying trees come from XGBoost, which stores split thresholds as 32-bit floats. See the float precision article.
