Home > Mobile >  How to modify a column named in another column using adjacent column in tidyverse?
How to modify a column named in another column using adjacent column in tidyverse?

Time:03-08

I've the following dataframe,

df <- tibble(x = c(2, 3, 4)) %>% 
mutate(`1` = 99, `2` = 88, `3` = 77, `4` = 66, `5` = 55)

column x holds the column names which needs to be manipulated, the value in that column has to be replaced with the sum of values in columns x-1, x and x 1. For example, for the first row where x is 2, value in column 2 has to be replaced with (99 88 77) = 264.

I tried using double curly brackets({{}}) and :=, like below,

df %>% 
  mutate("{{x}}" := {{x-1}}   {{x}}   {{x 1}})

but I'm getting the following error, Error in local_error_context(dots = dots, .index = i, mask = mask) : promise already under evaluation: recursive default argument reference or earlier problems?

Then I tried accessing the column using cur_column() inside across() like below,

df %>% 
  mutate(across(-x, ~if_else(x == cur_column(), {{cur_column()}}, .x)))

and I'm getting the same error as above, I think I may be using the curly operator incorrectly, can someone help, please?

CodePudding user response:

The {{}} syntax is for when you are passing unevaluated expressions to a dplyr command, it does not work for capturing column values.

Most of the time it's not easy to do different options on different columns for each row. One alternative is to reshape your data so you can use lead/lag functions. Then you can pivot back.

library(dplyr)
library(tidyr)
df %>% 
  mutate(row = row_number()) %>% 
  pivot_longer(!c(x, row)) %>% 
  mutate(name = as.integer(name)) %>% 
  group_by(row) %>% 
  mutate(value=if_else(x==name, value   lead(value)   lag(value), value)) %>% 
  pivot_wider(c(row, x)) %>% 
  select(-row)

#     row     x   `1`   `2`   `3`   `4`   `5`
#   <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     1     2    99   264    77    66    55
# 2     2     3    99    88   231    66    55
# 3     3     4    99    88    77   198    55

Another alternative is to create a helper function that can access the cur_column() and cur_data() with rowwise() in order to create a different transformation for each row.


colclump <- function(target) {
  prevc <- as.character(as.integer(target)-1)
  nextc <- as.character(as.integer(target) 1)
  function(x) {
    if (cur_column()==target) {
      x   cur_data()[[prevc]]   cur_data()[[nextc]]
    } else {
      x
    }
  }
  
}
df %>% 
  rowwise() %>% 
  mutate(across(-x, ~colclump(x)(.x)))

CodePudding user response:

Maybe this one also serves your purpose:

for(k in 2:4) {
  df[k-1,k 1] <- df[k-1,as.character(df$x[k-1])]   
              df[k-1,as.character(df$x[k-1]-1)]   
              df[k-1,as.character(df$x[k-1] 1)]
}
df
#  A tibble: 3 x 6
# x   `1`   `2`   `3`   `4`   `5`
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     2    99   264    77    66    55
# 2     3    99    88   231    66    55
# 3     4    99    88    77   198    55
  • Related