Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Conditionally mutate existing values by group R

I know this is similar to previous questions, but this seems a little different to me because it’s referring to existing values. I have R simplified R dataframe below.

set.seed(2342)
df <- tibble(bp = rep(c("vt1", "vt2"), 4),
             id = rep(c(1, 2), each = 4, 1),
             alg_vt1 = rep(c("a", "b"), each = 2, 2),
             alg_vt2 = rep(c("a", "b"), 4)) %>% 
    mutate(vo2 = round(runif(nrow(.), 10, 20)),
           vo2 = if_else(bp == "vt2", vo2 * 2, vo2))

Here’s what the sample data frame looks like (side note, how do I get the spacing in my dataframe correct when pasting a data frame into Stack Overflow?)

bp  id  alg_vt1 alg_vt2 vo2
vt1 1   a   a   18
vt2 1   a   b   36
vt1 1   b   a   16
vt2 1   b   b   30
vt1 2   a   a   19
vt2 2   a   b   32
vt1 2   b   a   10
vt2 2   b   b   34

I want to mutate a new column equal to the vo2 at vt2 for each combination of id, alg_vt1, and alg_vt2. That is, I want a data frame that looks like this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

bp  id  alg_vt1 alg_vt2 vo2 vo2_vt2
vt1 1   a   a   18  36
vt2 1   a   b   36  36
vt1 1   b   a   16  30
vt2 1   b   b   30  30
vt1 2   a   a   19  32
vt2 2   a   b   32  32
vt1 2   b   a   10  34
vt2 2   b   b   34  34

I’ve tried variations of

df %>% 
    group_by(id, alg_vt1, alg_vt2) %>% 
    mutate(vo2_vt2 = 

but whatever I put after that gives me an error or I don’t get the output I expect. I know there are hacky ways I could figure this out, but I’m sure there’s a "tidyverse" way to solve this problem. I feel like filter() or pick() could get me there, but I can’t quite put this all together.

>Solution :

tidyr::fill() can do the job.

library(tidyverse)

df |> 
  mutate(vo2_vt2 = ifelse(bp == "vt1", NA, vo2)) |> 
  fill(vo2_vt2, .direction = "up")
#> # A tibble: 8 × 6
#>   bp       id alg_vt1 alg_vt2   vo2 vo2_vt2
#>   <chr> <dbl> <chr>   <chr>   <dbl>   <dbl>
#> 1 vt1       1 a       a          18      36
#> 2 vt2       1 a       b          36      36
#> 3 vt1       1 b       a          16      30
#> 4 vt2       1 b       b          30      30
#> 5 vt1       2 a       a          19      32
#> 6 vt2       2 a       b          32      32
#> 7 vt1       2 b       a          10      34
#> 8 vt2       2 b       b          34      34

Regarding your question about pasting data.frames into SO: Use reprex to prepare your question/answer it will take care of the formatting.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading