---
title: "sda models"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{sda models}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include = FALSE}
if (requireNamespace("sda", quietly = TRUE)) {
library(tidypredict)
library(dplyr)
eval_code <- TRUE
} else {
eval_code <- FALSE
}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
eval = eval_code
)
```
| Function |Works|
|---------------------------------------------------------------|-----|
|`tidypredict_fit()`, `tidypredict_sql()`, `parse_model()` | ✔ |
|`tidypredict_to_column()` | ✗ |
|`tidypredict_test()` | ✗ |
|`tidypredict_interval()`, `tidypredict_sql_interval()` | ✗ |
|`parsnip` | ✔ |
`sda::sda()` fits shrinkage discriminant analysis models, including the diagonal
variant (`diagonal = TRUE`). Predicting with such a model is a softmax over one
linear predictor per outcome class, so `tidypredict_fit()` returns a *named list*
of expressions, one for each class, rather than a single expression. Since the
output is a list, `tidypredict_to_column()` and `tidypredict_test()` are not
supported.
Only the features that survive shrinkage appear in the fitted model, and the
generated expressions reference just those.
## `tidypredict_` functions
```{r}
model <- sda::sda(as.matrix(iris[1:4]), iris$Species, verbose = FALSE)
```
- Create the R formulas, one per class
```{r}
fit <- tidypredict_fit(model)
names(fit)
fit[["setosa"]]
```
- Add the predictions to the original table
```{r}
library(dplyr)
iris %>%
mutate(!!!tidypredict_fit(model)) %>%
glimpse()
```
- Confirm that the results match the model's `predict()` results
```{r}
probs <- sapply(fit, \(f) rlang::eval_tidy(f, iris))
posterior <- predict(model, as.matrix(iris[1:4]), verbose = FALSE)
all.equal(unname(probs), unname(posterior$posterior))
```
`sda()` rounds its posterior probabilities with `zapsmall()`, so expect agreement
to about seven decimal places rather than exactly.
## parsnip
`parsnip` fitted models are also supported by `tidypredict`:
```{r}
library(parsnip)
library(discrim)
p_model <- discrim_linear() %>%
set_engine("sda") %>%
fit(Species ~ ., data = iris)
```
```{r}
tidypredict_fit(p_model)[["virginica"]]
```
`sda()` is fit from a numeric matrix, so a model fit directly can only refer to
the matrix columns it was given. Categorical predictors therefore work through
the `parsnip` interface, which keeps the formula around and lets the dummy
columns be written in terms of the original factors:
```{r}
cars <- transform(mtcars, cyl = factor(cyl), gear = factor(gear))
c_model <- discrim_linear() %>%
set_engine("sda") %>%
fit(cyl ~ mpg + gear + disp, data = cars)
tidypredict_fit(c_model)[["8"]]
```
## Parse model spec
Here is an example of the model spec:
```{r}
pm <- parse_model(model)
str(pm, 2)
```