pluke
pluke

Reputation: 4346

mutate_ column using a calculated column name in dplyr

I have the following data.frame

qs <- structure(list(Question = c("This is a question", "This is a question"), 
Correct_Answer = c("D", "B"), 
Answer.A = c("This is an answer", "This is an answer"), 
Answer.B = c("This is an answer", "This is an answer"), 
Answer.C = c("This is an answer", "This is an answer"), 
Answer.D = c("This is an answer", "This is an answer"), 
Explanation = c("Just because!", "Just because!"), 
Response_A = c("", ""), 
Response_B = c("", ""), 
Response_C = c("", ""), 
Response_D = c("", "")), 
.Names = c("Question", "Correct_Answer", "Answer.A", "Answer.B",
           "Answer.C", "Answer.D", "Explanation", "Response_A", 
           "Response_B", "Response_C", "Response_D"), 
row.names = 1:2, class = "data.frame")

I want to set the Response_X value to match the Explanation for each question. For example in the first row, the Correct_Answer is D, so the Response_D should equal to the explanation, the other Responses_ should remain blank.

I've tried the following:

library(dplyr)

qs %>% rowwise() %>% mutate_(.dots=setNames(paste(Explanation), 
                          paste0("Response_",Correct_Answer)))

It gives:

Error in paste0("Response_", Correct_Answer) : 
  object 'Correct_Answer' not found

I feel I should be using apply here, but not sure how.

Upvotes: 2

Views: 611

Answers (3)

Joe
Joe

Reputation: 8601

A tidyverse solution. You gather the data to a "tidy" form, mutate conditionally on Correct_Answer, and spread it back.

library(tidyr)
library(dplyr)

qs %>% 
   gather(Resp, val, Response_A:Response_D, -Correct_Answer, -Explanation) %>% select(-val) %>% 
   mutate(Expl = if_else(paste("Response", Correct_Answer, sep="_") == Resp, Explanation, "")) %>%
   spread(Resp, Expl)

Hope that does the trick!

Upvotes: 2

Chirayu Chamoli
Chirayu Chamoli

Reputation: 2076

Using regular for loop you could do this:

for(i in 1:nrow(qs)){
    qs[i,paste('Response_',qs[i,'Correct_Answer'], sep = '')]=qs[i,'Explanation']
}

Im still trying to figure out how to update the col values using sapply.

sapply(1:nrow(qs), function(i) qs[paste('Response_',qs[i,'Correct_Answer'], sep = '')]=qs[i,'Explanation'])

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 388817

One way is using a custom function which assigns the correct value in the correct column for that row

assignValue <- function(x) {
   qs[x, paste0("Response_", qs$Correct_Answer[x])] <<- qs$Explanation[x]
 }

and then call the function for every row using sapply

sapply(1:nrow(qs), function(x) assignValue(x))

Note, the use of <<- operator in the function. From the help page (?"<<-")

The operators <<- and ->> are normally only used in functions, and cause a search to made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment

Upvotes: 2

Related Questions