1
votes
library(tidyverse)    

Using the sample code below, I want to use "mutate" or "mutate_at" to recode multiple columns into new columns based on the value of another column. Basically, I would like to recode the variables ending is "s" (q25s,q26s,etc...), based on the value of the corresponding non "s" variable. So for example, if q25 = 1, then q25s will be recoded so that 1 = 0, 2=0, 3=0, 4=1, 5=1, and 88=Missing, and the new name will be q25_new. If q25 does not equal 1, then is should not be recoded and q25_new should just be NA.

However, in order to achieve this I'm attempting to use tidyverse to create named vectors of column names, and then use "mutate", "recode", and "if_else" together with purr::map2.

I'm thinking something like the code below should be possible? I can't quite get it to work...and I feel like I need to use "paste0" somewhere to name all the new column variable names that start with "_new".

cols1<-Df %>%select(q25:q29)
cols2<-Df %>% select(q25s:q29s)

Df<- Df %>% map2(Df[cols1],Df[cols2],
  ~if_else(.x==1, mutate_at(vars (.y),funs(recode(.,`1`=0,`2`=0,`3`=0,`4`=1,`5`=1),"NA"))))

Here is the sample code.

Here is the sample code:
q25<-c(2,1,88,2,1)
q26<-c(2,88,88,88,2)
q27<-c(2,2,1,1,1)
q28<-c(88,1,1,2,2)
q29<-c(1,1,1,2,2)
q25s<-c(3,5,88,4,1)
q26s<-c(4,4,5,5,1)
q27s<-c(3,3,4,1,4)
q28s<-c(4,5,88,1,3)
q29s<-c(88,88,3,4,4)
Df<-data.frame(q25,q26,q27,q28,q29,q25s,q26s,q27s,q28s,q29s)
1
Can you show your desired output? Do want to keep q..s if q.. is not equal to 1?Psidom
If q.. is not equal to 1, then q..s should not be recoded, so I suppose q_new would then be NA.Mike
See my comment to the other answer below...Mike

1 Answers

1
votes

Would this work ?

map2(Df[1:5],Df[6:10], ~ if_else(.x==1, recode(.y,`1`=0,`2`=0,`3`=0,`4`=1,`5`=1,`88` = NA_real_),NA_real_)) %>%
  as.data.frame %>%
  rename_all(paste0,"_new") %>%
  cbind(Df,.)

#   q25 q26 q27 q28 q29 q25s q26s q27s q28s q29s q25_new q26_new q27_new q28_new q29_new
# 1   2   2   2  88   1    3    4    3    4   88       3       4       3       4      NA
# 2   1  88   2   1   1    5    4    3    5   88       1       4       3       1      NA
# 3  88  88   1   1   1   88    5    4   88    3      88       5       1      NA       0
# 4   2  88   1   2   2    4    5    1    1    4       4       5       0       1       4
# 5   1   2   1   2   2    1    1    4    3    4       0       1       1       3       4

OK in the end I couldn't resist the challenge, so here's the pretty much 100% tidy way to go at it (same output) :

library(tidyr)
Df %>%
  mutate(n=row_number()) %>%
  gather(key,value,-n) %>%
  mutate(key2 = ifelse(grepl("s",key),"s","x"),
         key=sub("s","",key)) %>%
  spread(key2,value) %>%
  mutate(`_new` = if_else(x==1, recode(s,`1`=0,`2`=0,`3`=0,`4`=1,`5`=1,`88` = NA_real_),Inf)) %>%
  gather(key3,value,s,x,`_new`) %>%
  unite(key,key,key3,sep="") %>%
  spread(key,value) %>%
  rename_all(~gsub("x","",.x)) %>%
  select(order(nchar(names(.))),-n)