parsnip multinom_reg() in R: Multinomial Logistic Regression
The parsnip multinom_reg() function defines a multinomial logistic regression model for outcomes with three or more unordered classes. It gives you one consistent interface that fits with the nnet or glmnet engine underneath.
multinom_reg() # default spec, nnet engine multinom_reg() |> set_engine("nnet") # neural-net multinomial fit multinom_reg(penalty = 0.1) |> set_engine("glmnet") # penalized multinomial fit spec |> set_mode("classification") # only mode multinom_reg allows fit(spec, Species ~ ., data = iris) # train on a 3+ class outcome predict(fit, new_data) # hard class label per row predict(fit, new_data, type = "prob") # one probability per class
Need explanation? Read on for examples and pitfalls.
What multinom_reg() does
multinom_reg() is a model specification, not a fitted model. It records your intent to build a multinomial logistic regression and the hyperparameters you want, but no data touches it until you call fit(). This separation lets you reuse one specification across many datasets or resampling folds.
Multinomial logistic regression extends binary logistic regression to outcomes with more than two categories. Instead of one set of coefficients, it estimates a separate set for each class relative to a reference class, then converts those scores into probabilities that sum to one across all classes.
The function belongs to the tidymodels framework. Because parsnip standardizes the interface, the same multinom_reg() code runs on the nnet engine or the penalized glmnet engine with only one line changed.
fit() turns it into a trained model object. Keeping those two steps apart is what makes tidymodels workflows reproducible across resamples.multinom_reg() syntax and arguments
multinom_reg() takes two tuning arguments and two setup verbs. The arguments control regularization, while set_engine() and set_mode() finish the specification.
The penalty argument sets the total amount of regularization applied to coefficients. The mixture argument, used only by glmnet, blends ridge (mixture = 0) and lasso (mixture = 1) penalties. The nnet engine ignores both arguments because it fits an unpenalized model.
The mode is always classification. Unlike linear_reg(), a multinomial model never predicts numbers, so set_mode("classification") is the only legal choice. You can pass the engine through set_engine() instead of the engine argument, which is the more common tidymodels style.
Fit a multinomial model: four examples
Every example below uses the built-in iris dataset. Its Species column has three classes, setosa, versicolor, and virginica, which makes it a natural fit for a multinomial model.
Example 1: Fit with the default nnet engine
Build the specification, then fit it to data. The nnet engine fits a multinomial model through a single-layer neural network.
The fitted object reports one row of coefficients per non-reference class. Setosa is the reference, so versicolor and virginica each get a coefficient row.
Example 2: Predict the most likely class
predict() returns a tidy tibble with one row per input row. The default prediction type gives the hard class label.
Each output column from a parsnip model starts with .pred, which keeps prediction columns from clashing with your original data when you bind them back together.
Example 3: Get per-class probabilities
Set type = "prob" to see the probability of every class. This is essential when you need a confidence score, not just a label.
The three probability columns sum to one in every row. A near-1.0 value, as in row 1, signals a confident prediction.
Example 4: Fit a penalized model with glmnet
Switch to glmnet for regularized coefficients. The glmnet engine needs a non-NULL penalty, and mixture = 1 requests a pure lasso penalty that can shrink weak predictors to zero.
penalty = tune() in the specification, then pass it to tune_grid() with a resampling object. The framework searches a grid of penalty values and reports which one generalizes best.multinom_reg() vs logistic_reg() vs other models
Pick the model by counting your outcome classes. multinom_reg() handles three or more unordered classes; the alternatives below cover the other cases.
| Function | Outcome type | Default engine | Use when |
|---|---|---|---|
multinom_reg() |
3+ unordered classes | nnet | Species, product category, region |
logistic_reg() |
exactly 2 classes | glm | Yes/no, churn, spam |
linear_reg() |
numeric | lm | Price, temperature, score |
poisson_reg() |
non-negative counts | glm | Visits, defects, calls |
rand_forest() |
any classification or regression | ranger | Non-linear effects, interactions |
Use multinom_reg() when the outcome categories have no natural order and you want interpretable coefficients. If the classes are ordered, such as low-medium-high, a multinomial model ignores that order and an ordinal model fits better.
multinom_reg() is LogisticRegression(multi_class="multinomial"). The glmnet engine with a penalty maps to scikit-learn's C parameter, which is the inverse of regularization strength.Common pitfalls
Three mistakes catch most newcomers to multinom_reg(). Each one below shows the error and the fix.
Forgetting the engine for glmnet leaves penalty unused. The nnet engine silently ignores penalty, so a model you expected to be regularized is not. Always call set_engine("glmnet") when you pass a penalty.
A character outcome column also trips people up. parsnip expects the classification outcome to be a factor. Convert it first with mutate(y = factor(y)) or the fit fails with a type error. Finally, the glmnet engine refuses to run when penalty is NULL, so always supply a numeric value or tune().
Try it yourself
Try it: Fit a multinomial model on iris using only the two petal columns as predictors, then predict the class of the 100th row. Save the prediction to ex_pred.
Click to reveal solution
Explanation: The formula Species ~ Petal.Length + Petal.Width restricts the model to two predictors. Row 100 of iris is a versicolor flower, and the petal measurements alone classify it correctly.
Related parsnip functions
multinom_reg() works alongside the rest of the parsnip model family. These functions cover the neighboring tasks in a tidymodels project.
logistic_reg()defines a two-class logistic regression model.linear_reg()defines a regression model for numeric outcomes.rand_forest()defines a random forest for classification or regression.set_engine()chooses the computational backend for any specification.fit()trains a specification on data and returns a model object.
FAQ
What engine does multinom_reg() use by default?
The default engine is nnet, which calls nnet::multinom() to fit the multinomial model through a single-layer neural network. It fits an unpenalized model and ignores the penalty and mixture arguments. To apply regularization, switch to the glmnet engine with set_engine("glmnet") and supply a numeric penalty. Always confirm the active engine with show_engines("multinom_reg") if you are unsure.
What is the difference between multinom_reg() and logistic_reg()?
logistic_reg() models an outcome with exactly two classes, while multinom_reg() models an outcome with three or more classes. Internally, the multinomial model estimates a separate set of coefficients for each class against a reference class. If you pass a three-class outcome to logistic_reg(), the fit fails, so match the function to the number of classes in your target variable.
Does multinom_reg() require the outcome to be a factor?
Yes. parsnip expects the classification outcome to be a factor, not a character or numeric vector. If your outcome is stored as text, convert it first with mutate(species = factor(species)) before calling fit(). The factor levels also determine the reference class, which is the first level by default and the baseline for every coefficient.
Can I tune the penalty in multinom_reg()?
Yes, set penalty = tune() in the specification and use the glmnet engine. Pass the specification to tune_grid() with a resampling object such as vfold_cv(), and the framework searches a grid of penalty values. Use select_best() to pick the value with the best metric, then finalize_workflow() to lock it in before the final fit.
Why do my predicted probabilities not match across engines?
The nnet and glmnet engines fit different models. nnet fits an unpenalized maximum-likelihood model, while glmnet adds an L1 or L2 penalty controlled by penalty and mixture. A non-zero penalty shrinks coefficients toward zero, which changes the predicted probabilities. This difference is expected, so compare engines with a resampled metric rather than raw probabilities.
For the full argument reference, see the parsnip multinom_reg() documentation.