вернуть несколько (несколько столбцов в один столбец)

#r #dataframe

#r #фрейм данных

Вопрос:

У меня есть набор данных с ответами из опроса из 17 вопросов (10 вопросов — это 5 или 7 вопросов по 7-балльной шкале), и теперь формат данных дает мне 5 или 7 столбцов для каждого ответа на вопрос (True или False), что похоже на одноразовый стиль кодирования. И я хочу преобразовать эти столбцы обратно в 15 отдельных столбцов.

Чтобы быть более конкретным, имеющиеся у меня данные выглядят следующим образом

         Q1.1  Q1.2  Q1.3 Q1.4 Q1.5 Q1.6 Q1.7 .... Q17.1 Q17.2 ... Q17.5 
row1     T     F      F    F    F    F    F         F     T          F
  ...               ...
row2000  F     T      F    F    F    F    F         T     F          F
  

желаемый формат, который я хочу иметь, это

         Q1  Q2 .... Q17
row1    1    4       2  # with number indicating the value that the column is True
           ....
row2000 2    3       1  #(e.g., if Q2.4 is T, then for Q2, it is 4).
  

Ответ №1:

Базовый подход R с использованием split.default и max.col . С помощью split.default мы можем разделить столбцы на основе шаблона в их названии, чтобы каждый вопрос был разделен на список. Предполагая, что каждый вопрос будет иметь только одно TRUE значение, мы можем использовать max.col для нахождения TRUE индекса.

 sapply(split.default(df, sub("\..*", "", names(df))), max.col)

#     Q1 Q2
#[1,]  1  2
#[2,]  6  5
  

данные

 df <-read.table(text = "Q1.1 Q1.2 Q1.3 Q1.4 Q1.5 Q1.6 Q1.7 Q2.1 Q2.2  Q2.3 Q2.4 Q2.5
T     F      F    F    F    F    F         F     T          F F F
F     F      F    F    F    T    F         F     F          F F T", header = T)
  

Предполагается, что класс ваших данных «логический». Если «T» / «F» хранятся в символьном формате (как в ответе @Maurits), нам нужно сначала преобразовать их в логический.

Используя данные от @Maurits Evers

 df[] <- lapply(df, as.logical)
sapply(split.default(df, sub("\..*", "", names(df))), max.col)

#     Q1 Q17
#[1,]  1   2
#[2,]  2   1
  

Ответ №2:

Вот tidyverse вариант:

 library(tidyverse)
df %>%
    rownames_to_column("row") %>%
    gather(k, v, -row) %>%
    separate(k, c("question", "part"), sep = "\.") %>%
    filter(v == "T") %>%
    group_by(row) %>%
    select(-v) %>%
    spread(question, part)
## A tibble: 2 x 3
## Groups:   row [2]
#  row     Q1    Q17
#  <chr>   <chr> <chr>
#1 row1    1     2
#2 row2000 2     1
  

Я предполагаю, что ваши исходные данные содержат записи "T" / "F" as character . Если они на самом деле являются TRUE / FALSE , вам следует изменить filter(v == "T") на filter(v == TRUE) .


Пример данных

 df <- read.table(text =
    "Q1.1  Q1.2  Q1.3 Q1.4 Q1.5 Q1.6 Q1.7  Q17.1 Q17.2  Q17.5
row1     T     F      F    F    F    F    F         F     T          F
row2000  F     T      F    F    F    F    F         T     F          F", colClasses = "character")