--- title: "R6 Classes and tidymodels" author: "Jodavid Ferreira" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{R6 Classes and tidymodels} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) has_tidymodels <- all(vapply( c("parsnip", "dials", "recipes", "rsample", "tune", "workflows", "yardstick"), requireNamespace, logical(1), quietly = TRUE )) ``` Since version 0.3.0, every classifier of `FuzzyClass` is an [R6](https://r6.r-lib.org) class, and all of them can be used within the [tidymodels](https://www.tidymodels.org) framework through the parsnip model `fuzzy_naive_bayes()`. This vignette shows both interfaces. ```{r} library(FuzzyClass) set.seed(123) train_index <- sample(nrow(iris), nrow(iris) * 0.7) train_data <- iris[train_index, ] test_data <- iris[-train_index, ] ``` ## The R6 interface Each classifier `X` has an R6 generator `XModel`, which inherits from the base class `FuzzyClassifier`. A model is created with `$new()`, which receives the hyperparameters of the classifier: ```{r} model <- GauNBFuzzyParamModel$new(metd = 2) model ``` `$fit()` estimates the model. While training, a message reports which classifier is being estimated, the size of the data and the training time: ```{r} model$fit(train = train_data[, -5], cl = train_data$Species) model ``` `$predict()` classifies new observations, returning the predicted classes or, with `type = "prob"`, the matrix of class probabilities: ```{r} pred <- model$predict(test_data[, -5]) head(pred) mean(pred == test_data$Species) head(model$predict(test_data[, -5], type = "prob")) ``` Hyperparameters are changed with `$set_params()`, which resets the model so that it must be trained again. Since `$fit()` and `$set_params()` return the object, the calls can be chained; `verbose = FALSE` trains silently: ```{r} model$set_params(metd = 5)$fit(train_data[, -5], train_data$Species, verbose = FALSE) mean(model$predict(test_data[, -5]) == test_data$Species) ``` The training message can also be disabled for the whole session with `options(FuzzyClass.verbose = FALSE)`. ### The functional interface The functions of the previous versions are still available. They train the model and return the R6 object, and the S3 method `predict()` is supported: ```{r} fit <- FuzzyGaussianNaiveBayes(train = train_data[, -5], cl = train_data$Species) class(fit) head(predict(fit, test_data[, -5])) head(predict(fit, test_data[, -5], type = "matrix")) ``` ## Using FuzzyClass with tidymodels `fuzzy_naive_bayes()` defines a parsnip model specification. The classifier is chosen through the engine (see `?fuzzy_naive_bayes` for the full list): ```{r, eval = has_tidymodels, message = FALSE} library(parsnip) library(workflows) library(recipes) library(rsample) library(tune) library(yardstick) spec <- fuzzy_naive_bayes(fuzzy = TRUE) |> set_engine("gaussian") spec iris_fit <- fit(spec, Species ~ ., data = train_data) predict(iris_fit, test_data[1:5, ]) predict(iris_fit, test_data[1:5, ], type = "prob") ``` Arguments specific to a classifier are passed to `set_engine()`: ```{r, eval = has_tidymodels} fuzzy_naive_bayes() |> set_engine("dw_gamma", wdelta = rep(1/3, 3), weta = rep(1/4, 4), verbose = FALSE) |> fit(Species ~ ., data = train_data) |> augment(new_data = test_data) |> yardstick::accuracy(truth = Species, estimate = .pred_class) ``` ### Tuning The main arguments `fuzzy`, `alpha_cut` and `ranking_method` can be tuned. Here we tune the fuzzy-parameter Gaussian classifier inside a workflow with a recipe, using cross-validation. The training messages are disabled while tuning: ```{r, eval = has_tidymodels} options(FuzzyClass.verbose = FALSE) split <- initial_split(iris, prop = 0.7, strata = Species) folds <- vfold_cv(training(split), v = 5, strata = Species) wf <- workflow() |> add_recipe(recipe(Species ~ ., data = training(split))) |> add_model( fuzzy_naive_bayes(alpha_cut = tune(), ranking_method = tune()) |> set_engine("gaussian_fuzzy_param") ) set.seed(1) tuned <- tune_grid(wf, resamples = folds, grid = 6, metrics = metric_set(yardstick::accuracy, yardstick::roc_auc)) show_best(tuned, metric = "accuracy", n = 3) final <- finalize_workflow(wf, select_best(tuned, metric = "accuracy")) |> last_fit(split, metrics = metric_set(yardstick::accuracy, yardstick::roc_auc)) collect_metrics(final) options(FuzzyClass.verbose = TRUE) ```