Search code examples
rdplyrmutate

mutate several combinations of var prefixes and suffixes, conditionally


I want to write a shorter version of this code:

ResultsTable <- ResultsTable %>%
  mutate(V_a  = as.integer(V_a  + h2_a),
         V_b  = as.integer(V_b  + h2_b),
         V_c  = as.integer(V_c  + h2_c),
         V_d  = as.integer(V_d  + h2_d),
         V_e  = as.integer(V_e  + h2_e),
         V_f  = as.integer(V_f  + h2_f))

the point it that there are several variable prefixes and suffixes that need to be combined.

also, this should be done only for lines where ResultsTable$cond == 1, but all lines must be kept.

I tried using across(), but that doesn't seem to work with both prefixes and suffixes.

I don't even know how to approach this. help!


Solution

  • It is easier to help if you provide a reproducible example along with expected output. Here is a simple made up example -

    df <- data.frame(cond = c(1, 1, 0, 1, 0), 
                     V_a = 1:5, V_b = 11:15, 
                     h2_a = 26:30, h2_b = 36:40)
    
    df
    
    #  cond V_a V_b h2_a h2_b
    #1    1   1  11   26   36
    #2    1   2  12   27   37
    #3    0   3  13   28   38
    #4    1   4  14   29   39
    #5    0   5  15   30   40
    

    One way to automate this is using across and pick. For better visibility of the results I create new columns to store the output (res_V_a and res_V_b) using .names argument in across. For these results column we check if the cond column is either 1 or 0 and use ifelse to apply the condition.

    library(dplyr)
    
    df %>%
      mutate(across(starts_with("V"), .names = "res_{col}") + pick(starts_with("h2")),
             across(starts_with("res"), ~ifelse(cond == 1, ., 
                                               get(sub("res_", "", cur_column())))))
    
    #  cond V_a V_b h2_a h2_b res_V_a res_V_b
    #1    1   1  11   26   36      27      47
    #2    1   2  12   27   37      29      49
    #3    0   3  13   28   38       3      13
    #4    1   4  14   29   39      33      53
    #5    0   5  15   30   40       5      15
    

    and if you don't want to create new columns and modify only existing columns.

    df %>%
      mutate(pick(starts_with("V")) + pick(starts_with("h2")),
             across(starts_with("V"), ~ifelse(cond == 1, ., 
                                            . - get(sub("V", "h2", cur_column())))))
    
    #  cond V_a V_b h2_a h2_b
    #1    1  27  47   26   36
    #2    1  29  49   27   37
    #3    0   3  13   28   38
    #4    1  33  53   29   39
    #5    0   5  15   30   40