Генерация нескольких столбцов переменных с помощью `dplyr` и функции в векторизации - PullRequest
2 голосов
/ 29 марта 2020

Представьте себе, что для собранной анкеты по десяткам предметов я хочу проверить правильность ответов на каждый вопрос. Чтобы выполнить эту манипуляцию по столбцам, я использую функцию mapply, где векторизованными парами являются столбцы (несколько переменных) и векторы (несколько элементов) соответственно, подробности см. Ниже в демонстрационном коде. Однако при таком методе мне нужно сгенерировать переменные вручную, чтобы включить их в исходный фрейм данных, поэтому мне интересно, есть ли альтернативный метод, с помощью которого можно добиться аналогичного эффекта, используя многовариантную версию функции mutate в dplyr пакетах? поэтому нет необходимости генерировать имена переменных вручную и реализовывать их в векторизованном виде.

##simulated data generation with four questions
IDs<-paste0('subj',0,1:7)
Q1<-c('A','B','C','A','A','A','D')
Q2<-c('A','B','B','B','B','D','C')
Q3<-c('B','B','C','C','C','D','C')
Q4<-c('A','D','D','B','D','D','C')
vect<-data.frame(cbind(IDs,Q1,Q2,Q3,Q4))

##answer for the four questions
answer<-c('A','B','C','D')

##method with mapply function
myfunc<-function(vec,value) {
  ifelse(vec==value, TRUE, FALSE)
}

newvariable<-mapply(myfunc, vect[,2:5], answer)

colnames(newvariable)<-paste0('Q',1:4,"_ans")
newvariable
vect_new1<-cbind(vect,newvariable)
vect_new1

Ответы [ 3 ]

2 голосов
/ 29 марта 2020

Базовый способ, используя apply:

cbind(vect, `colnames<-`(t(apply(vect[-1], 1, `==`, answer)), paste0("Q", 1:4, "_Ans")))

Или используя map2:

library(tidyverse)

vect %>%
  select(-IDs) %>%
  map2_dfc(answer, `==`) %>%
  set_names(~ str_c(., "_Ans")) %>%
  bind_cols(vect, .)

Или

vect %>%
  pivot_longer(Q1:Q4) %>%
  mutate(Ans = value == answer) %>%
  pivot_wider(values_from = c(value, Ans))

Выход

#      IDs Q1 Q2 Q3 Q4 Q1_Ans Q2_Ans Q3_Ans Q4_Ans
# 1 subj01  A  A  B  A   TRUE  FALSE  FALSE  FALSE
# 2 subj02  B  B  B  D  FALSE   TRUE  FALSE   TRUE
# 3 subj03  C  B  C  D  FALSE   TRUE   TRUE   TRUE
# 4 subj04  A  B  C  B   TRUE   TRUE   TRUE  FALSE
# 5 subj05  A  B  C  D   TRUE   TRUE   TRUE   TRUE
# 6 subj06  A  D  D  D   TRUE  FALSE  FALSE   TRUE
# 7 subj07  D  C  C  C  FALSE  FALSE   TRUE  FALSE
2 голосов
/ 29 марта 2020

Ваш вопрос связан с вопросом стандартной оценки. Это может быть довольно сложно с dplyr ( см. Сообщение в блоге, которое я написал вчера ).

С dplyr вам будет довольно сложно, потому что он не очень адаптирован к столбцу имена в строке. Ваша проблема была бы легче решена с помощью data.table

Сначала преобразуйте ваш объект в data.table

library(data.table)
data.table::setDT(vect)

Затем вам просто нужно перебрать ваш вектор ответов (если они в хорошем порядке!) и используйте условную замену data.table на :=

output <- lapply(seq_len(length(answer)), function(ans) {

  vect[,c(paste0("Q",ans,"_ans")) := FALSE]
  vect[get(paste0("Q",ans)) == answer[ans], c(paste0("Q",ans,"_ans")) := TRUE]
} )
output <- output[[length(output)]]

Последняя строка - потому что вы повторяете итерацию по одному и тому же набору данных, но возвращаете последний. Вас интересует только результат последней итерации.

Результат:

output
# IDs Q1 Q2 Q3 Q4 Q1_ans Q2_ans Q3_ans Q4_ans
# 1: subj01  A  A  B  A   TRUE  FALSE  FALSE  FALSE
# 2: subj02  B  B  B  D  FALSE   TRUE  FALSE   TRUE
# 3: subj03  C  B  C  D  FALSE   TRUE   TRUE   TRUE
# 4: subj04  A  B  C  B   TRUE   TRUE   TRUE  FALSE
# 5: subj05  A  B  C  D   TRUE   TRUE   TRUE   TRUE
# 6: subj06  A  D  D  D   TRUE  FALSE  FALSE   TRUE
# 7: subj07  D  C  C  C  FALSE  FALSE   TRUE  FALSE
2 голосов
/ 29 марта 2020

Один из вариантов может быть:

bind_cols(vect, vect %>%
           do(data.frame(sweep(select(., -1), 2, FUN = `==`, c("A", "B", "C", "D")))) %>%
           rename_all(~ paste0(., "_ans")))

     IDs Q1 Q2 Q3 Q4 Q1_ans Q2_ans Q3_ans Q4_ans
1 subj01  A  A  B  A   TRUE  FALSE  FALSE  FALSE
2 subj02  B  B  B  D  FALSE   TRUE  FALSE   TRUE
3 subj03  C  B  C  D  FALSE   TRUE   TRUE   TRUE
4 subj04  A  B  C  B   TRUE   TRUE   TRUE  FALSE
5 subj05  A  B  C  D   TRUE   TRUE   TRUE   TRUE
6 subj06  A  D  D  D   TRUE  FALSE  FALSE   TRUE
7 subj07  D  C  C  C  FALSE  FALSE   TRUE  FALSE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...