1

I'm trying to automate creating variables indicating whether students' answer (variables beginning with l,m, f or g) to the questions (eg. variables starting in "test_") are correct or not. ie. This done by checking whether, for example, test_l1 == l1.

I cannot figure out how to do this other than using the index, but it's very tedious and creates a lot of codes.

Below is a toy dataset that mimics the structure of the actual dataset which has 4 different kinds of tests with 12 exercises each (test_l1 ~ test_l12, test_m1 ~ test_m12, test_f1~,test_g1~) and corresponding student responses (l1~l12, m1~m12, f1~, g1~). I would like to create 48 variables that are namely correct_l1 ~ correct_l12, correct_m1~, correct_f1~ etc.)

df<-data.frame(test_l1 = c(1,0,0), test_l2=c(1,1,1), test_m1 = c(0,1,0), test_m2=c(0,1,1), l1=c(0,1,0), l2=c(1,1,1), m1=c(1,1,1), m2=c(0,0,1))

Many thanks in advance!!!

ravman
  • 25
  • 4

2 Answers2

1

Get all the 'test' columns in test_cols, remove the string 'test_' from test_cols to get the corresponding columns to compare.

Directly compare the two dataframes and create new columns.

test_cols <- grep('test', names(df), value = TRUE)
ans_cols <- sub('test_', '', test_cols)
df[paste0('correct_', ans_cols)] <- df[test_cols] == df[ans_cols]

df
#  test_l1 test_l2 test_m1 test_m2 l1 l2 m1 m2 correct_l1 correct_l2 correct_m1 correct_m2
#1       1       1       0       0  0  1  1  0      FALSE       TRUE      FALSE       TRUE
#2       0       1       1       1  1  1  1  0      FALSE       TRUE       TRUE      FALSE
#3       0       1       0       1  0  1  1  1       TRUE       TRUE      FALSE       TRUE

where TRUE means the answer is correct and FALSE means answer is wrong.

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Thank you so much, that worked!! (Upvoted but I'm a stack novice and don't have the reputation pts to upvote yet :( ) – ravman Jul 12 '21 at 14:23
1

Here is a tidyverse solution you can use:

library(dplyr)

df %>%
  mutate(across(starts_with("test_"), ~ .x == get(sub("test_", "", cur_column())), 
                .names = '{gsub("test_", "answer_", .col)}'))

  test_l1 test_l2 test_m1 test_m2 l1 l2 m1 m2 answer_l1 answer_l2 answer_m1 answer_m2
1       1       1       0       0  0  1  1  0     FALSE      TRUE     FALSE      TRUE
2       0       1       1       1  1  1  1  0     FALSE      TRUE      TRUE     FALSE
3       0       1       0       1  0  1  1  1      TRUE      TRUE     FALSE      TRUE
Anoushiravan R
  • 21,622
  • 3
  • 18
  • 41
  • Thank you so much, that worked!! (Upvoted but I'm a stack novice and don't have the reputation pts to upvote yet :( ) – ravman Jul 12 '21 at 14:23
  • 2
    Nice use of `cur_column()` – akrun Jul 12 '21 at 16:44
  • My pleasure dear Arun, this question was an opportunity I tweaked `.names` argument with a string manipulation function and again thanks to one of Anil's questions. – Anoushiravan R Jul 12 '21 at 17:25