Имя столбца последней строки в строке, отличной от NA; используя решение tidyverse?

Краткое описание набора данных. У меня есть данные опроса, созданные с помощью Qualtrics, которые я импортировал в R в виде фрагмента. Каждый столбец соответствует вопросу опроса, и я сохранил исходный порядок столбцов (чтобы соответствовать порядку вопросов в опросе).

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

Постановка проблемы в R: Я хочу сгенерировать (используя tidyverse):

  • 1) Новый столбец (lastq), в котором для каждой строки (т. Е. Для каждого участника) указано имя последнего столбца, не относящегося к NA (т.е. имя последнего вопроса, который они ответили).
  • 2) Второй новый столбец, в котором указан номер столбца в lastq

Пример фрейма данных df

df <- tibble(
  year = c(2015, 2015, 2016, 2016),
  grade = c(1, NA, 1, NA),
  height = c("short", "tall", NA, NA),
  gender = c(NA, "m", NA, "f")
 )

Исходный формат df

  # A tibble: 4 x 4
   year grade height gender
  <dbl> <dbl>  <chr>  <chr>
1  2015     1  short   <NA>
2  2015    NA   tall      m
3  2016     1   <NA>   <NA>
4  2016    NA   <NA>      f

Желаемый конечный df

   # A tibble: 4 x 6
   year grade height gender  lastq lastqnum
  <dbl> <dbl>  <chr>  <chr>  <chr>    <dbl>
1  2015     1  short   <NA> height        3
2  2015    NA   tall      m gender        4
3  2016     1   <NA>   <NA>  grade        2
4  2016    NA   <NA>      f gender        4

Есть и другие связанные вопросы, но я не могу найти ответов, ориентированных на извлечение имен столбцов (по сравнению с сами значения) на основе набора смешанных классов переменных (по сравнению с all numeric), используя решение tidyverse

То, что я пытался - я знаю, что мне здесь кое-что не хватает ...:

  • ds %>% map(which(!is.na(.)))
  • ds %>% map(tail(!is.na(.), 2))
  • ds %>% rowwise() %>% mutate(last = which(!is.na(ds)))

?


Спасибо большое за вашу помощь!


person Jen W    schedule 25.03.2018    source источник


Ответы (1)


Напишите функцию, которая решает проблему, следуя предложению Джеймса, но немного более надежную (обрабатывает случай, когда все ответы - NA)

f0 = function(df) {
    idx = ifelse(is.na(df), 0L, col(df))
    apply(idx, 1, max)
}

L делает 0 целым, а не числовым. Для повышения скорости (при большом количестве строк) используйте пакет matrixStats

f1 = function(df) {
    idx = ifelse(is.na(df), 0L, col(df))
    matrixStats::rowMaxs(idx, na.rm=TRUE)
}

Следуйте предложению Маркуса, чтобы использовать это в контексте dplyr

mutate(df, lastqnum = f1(df), lastq = c(NA, names(df))[lastqnum + 1])
df %>% mutate(lastqnum = f1(.), lastq = c(NA, names(.))[lastqnum + 1])

или просто сделай это

lastqnum = f1(df)
cbind(df, lastq=c(NA, names(df))[lastqnum + 1], lastqnum)

Отредактировано после принятия. Я думаю, что аккуратный подход будет первым, чтобы привести данные в порядок в развернутой форме.

df1 = cbind(gather(df), id = as.vector(row(df)), event = as.vector(col(df)))

а затем сгруппировать и обобщить

group_by(df1, id) %>%
    summarize(lastq = tail(event[!is.na(value)], 1), lastqname = key[lastq])

Это не относится к случаю, когда нет ответов.

person Martin Morgan    schedule 25.03.2018
comment
Я не уверен, что это следует за idomatic tidyverse, учитывая использование ifelse вместо if_else, cbind вместо bind_cols и т. Д. - person rsmith54; 14.05.2020