Search code examples
rmutate

fill a column with name and content of 3 other columns


dput(df)
structure(list(trtmt = c(26, 28, 35, 42, 49, 63, 33, 24, 38, 
4, 24, 10, 59, 20, 16, 15, 66, 23, 51, 41, 39, 17, 8, 9, 28, 
2, 13, 32, 43, 58, 4, 49, 63, 27, 27, 34, 6, 8, 57, 43, 23, 10, 
50, 47, 41, 65, 57, 21, 15, 35), R = c(150, 150, 0, 0, 25, 25, 
0, 100, 0, 150, 100, 0, 100, 50, 25, 25, 33, 100, 100, 0, 0, 
50, 0, 0, 150, 50, 25, 0, 0, 50, 150, 25, 25, 150, 150, 0, 0, 
0, 25, 0, 100, 0, 50, 100, 0, 100, 25, 100, 25, 0), V = c(50, 
150, 50, 150, 0, 100, 50, 150, 100, 0, 150, 0, 0, 150, 150, 100, 
30.3, 100, 0, 150, 100, 25, 150, 0, 150, 0, 25, 25, 150, 0, 0, 
0, 100, 100, 100, 50, 50, 150, 0, 150, 100, 0, 0, 0, 150, 25, 
0, 25, 100, 50), B = c(0, 0, 100, 50, 50, 25, 25, 0, 50, 0, 0, 
50, 150, 0, 0, 0, 1.8, 0, 50, 25, 100, 0, 0, 25, 0, 0, 0, 150, 
100, 150, 0, 50, 25, 0, 0, 50, 0, 0, 150, 100, 0, 50, 50, 25, 
25, 25, 150, 0, 0, 100)), row.names = c(NA, -50L), class = c("tbl_df", 
"tbl", "data.frame"))

    head(df)
# A tibble: 6 × 4
  trtmt     R     V     B
  <dbl> <dbl> <dbl> <dbl>
1    26   150    50     0
2    28   150   150     0
3    35     0    50   100
4    42     0   150    50
5    49    25     0    50
6    63    25   100    25

With the code below, I was telling R, for each row in the key column, grab the column names and values of R, V, and B, from left to right, and combine.

df %>%
rowwise() %>%
  mutate(key = paste0(names(.[2:4])[c_across() == c(2:4)], collapse = '_'))

but I got this error

Error in `mutate()`:
! Problem while computing `key = paste0(names(.)[c_across() == c(2:4)], collapse = "_")`.
ℹ The error occurred in row 1.
Caused by error:
! Can't combine `trtmt` <double> and `id` <character>.

What I expected is

  trtmt     R     V     B key            
  <dbl> <dbl> <dbl> <dbl> <chr>          
1    26   150    50     0 R150_V50_B0
2    28   150   150     0 R150_V150_B0
3    35     0    50   100 R0_V50_B100
4    42     0   150    50 R0_V150_B_50
5    49    25     0    50 R25_V0_B50
6    63    25   100    25 R25_V100_B25

I got the hint from Create new column containing names of other columns based on values ​of those columns.

Thanks for stopping by.


Solution

  • We could use cur_column() to get the column names by looping across the columns of interest, paste (str_c) the column names with the values of the column, then use invoke (or exec from purrr - similar to do.call/Reduce in base R to paste the columns row wise)

    library(purrr)
    library(dplyr)
    library(stringr)
    df %>% 
       mutate( key = invoke(str_c, 
           across(R:B, ~ str_c(cur_column(), .x)),  sep = "_"))
    

    -output

    # A tibble: 50 × 5
       trtmt     R     V     B key         
       <dbl> <dbl> <dbl> <dbl> <chr>       
     1    26   150    50     0 R150_V50_B0 
     2    28   150   150     0 R150_V150_B0
     3    35     0    50   100 R0_V50_B100 
     4    42     0   150    50 R0_V150_B50 
     5    49    25     0    50 R25_V0_B50  
     6    63    25   100    25 R25_V100_B25
     7    33     0    50    25 R0_V50_B25  
     8    24   100   150     0 R100_V150_B0
     9    38     0   100    50 R0_V100_B50 
    10     4   150     0     0 R150_V0_B0  
    # … with 40 more rows