Je recherche une méthode efficace pour combiner ces 2 data.frames: L'un avec les questions et leurs réponses et points associés (questions organisées par lignes)
result_research <- data.frame(cand = c("can1","can2","can3"), X01 = c(1,1,0), X02 = c(0,2,2), X03 = c(1,1,1), X04 = c(0.5,0.5,0)) cand X01 X02 X03 X04 can1 1 0 1 0.5 can2 1 2 1 0.5 can3 0 2 1 0.0
et l'autre avec le nombre de candidats et leur réponse (questions organisées par colonnes)
extract <- data.frame(cand = c("can1","can2","can3"), X01 = c("A","A","B"), X02 = c("B","C","C"), X03 = c("B","B","B"), X04 = c("C","C","A")) cand X01 X02 X03 X04 can1 A B B C can2 A C B C can3 B C B A
Comment accéder au prochain résultat? Un bloc de données avec la même dimension que le second mais au lieu des réponses, nous trouverions les points situés dans le bloc de données réponse.
Sortie souhaitée:
answer <- data.frame(num_question = c("X01","X02","X03","X04"), ans = c("A","C","B","C"), point = c(1,2,1,0.5)) num_question ans point X01 A 1.0 X02 C 2.0 X03 B 1.0 X04 C 0.5
5 Réponses :
library(tidyverse) tmp <- extract %>% gather(num_question, can_ans, -cand) %>% # turn the extract data.frame into long format left_join(answer, by="num_question") %>% #merge extract by question number into a single data.frame mutate(correct = (can_ans == ans)+0) %>% # is candidate answer the same as the correct answer (1 = TRUE, 0 = FALSE) mutate(result = correct*point) # multiply correct answer (1) with points given #turn the data.frame into wide format tmp %>% select(cand, num_question, result) %>% spread(num_question,result) # cand X01 X02 X03 X04 # 1 can1 1 0 1 0.5 # 2 can2 1 2 1 0.5 # 3 can3 0 2 1 0.0
cand X01 X02 X03 X04 1 can1 1 0 1 0.5 2 can2 1 2 1 0.5 3 can3 0 2 1 0.0
Nous pouvons utiliser dplyr
et tidyr
pour collecter
des données au format long, left_join
sur num_question
et ans
, remplacez les NA
s par 0 et répartissez
les données en grand format.
library(dplyr) library(tidyr) extract %>% gather(key, value, -cand) %>% left_join(answer, by = c("key" = "num_question", "value" = "ans")) %>% replace_na(list(point = 0)) %>% select(-value) %>% spread(key, point) # cand X01 X02 X03 X04 #1 can1 1 0 1 0.5 #2 can2 1 2 1 0.5 #3 can3 0 2 1 0.0
Voici une approche de base R avec stack
et unstack
, c'est-à-dire
d1 <- stack(extract[-1]) d1$values <- answer$point[match(do.call(paste, d1), paste(answer$ans, answer$num_question))] d1$values <- replace(d1$values, is.na(d1$values), 0) cbind.data.frame(cand = extract$cand, unstack(d1)) # cand X01 X02 X03 X04 #1 can1 1 0 1 0.5 #2 can2 1 2 1 0.5 #3 can3 0 2 1 0.0
Où puis-je trouver la fonction de pile? dans le paquet utils?
C'est une fonction de base R
Cela peut également être fait avec la base R en utilisant apply
:
answer <- answer[match(answer$num_question, names(extract)[-1]), ] extract[, -1] <- t((t(extract[, -1]) == answer$ans) * answer$point) extract #> cand X01 X02 X03 X04 #> 1 can1 1 0 1 0.5 #> 2 can2 1 2 1 0.5 #> 3 can3 0 2 1 0.0
Pour chaque ligne de extract
(c'est-à-dire chaque candidat) correspond les numéros de question entre data.frames en utilisant match
. Si la réponse donnée coïncide avec la bonne réponse, renvoyez le point associé, sinon renvoyez zéro.
Ou sans appliquer
en utilisant uniquement des opérations vectorisées:
extract[, -1] <- t(apply(extract[, -1], 1, function(x) ifelse(x[match(names(x), answer$num_question)] == answer$ans, answer$point, 0) )) extract #> cand X01 X02 X03 X04 #> 1 can1 1 0 1 0.5 #> 2 can2 1 2 1 0.5 #> 3 can3 0 2 1 0.0