通过ID(不是行号)和列名来识别数据帧中NA值的位置

时间:2018-06-15 03:16:24

标签: r dataframe 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

我想看看哪些ID号码没有回答哪些问题。以下代码非常接近我想要的输出但是按行号识别主题 - 我希望主题由ID号识别

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

现在输出显示行1,3,5没有回答至少一个问题,并且它标识了具有缺失值的列。我希望它向我展示同样的东西,但ID号为12,14,16。如果你可以在输出中输入列名(例如Q1,Q2,Q3)而不是列号,那将是一个额外的好处。

7 个答案:

答案 0 :(得分:4)

我们可以使用names获取行NAapply并将其设置为逗号分隔字符串,并将其附加到新数据框中{{1} }}

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

答案 1 :(得分:1)

如果您希望避免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

答案 2 :(得分:1)

您可以使用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

答案 3 :(得分:1)

在基地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

答案 4 :(得分:0)

如何使用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

输出: X:

  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

答案 5 :(得分:0)

我的尝试并不比任何已经提供的尝试好,但这是一个有趣的问题,所以我的这里。因为为什么不呢?:

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

答案 6 :(得分:0)

大部分答案来自你的问题:

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>