Skip to content

Add step_adjust_linear() for linear adjustment - #281

Open
mattansb wants to merge 5 commits into
tidymodels:mainfrom
mattansb:main
Open

mattansb wants to merge 5 commits into
tidymodels:mainfrom
mattansb:main

Conversation

@mattansb

Copy link
Copy Markdown

This PR addresses the feature request in #275.

I have named the step step_adjust_linear() - its functionality can be seen in the original issue.

Here is the example from the docs:

library(embed)
#> Loading required package: recipes
#> Loading required package: dplyr
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
#> 
#> Attaching package: 'recipes'
#> The following object is masked from 'package:stats':
#> 
#>     step
library(ggplot2)

data("penguins", package = "modeldata")
penguins <- na.omit(penguins)

p <- ggplot(penguins, aes(flipper_length_mm, body_mass_g, color = sex)) +
  geom_point(aes(shape = species)) +
  stat_ellipse() +
  labs(title = "No adjustment")

p

recipe <- recipe(body_mass_g ~ ., data = penguins) |>
  step_adjust_linear(
    flipper_length_mm,
    body_mass_g,
    remove_vars = vars(species),
    keep_vars = vars(sex),
    drop = "none" # keep all variables in the baked data
  )

p +
  (prep(recipe) |>
    bake(new_data = penguins)) +
  labs(title = "Adjustment for species")

Created on 2026-09-23 with reprex v2.1.1


Since the step does not depend on any package other than stats I'm not sure if {embed} or {recipes} are the right place for it.

@EmilHvitfeldt

Copy link
Copy Markdown
Member

I think that {embed} is the right place for this. i'll try to look at this later this week!

@mattansb

Copy link
Copy Markdown
Author

This step can also be used for causal inference - and since it can be used with any other previous steps, it can also adjust non-linear terms. Here's a very simple example:

library(embed)
#> Loading required package: recipes
#> Loading required package: dplyr
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
#> 
#> Attaching package: 'recipes'
#> The following object is masked from 'package:stats':
#> 
#>     step

n <- 500

set.seed(333)

dat <- tibble(
  Z = rnorm(n),
  X = 3^Z + 1.3 * Z^2 - rnorm(n),
  Y = 30 * Z - 4 * X + 100 * rnorm(n)
)

plot(dat)

rec <- recipe(Y ~ ., data = dat) |>
  step_spline_b(Z, deg_free = 5) |>
  step_adjust_linear(X, remove_vars = vars(starts_with("Z")))

baked <- prep(rec) |> bake(new_data = dat, stop_at = 2)

lm(Y ~ X, data = dat) # confounded
#> 
#> Call:
#> lm(formula = Y ~ X, data = dat)
#> 
#> Coefficients:
#> (Intercept)            X  
#>      -6.202       -0.587

lm(Y ~ X, data = baked) # should be about ~4
#> 
#> Call:
#> lm(formula = Y ~ X, data = baked)
#> 
#> Coefficients:
#> (Intercept)            X  
#>       2.070       -3.199

Created on 2026-09-23 with reprex v2.1.1

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants