0Pricing
R Academy · Lesson

Workflows: Combining Recipes and Models

Bundle preprocessing and model into a single workflow object.

Workflows: Combining Recipes and Models is a free R Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is a Workflow?

A workflow bundles a recipe and a model spec into a single object. This solves a critical problem: preprocessing and modelling steps must be treated as one unit during cross-validation and final fitting, otherwise parameters like normalization means can leak from test folds.

library(workflows)

# Start an empty workflow
wf <- workflow()
print(wf)

# Workflows have two slots: preprocessor and model
# Both must be filled before fitting

add_recipe() and add_model()

Use add_recipe(rec) to attach a recipe preprocessor and add_model(spec) to attach a parsnip model specification. The pipe operator makes this highly readable.

library(recipes)
library(parsnip)
library(workflows)

rec <- recipe(price ~ ., data = train) |>
  step_impute_median(all_numeric_predictors()) |>
  step_dummy(all_nominal_predictors()) |>
  step_normalize(all_numeric_predictors())

spec <- linear_reg() |> set_engine('lm')

wf <- workflow() |>
  add_recipe(rec) |>
  add_model(spec)

print(wf)

fit() on a Workflow

Calling fit(wf, data = train) on a workflow automatically calls prep() on the recipe using the training data and then trains the model on the preprocessed features. You never need to manually call prep() or bake().

fitted_wf <- fit(wf, data = housing_train)

# The fitted workflow stores both the prepped recipe
# and the trained model
print(fitted_wf)

predict() on a Fitted Workflow

When you call predict(fitted_wf, new_data = test), the workflow automatically applies bake() to the new data using the trained recipe before generating predictions. This eliminates the risk of forgetting to preprocess test data.

# Predictions automatically preprocess the test data
preds <- predict(fitted_wf, new_data = housing_test)
head(preds)

# For classification
preds_prob <- predict(fitted_wf, new_data = test_df, type = 'prob')
preds_class <- predict(fitted_wf, new_data = test_df, type = 'class')

last_fit() — Train on All, Evaluate on Test

last_fit(wf, split) takes your final workflow and the initial train/test split object. It fits the workflow on the training portion and evaluates it on the test portion — the standard final-model evaluation step after tuning is complete.

library(rsample)

split <- initial_split(housing_data, prop = 0.8, strata = price)

# Fit on training, evaluate on test
final_res <- last_fit(wf, split)

# View performance on the held-out test set
collect_metrics(final_res)

extract_fit_parsnip()

extract_fit_parsnip(fitted_wf) pulls out the trained parsnip model object from a fitted workflow. You can then use it to inspect coefficients, variable importance, or pass to model-explanation tools.

fitted_wf <- fit(wf, data = housing_train)

# Extract the parsnip model
parsnip_fit <- extract_fit_parsnip(fitted_wf)

# Now access the underlying model
tidy(parsnip_fit)      # coefficients for lm
vip::vip(parsnip_fit)  # variable importance plot

extract_recipe()

extract_recipe(fitted_wf) returns the prepped recipe from a fitted workflow. This is useful for inspecting what transformations were applied or for retrieving the trained preprocessing to apply to external data independently.

fitted_wf <- fit(wf, data = housing_train)

# Get the prepped recipe
prepped_rec <- extract_recipe(fitted_wf)

# Inspect normalization stats
tidy(prepped_rec, number = 3)  # step_normalize details

# Apply recipe to completely new external data
new_baked <- bake(prepped_rec, new_data = brand_new_df)

augment() on Workflows

augment(fitted_wf, new_data) returns the input data frame with prediction columns appended. For regression it adds .pred; for classification it adds .pred_class and probability columns for each class.

fitted_wf <- fit(wf, data = housing_train)

# Append predictions to the test data frame
results <- augment(fitted_wf, new_data = housing_test)

# Now compute metrics directly
library(yardstick)
results |>
  metrics(truth = price, estimate = .pred)

Updating a Workflow

You can update individual components of a workflow with update_recipe() or update_model() without rebuilding from scratch. This is handy during experimentation when you want to swap the model engine while keeping the same recipe.

# Original workflow with lm
wf_lm <- workflow() |>
  add_recipe(rec) |>
  add_model(linear_reg() |> set_engine('lm'))

# Swap model to random forest, keep same recipe
wf_rf <- update_model(
  wf_lm,
  rand_forest(trees = 300) |>
    set_engine('ranger') |>
    set_mode('regression')
)

fit_rf <- fit(wf_rf, data = housing_train)

add_formula() vs add_recipe()

If you don't need a recipe, you can use add_formula(outcome ~ .) as the preprocessor. This applies minimal transformations (just the formula specification). Use add_recipe() when you need feature engineering; use add_formula() for quick baseline models.

# Simple baseline — no recipe needed
baseline_wf <- workflow() |>
  add_formula(price ~ sqft + bedrooms + bathrooms) |>
  add_model(linear_reg() |> set_engine('lm'))

baseline_fit <- fit(baseline_wf, data = housing_train)
baseline_preds <- predict(baseline_fit, new_data = housing_test)

# Compare RMSE to recipe-based model
yardstick::rmse_vec(housing_test$price, baseline_preds$.pred)

Workflow Sets for Comparison

workflow_set() from the workflowsets package creates a collection of workflows combining multiple recipes and model specs. You can then tune and evaluate all combinations at once with workflow_map().

library(workflowsets)

all_workflows <- workflow_set(
  preproc = list(basic = basic_rec, full = full_rec),
  models  = list(
    lm  = linear_reg() |> set_engine('lm'),
    rf  = rand_forest(trees = 200) |> set_engine('ranger') |> set_mode('regression')
  )
)

# Fit all 4 combinations on resamples
results <- workflow_map(all_workflows, 'fit_resamples', resamples = cv_folds)
autoplot(results)

Quick Check

What is the main advantage of using last_fit(workflow, split) instead of manually fitting and predicting?

Workflows Recap

Key takeaways from Workflows: Combining Recipes and Models:

  • workflow() |> add_recipe(rec) |> add_model(spec) bundles preprocessing and modelling.
  • fit(wf, data = train) preps the recipe and trains the model in one call.
  • predict(fitted_wf, new_data) automatically bakes new data before predicting.
  • last_fit(wf, split) trains on train, evaluates on test — use for final model assessment.
  • extract_fit_parsnip() and extract_recipe() retrieve components for inspection.
  • augment() appends predictions to the data frame for easy metric calculation.
  • workflow_set() compares multiple recipe-model combinations simultaneously.
# Canonical tidymodels workflow pattern
split    <- initial_split(data, prop = 0.8)
train    <- training(split)
test     <- testing(split)

rec  <- recipe(y ~ ., data = train) |> step_normalize(all_numeric_predictors())
spec <- rand_forest(trees = 300) |> set_engine('ranger') |> set_mode('regression')

wf   <- workflow() |> add_recipe(rec) |> add_model(spec)

final_res <- last_fit(wf, split)
collect_metrics(final_res)

Frequently asked questions

Is the “Workflows: Combining Recipes and Models” lesson free?

Yes — the full text of “Workflows: Combining Recipes and Models” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.

What will I learn in “Workflows: Combining Recipes and Models”?

Bundle preprocessing and model into a single workflow object. You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start R Academy?

No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Workflows: Combining Recipes and Models” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this R Academy lesson?

Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Feature Engineering with recipes
  2. Model Specifications with parsnip
  3. Workflows: Combining Recipes and Models
  4. Resampling and Cross-Validation with rsample
← Back to R Academy