workflowsets as_workflow_set() in R: Wrap Workflow Lists
The workflowsets as_workflow_set() function in R converts a named list of pre-built workflow objects into a single workflow_set tibble, so you can fit, tune, and rank a hand-picked collection of models with the same one-line calls that workflow_set() enables for combinatorial designs.
as_workflow_set(lr = wf_lr) # one workflow, one row as_workflow_set(lr = wf_lr, rf = wf_rf) # multiple named workflows as_workflow_set(!!!list_of_wfs) # splice a named list as_workflow_set(simple = wf1, tuned = wf2) # mix tunable and fixed res <- as_workflow_set(lr = wf_lr) |> workflow_map() # then fit or resample bind_rows(set_a, set_b) # combine two sets (not as_workflow_set)
Need explanation? Read on for examples and pitfalls.
What as_workflow_set() does in one sentence
as_workflow_set() wraps existing workflows into the workflow_set container. You pass one or more named workflow objects and receive a tibble with one row per workflow, ready to be piped into workflow_map() for fitting or tuning across the same resamples. The companion function workflow_set() builds rows from a preprocessor crossing a model list; as_workflow_set() skips that crossing and lets you assemble a hand-curated lineup directly.
workflow_set(). If as_workflow_set is unknown to your session, run update.packages("workflowsets") before continuing.as_workflow_set() syntax and arguments
The signature accepts a dynamic dots list of named workflows. Every element of ... must be a workflow object and every argument must be named, since names become the wflow_id column used for joining metrics, predictions, and ranks downstream.
The returned object inherits from tbl_df so any tibble verb works on it, and from workflow_set so workflowsets verbs like workflow_map() and rank_results() dispatch correctly.
Four examples of as_workflow_set() in action
Example 1: wrap two complete workflows for a head-to-head fit.
Example 2: splice a programmatically built list with !!!. When you assemble workflows in a loop or purrr::map(), the result is a list. The bang-bang-bang operator from rlang splices that list into the dots so each element becomes a named argument.
Example 3: pipe straight into workflow_map() to fit on resamples. A wrapped set behaves identically to a set built by workflow_set(), so the standard fitting verbs apply.
Example 4: extend an existing set instead of rebuilding it. Use bind_rows() to combine two workflow sets; as_workflow_set() itself does not append to a set.
lr_basic, lr_poly, rf_500_trees. Avoid numeric suffixes like wf1, wf2; they reduce a rank table to a guessing game when you revisit it weeks later.as_workflow_set() compared with workflow_set() and bind_rows
Pick the constructor that matches how your workflows came into being.
| Function | Input | Use when | Row count |
|---|---|---|---|
as_workflow_set() |
Named workflow objects (via ...) |
You already built complete workflows by hand or in a loop | Number of inputs |
workflow_set() |
A list of preprocessors and a list of model specs | You want every preprocessor x model combination | preprocessors x models |
bind_rows() (on sets) |
Two or more workflow_set tibbles |
You need to merge sets built at different times | Sum of input rows |
workflow_set() does the crossing; as_workflow_set() does the wrapping. Reach for workflow_set() when you want a grid of preprocessor times model. Reach for as_workflow_set() when each workflow is already its own thing and you only need them collected so tuning verbs can sweep through them.Common pitfalls
Unnamed arguments fail loudly. as_workflow_set() requires every dot to be named because the names become wflow_id values used by every downstream join.
Non-workflow inputs are rejected. Passing a raw parsnip model spec or a recipe instead of a full workflow raises an error rather than silently coercing.
Duplicate ids overwrite silently in some pipelines. Reusing the same name across two as_workflow_set() calls and then bind_rows-ing the results leaves you with two rows sharing one wflow_id. workflow_map() will run both, but rank_results() then treats them as different configurations of the same model. Always sweep names with make.unique() before binding sets that may collide.
Try it yourself
Try it: Build two regression workflows on mtcars (a basic linear model and a polynomial term), wrap them with as_workflow_set(), and store the result in ex_set.
Click to reveal solution
Explanation: Each argument name becomes the wflow_id for that row, so basic and poly show up as the labels you can later filter, rank, or plot by.
Related workflowsets and tidymodels functions
- workflow_set() builds a set from preprocessor crossed with model lists.
- workflow_map() fits or tunes every workflow in a set across one resample object.
- rank_results() sorts a fitted set by a chosen metric.
- workflow() is the single-model object that
as_workflow_set()wraps. - extract_workflow() pulls a named workflow back out of a set.
For the canonical reference, see the workflowsets package site.
FAQ
What is the difference between as_workflow_set() and workflow_set()?
workflow_set() takes a list of preprocessors and a list of model specs and returns the cross-product (every preprocessor paired with every model). as_workflow_set() takes workflows that are already complete and wraps them into the same workflow_set container without any combinatorial step. Use the first for grids; use the second for hand-picked lineups.
Can I add a new workflow to an existing workflow_set?
Not directly with as_workflow_set(). Wrap the new workflow as a one-row set, then combine: bind_rows(existing, as_workflow_set(new_id = new_wf)). The resulting tibble keeps the workflow_set class so verbs like workflow_map() and rank_results() continue to work.
Why does as_workflow_set() require named arguments?
Names become the wflow_id column, the join key used by workflow_map(), collect_metrics(), rank_results(), and every other workflowsets verb. Without names the join would have nothing to grip and most downstream calls would fail with a missing-column error.
Can I pass a parsnip model spec instead of a full workflow?
No. as_workflow_set() validates each input with is_workflow() and aborts on anything else. Wrap your model spec in workflow() |> add_model(spec) |> add_formula(y ~ .) first, then pass the result.
How do I splice a list of workflows built by purrr::map()?
Use the rlang splice operator !!!. If wf_list is a named list of workflows, as_workflow_set(!!!wf_list) unpacks it so each element becomes a separate named argument. This is the cleanest way to feed programmatically constructed workflows into a set.