---
title: "Nominal conditional synthesis (experimental)"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Nominal conditional synthesis (experimental)}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```

The SynthesizerPlus copula uses a single latent coordinate per categorical
variable. This is natural for ordinal responses. For unordered categories the
copula places them on that coordinate in an order estimated from the data
(by their association with the other columns), not in the order of their
labels, but one coordinate cannot represent every pattern of association a
nominal variable can have. Since version 0.4.0,
`nominal_target` instead fits a *conditional multinomial logistic model* of one
unordered response. The other columns are generated using the usual fitted
copula, then the response is drawn from predicted category probabilities.
The model is

$$P(Y = k \mid x) = \frac{\exp\{\eta_k(x)\}}{\sum_l \exp\{\eta_l(x)\}},
\qquad \eta_k(x) = \beta_{k0} + \sum_j f_{kj}(x_j),$$

with $\eta$ of the first category fixed at zero. For each numeric predictor
with at least five distinct values, $f_{kj}$ is a natural cubic spline with
`nominal_spline_df` degrees of freedom (default 3, knots at quantiles of the
training values), so the category probabilities can depend nonlinearly and
non-monotonically on it; other predictors enter linearly or as category
dummies, with a missingness indicator for numeric predictors. The model is
fitted by `nnet::multinom()` with weight decay `nominal_decay`. The purely
linear logit is fitted as well, and the model with the smaller AIC is used;
the comparison is stored in `fit$pooled$nominal$selection` and the choice in
`fit$pooled$nominal$spline_df`. Splines are thus used when the extra
parameters are supported by the data; with (nearly) separated classes, as in
`iris`, the linear logit is better determined and is kept. Setting
`nominal_spline_df = 0` fits only the linear logit.

```{r example, eval=requireNamespace("nnet", quietly=TRUE)}
library(SynthesizerPlus)
set.seed(204)
input <- data.frame(
  age = rnorm(500, 35, 10),
  income = rgamma(500, shape = 4, scale = 1000)
)
logits <- cbind(0, (input$age - 35)/15, log(input$income/4000))
p <- exp(logits - apply(logits, 1L, max))
p <- p/rowSums(p)
classes <- c("bus", "car", "rail")
input$transport <- factor(classes[apply(p, 1, function(q)
  sample.int(3, 1, prob = q))])

fit <- fit_synthesizer(input, nominal_target = "transport", seed = 11)
synthetic <- generate(fit, n = 500, seed = 12)
prop.table(table(synthetic$transport))
fit$pooled$nominal$selection   # AIC of the spline and linear models
```

Nominal category labels have no ordinal interpretation. Reordering or
renaming those labels represents the same statistical outcome categories;
the multinomial model is approximately equivariant to such relabelling (up to
numerical optimisation and Monte Carlo variability). Reproducibility of the
*factor-level metadata* is preserved by the generated table.

At least 40 observed categorical responses and two to twenty distinct
categories are required. Sparse strata fall back to the conventional copula
model, including the nominal target; `fit_synthesizer()` warns when this
happens and lists the strata in `fit$strata$conditional_fallback`. The
multinomial model has additive spline effects of the numeric predictors and
no interactions, so class boundaries that depend on interactions between
predictors remain a limitation. Fitted model objects include information
about the training data and should not be publicly released as if privacy-safe.
