Определение местоположения значений NA в фрейме данных по идентификатору (не номеру строки) и имени столбца

У меня есть опрос, в котором некоторые участники не ответили на некоторые вопросы. Вот упрощенная версия моих данных

df <- data.frame(ID = c(12:16), Q1 = c("a","b","a","a",NA), 
      Q2 = c("a","a",NA,"b",NA), Q3 = c(NA,"a","a","a","b"))
df

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

table(data.frame(which(is.na(df), arr.ind=TRUE)))

прямо сейчас выходные данные показывают, что строки 1,3,5 не ответили хотя бы на один вопрос, и он идентифицирует столбец с отсутствующим значением. Я бы хотел, чтобы он показал мне то же самое, но с номерами 12,14,16. Было бы неплохо, если бы вы могли иметь имена столбцов (например, Q1, Q2, Q3) в выводе вместо номера столбца.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 642
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Мы можем получить столбец names, который является строкой NA, используя apply, превратить его в строку, разделенную запятыми, и прикрепить ее к новому фрейму данных вместе с его ID.

new_df <- data.frame(ID =df$ID, ques = apply(df, 1, function(x) 
               paste0(names(which(is.na(x))), collapse = ",")))

new_df

#  ID  ques
#1 12    Q3
#2 13      
#3 14    Q2
#4 15      
#5 16 Q1,Q2

Аналогичный эквивалент был бы

new_df <- data.frame(ID = df$ID, ques = apply(is.na(df), 1, function(x) 
             paste0(names(which(x)), collapse = ",")))

Если вы хотите избежать операций типа apply и продолжить с which(..., T), вы можете сделать что-то вроде следующего:

tmp <- data.frame(which(is.na(df[, 2:4]), T))
# change to character
tmp[, 2] <- paste0('Q', tmp[, 2])
# gather column numbers together for each row number
tmp_split <- split(tmp[, 2], tmp[, 1])

# preallocate new column in df
df$missing <- vector('list', 5)
df$missing[as.numeric(names(tmp_split))] <- tmp_split

Это производит

> df
  ID   Q1   Q2   Q3 missing
1 12    a    a <NA>      Q3
2 13    b    a    a    NULL
3 14    a <NA>    a      Q2
4 15    a    b    a    NULL
5 16 <NA> <NA>    b  Q1, Q2

Мне тоже очень нравится этот ответ. Я не буду использовать его для моего текущего набора данных, потому что у меня слишком много испытуемых, которые действительно ответили на все вопросы (а они меня сейчас не интересуют), но это определенно пригодится в будущем.

B.Kenobi 20.06.2018 04:37

Как это с tidyverse:

данные:

library(tidyverse)
df <- data.frame(ID = c(12:16), Q1 = c("a","b","a","a",NA), Q2 = c("a","a",NA,"b",NA), Q3 = c(NA,"a","a","a","b"))

код:

x <- df %>% filter(is.na(Q1) | is.na(Q2) | is.na(Q3)) # filter out NAs

y <- cbind(x %>% select(ID),
      x %>% select(Q1, Q2, Q3) %>% sapply(., function(x) ifelse(is.na(x), 1, 0))
) # in 1/0 format

выход: Икс:

  ID   Q1   Q2   Q3
1 12    a    a <NA>
2 14    a <NA>    a
3 16 <NA> <NA>    b

y:

  ID Q1 Q2 Q3
1 12  0  0  1
2 14  0  1  0
3 16  1  1  0

Вы можете конвертировать данные в длинный формат с помощью tidyr::gather. Фильтр для Answer недоступен. Наконец, вы можете суммировать свои данные с помощью toString как:

library(tidyverse)

df %>% gather(Question, Ans, -ID) %>%
  filter(is.na(Ans)) %>%
  group_by(ID) %>%
  summarise(NotAnswered = toString(Question))
# # A tibble: 3 x 2
#      ID NotAnswered
#   <int> <chr>     
# 1    12 Q3        
# 2    14 Q2        
# 3    16 Q1, Q2

Если OP хочет включить в результат все IDs, решение может быть таким:

df %>% gather(Question, Ans, -ID) %>%
  group_by(ID) %>%
  summarise(NoAnswered = toString(Question[is.na(Ans)])) %>%
  as.data.frame()

#   ID NoAnswered
# 1 12         Q3
# 2 13           
# 3 14         Q2
# 4 15           
# 5 16     Q1, Q2

Моя попытка не лучше всех уже предложенных, но это интересная проблема, так что вот моя. Почему бы и нет ?:

library( magrittr )

df$ques <- df %>%
    is.na() %>%
    apply( 1, function(x) {
        x %>%
            which() %>%
            names() %>%
            paste0( collapse = "," )
    } )

df

#   ID   Q1   Q2   Q3  ques
# 1 12    a    a <NA>    Q3
# 2 13    b    a    a      
# 3 14    a <NA>    a    Q2
# 4 15    a    b    a      
# 5 16 <NA> <NA>    b Q1,Q2
Ответ принят как подходящий

В базе R:

res <- df[!complete.cases(df),]
res[-1] <- as.numeric(is.na(res[-1]))
res
#    ID Q1 Q2 Q3
# 12 12  0  0  1
# 14 14  0  1  0
# 16 16  1  1  0

Спасибо, это именно то, что я хотел, и это достаточно просто, чтобы мне было легко понять.

B.Kenobi 20.06.2018 01:46

Большая часть ответа исходит из вашего вопроса:

df[which(is.na(df), arr.ind=TRUE)[,1],]
#     ID   Q1   Q2   Q3
# 5   16 <NA> <NA>    b
# 3   14    a <NA>    a
# 5.1 16 <NA> <NA>    b
# 1   12    a    a <NA>

Это в основном то, что я хотел, но меня смущает столбец 5.1 и почему он там

B.Kenobi 20.06.2018 01:37

Правильно, принятый ответ проще, поэтому я предлагаю его использовать. но причина дублирования строк в том, что which(..., arr.ind=TRUE) возвращает индексы строк и столбцов для каждого пропущенного значения. В строке 5 два NA, поэтому он продублирован. Вы можете обойти это с помощью df[unique(which(is.na(df), arr.ind=TRUE=[,1]),], но принятый ответ предлагает более простое решение.

lebatsnok 20.06.2018 13:58

Другие вопросы по теме