--- title: "Decision trees, using C5.0" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Decision trees, using C5.0} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library(dplyr) library(tidypredict) library(C50) set.seed(100) ``` | Function |Works| |---------------------------------------------------------------|-----| |`tidypredict_fit()`, `tidypredict_sql()`, `parse_model()` | |`tidypredict_to_column()` | |`tidypredict_test()` | |`parsnip` | ## How it works Here is a simple `C5.0()` classification model using the `mtcars` dataset: ```{r} library(dplyr) library(tidypredict) library(C50) mtcars2 <- mtcars mtcars2$vs <- factor(mtcars2$vs) model <- C5.0(mtcars2[, c("wt", "cyl", "mpg")], mtcars2$vs) ``` ## Under the hood C5.0 stores its fitted tree as text in the `tree` element of the model object. `tidypredict` parses that text directly, so the model can be translated even when it was fitted through the x/y interface (as `parsnip` does). The tree is transformed into a `dplyr`, a.k.a Tidy Eval, formula. The decision tree becomes a nested `dplyr::case_when()` statement. ```{r} tidypredict_fit(model) ``` From there, the Tidy Eval formula can be used anywhere where it can be operated. `tidypredict` provides three paths: - Use directly inside `dplyr`, `mutate(mtcars2, !! tidypredict_fit(model))` - Use `tidypredict_to_column(model)` to a piped command set - Use `tidypredict_sql(model)` to retrieve the SQL statement ## Categorical predictors `C5.0` handles categorical predictors natively. The generated formula uses `%in%` for categorical splits, and multi-way splits become nested `case_when()` branches: ```{r} mtcars3 <- mtcars2 mtcars3$gear <- factor(mtcars3$gear) model_cat <- C5.0(mtcars3[, c("wt", "gear", "mpg")], mtcars3$vs) tidypredict_fit(model_cat) ``` ## parsnip `tidypredict` also supports `C5.0` model objects fitted via the `parsnip` package, both as a `decision_tree()` and as a boosted `boost_tree()`. ```{r} library(parsnip) parsnip_model <- decision_tree(mode = "classification") |> set_engine("C5.0") |> fit(vs ~ wt + cyl + mpg, data = mtcars2) tidypredict_fit(parsnip_model) ``` ## Boosted models `C5.0` can boost several trees together, which `parsnip` exposes through `boost_tree()`. Each trial casts a confidence-weighted vote, and the class with the greatest total vote is predicted. `tidypredict` reproduces this by summing the per-trial votes and picking the winning class: ```{r} boosted_model <- boost_tree(mode = "classification", trees = 5) |> set_engine("C5.0") |> fit(Species ~ ., data = iris) tidypredict_fit(boosted_model) ``` ## Rule-based models Instead of a tree, `C5.0` can produce an ordered set of rules (`rules = TRUE`), which `parsnip` exposes through `C5_rules()`. Each rule that a case satisfies casts a confidence-weighted vote for its class, and the class with the greatest total vote is predicted (the default class wins ties and cases matched by no rule). `tidypredict` reproduces this by summing the per-rule votes and picking the winning class: ```{r} rule_model <- C5.0(iris[, 1:4], iris$Species, rules = TRUE) tidypredict_fit(rule_model) ``` ## Limitations Some options change how C5.0 predicts in ways that cannot be expressed as a hard-split `case_when()`, so they raise an error: fuzzy thresholds (`fuzzyThreshold = TRUE`), models fitted with a cost matrix (`costs`), and boosted rule-based models (`rules = TRUE` with `trials > 1`).