Перекодировать выходные данные опроса с множественным выбором

Я провел опрос с помощью Limesurvey и экспортировал результаты в виде файла csv, который я импортировал в R.

Один из вопросов представляет собой вопрос с множественным выбором, в котором участники могли назвать предметы, которые они изучают. Результат работы лайм-опроса выглядит примерно так (но с большим количеством тем и участников):

Participant | Maths | Physics | English | Biology 
1           |   Y   |         |    Y    |         
2           |       |    Y    |    Y    |         
3           |   Y   |    Y    |         |   Y     

Я хотел бы получить результат, который выглядит так

Participant | Subject 1 | Subject 2| Subject 3  |
1           |   Maths   | English  |            |         
2           |   Physics | English  |            |         
3           |   Maths   | Physics  | Biology    |        

Буду признателен за любые указатели.


person SamVimes    schedule 07.11.2018    source источник
comment
…выглядит примерно так…, если вы покажете нам в точности, как это выглядит, вам будет намного легче помочь. Попробуйте dput(head(your_data)) или что-то в этом роде.   -  person AkselA    schedule 07.11.2018
comment
Я, возможно, был недостаточно ясен, извините за это! Мой файл выглядит точно так же, как в примере, который я привел, только там больше тем и больше участников, которых я не хотел сюда вставлять.   -  person SamVimes    schedule 07.11.2018
comment
Это выглядит так при импорте в R?   -  person AkselA    schedule 07.11.2018
comment
Да, это датафрейм, который выглядит так   -  person SamVimes    schedule 07.11.2018
comment
Если это выглядит так, это не data.frame.   -  person AkselA    schedule 07.11.2018


Ответы (2)


Вот моя попытка сгенерировать ожидаемый кадр данных в соответствии с запросом:

library(tidyverse)
library(gtools)
rand_list = c('Y', NA)
df = data.frame(participant = seq(1,10, by = 1), # r starts counting from 0
                Maths = sample(rand_list, 10, replace = TRUE),
                Physics = sample(rand_list, 10, replace = TRUE),
                English = sample(rand_list, 10, replace = TRUE),
                Biology = sample(rand_list, 10, replace = TRUE))

df_to_new_format = function(data){
  vector_subject = colnames(data)
  vector_new_col = c()
  for (i in 1:length(vector_subject)){
    if (i == 1){
      new_col = 'participant'
      vector_new_col <- c(vector_new_col, new_col)
      rm(new_col)
    } else{
      new_col = paste('Subject', as.character(i - 1))
      vector_new_col <- c(vector_new_col, new_col)
      rm(new_col)
    }
  }

  for (j in 1:length(vector_subject)){
    if (j == 1){
      next
    } else{
      data[[j]] <- recode(data[[j]], 'Y' = vector_subject[j])
    }
  }

  colnames(data) <- vector_new_col
  return(data)
}

df = df_to_new_format(data = df)
df_new_format = c()

for (m in 1:nrow(df)){
  temp = mixedsort(as.matrix(df[m,]))
  print(temp)
  df_new_format = rbind(df_new_format, temp)
}

df_new_format = as.data.frame(df_new_format, row.names = FALSE)
colnames(df_new_format) = colnames(df)

введите здесь описание изображения

person viperdoraemon    schedule 07.11.2018
comment
Это работает как шарм, спасибо! Я только что заметил, что он продолжает создавать столько столбцов, сколько тем в df_new_format (которые не нужны и просто заполнены NA), но я могу легко избавиться от них. - person SamVimes; 08.11.2018
comment
Да, это для общих случаев, при условии, что есть дополнительные темы. Рад, что это помогает! - person viperdoraemon; 08.11.2018

Я немного отвык от такой обработки данных, но вот несколько предложений.

Сначала предположим, что ваши данные имеют следующую форму:

dtf <- structure(list(Participant = c("1", "2", "3", "4"),
Physics = c("Y", "Y", "N", "N"), Chemistry = c("Y", "N", "N",
"N"), Math = c("N", "Y", "Y", "Y"), Biology = c("N", "Y", "N",
"Y")), class = "data.frame", row.names = c(NA, -4L))

Затем мы можем переставить такие вещи

wh <- which(dtf == "Y", arr.ind=TRUE)
tapply(wh[,2], wh[,1], function(x) colnames(dtf)[x])
# $`1`
# [1] "Physics"   "Chemistry"

# $`2`
# [1] "Physics" "Math"    "Biology"

# $`3`
# [1] "Math"

# $`4`
# [1] "Math"    "Biology"

Or

dtf2 <- dtf[1]
dtf2$Subject <- apply(dtf, 1, function(r) {c(names(dtf)[r == "Y"])})
dtf2
#   Participant                Subject
# 1           1     Physics, Chemistry
# 2           2 Physics, Math, Biology
# 3           3                   Math
# 4           4          Math, Biology

Или используя melt() и dcast() из reshape2

library(reshape2)

dtf.m <- melt(dtf, 1)
dcast(dtf.m[dtf.m$value == "Y", 1:2], Participant ~ variable)
#   Participant Physics Chemistry Math Biology
# 1           1 Physics Chemistry <NA>    <NA>
# 2           2 Physics      <NA> Math Biology
# 3           3    <NA>      <NA> Math    <NA>
# 4           4    <NA>      <NA> Math Biology
person AkselA    schedule 07.11.2018
comment
Спасибо, что нашли время, чтобы помочь мне! Я обнаружил, что ответ kon_u работает немного лучше для моего варианта использования, но это также может быть связано с тем, что я недостаточно точно описал свои данные. - person SamVimes; 08.11.2018
comment
@SamVimes: Рад слышать. Да, точный репрезентативный пример входных данных и ожидаемый результат сводит догадки к минимуму. - person AkselA; 08.11.2018