某些列的行式 NA 计数 - 按 id 分组

row wise NA count across some columns - grouped by id

我有一个数据框 df 如下:

输入

id  na_count    task q1   q2   q3   q4  q5
7   3           a    1    NA   NA   2   NA
7   1           b    1    0    0    NA  0
7   3           c    NA   NA   1    NA  1
9   0           a    1    1    0    2   1
9   1           b    1    0    0    1   NA
9   0           c    1    1    0    1   0
9   1           d    1    0    NA   1   1
3   3           a    1    NA   NA   1   NA
3   1           b    1    1    NA   2   1
1   2           b    1    1    NA   1   NA
1   2           c    1    1    NA   1   NA
1   3           d    NA   NA   1    NA  1
2   4           a    1    NA   NA   NA  NA
2   2           b    1    2    NA   1   NA
2   1           c    1    1    2    NA  2
2   1           d    NA   1    3    3   3
2   0           e    2    2    3    3   4
  1. 我有兴趣添加一个二进制列或标志 evidence,这是通过查看每个 id 的数据然后确定 id 是否满足非 NA 值的最小阈值。

  2. 例如,我将最小非 NA 阈值设置为 10。因此,如果对于任何 id 至少有 10 个非 NA 值(多行),则我要设置证据为Yes,否则我要设置证据为No

  3. (Prefered) 如果可能的话,我想使用 na_count 列中非 NA 值的计数,而不是实际计算 NA在列 q1:q5

输出

对于阈值为 10 非 NA 的示例,我的输出如下:

id  na_count    task q1   q2   q3   q4  q5  evidence
7   3           a    1    NA   NA   2   NA  no
7   1           b    1    0    0    NA  0   no
7   3           c    NA   NA   1    NA  1   no
9   0           a    1    1    0    2   1   yes
9   1           b    1    0    0    1   NA  yes
9   0           c    1    1    0    1   0   yes
9   1           d    1    0    NA   1   1   yes
3   3           a    1    NA   NA   1   NA  no
3   1           b    1    1    NA   2   1   no
1   2           b    1    1    NA   1   NA  no
1   2           c    1    1    NA   1   NA  no
1   3           d    NA   NA   1    NA  1   no
2   4           a    1    NA   NA   NA  NA  yes
2   2           b    1    2    NA   1   NA  yes
2   1           c    1    1    2    NA  2   yes
2   1           d    NA   1    3    3   3   yes
2   0           e    2    2    3    3   4   yes

部分解决方案

我尝试了以下方法,但它只计算行数,而不是该 ID 的多行的非 NA 值。

library(dplyr)
df = df %>%
       group_by(id) %>%
           mutate(rows = n())

相关帖子

以下帖子是相关的,但没有解决我的问题 and

dput()

为了编码,我也在复制数据帧的dput()

# dput(df)

structure(list(
id = c(7L, 7L, 7L, 9L, 9L, 9L, 9L, 3L, 3L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L), 
na_count = c(3L, 1L, 3L, 0L, 1L, 0L, 1L, 3L, 1L, 2L, 2L, 3L, 4L, 2L, 1L, 1L, 0L), 
task = c("a", "b", "c", "a", "b", "c", "d", "a", "b", "b", "c", "d", "a", "b", "c", "d", "e"), 
q1 = c(1L, 1L, NA, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, NA, 1L, 1L, 1L, NA, 2L), 
q2 = c(NA, 0L, NA, 1L, 0L, 1L, 0L, NA, 1L, 1L, 1L, NA, NA, 2L, 1L, 1L, 2L), 
q3 = c(NA, 0L, 1L, 0L, 0L, 0L, NA, NA, NA, NA, NA, 1L, NA, NA, 2L, 3L, 3L), 
q4 = c(2L, NA, NA, 2L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, NA, NA, 1L, NA, 3L, 3L), 
q5 = c(NA, 0L, 1L, 1L, NA, 0L, 1L, NA, 1L, NA, NA, 1L, NA, NA, 2L, 3L, 4L)), 
row.names = c(NA, -17L), class = "data.frame")

如有任何帮助,我们将不胜感激,谢谢!

使用 tidyverse 包的解决方案。我们可以定义一个辅助函数来计算非 NA 值,嵌套数据框,将函数应用于每个 id,然后取消嵌套数据框。

library(tidyverse)

count_non_na <- function(x, threshold = 10){
  x2 <- x %>%
    dplyr::select(starts_with("q")) %>%
    unlist()
  non_na <- sum(!is.na(x2)) >= threshold
  
  if (non_na){
    result <- "yes"
  } else {
    result <- "no"
  }
  
  return(result)
}

df2 <- df %>%
  group_by(id) %>%
  nest() %>%
  mutate(evidence = map_chr(data, count_non_na)) %>%
  unnest(cols = data) %>%
  ungroup()

df2
# # A tibble: 17 x 9
#       id na_count task     q1    q2    q3    q4    q5 evidence
#    <int>    <int> <chr> <int> <int> <int> <int> <int> <chr>   
#  1     7        3 a         1    NA    NA     2    NA no      
#  2     7        1 b         1     0     0    NA     0 no      
#  3     7        3 c        NA    NA     1    NA     1 no      
#  4     9        0 a         1     1     0     2     1 yes     
#  5     9        1 b         1     0     0     1    NA yes     
#  6     9        0 c         1     1     0     1     0 yes     
#  7     9        1 d         1     0    NA     1     1 yes     
#  8     3        3 a         1    NA    NA     1    NA no      
#  9     3        1 b         1     1    NA     2     1 no      
# 10     1        2 b         1     1    NA     1    NA no      
# 11     1        2 c         1     1    NA     1    NA no      
# 12     1        3 d        NA    NA     1    NA     1 no      
# 13     2        4 a         1    NA    NA    NA    NA yes     
# 14     2        2 b         1     2    NA     1    NA yes     
# 15     2        1 c         1     1     2    NA     2 yes     
# 16     2        1 d        NA     1     3     3     3 yes     
# 17     2        0 e         2     2     3     3     4 yes 

这是另一个想法。此解决方案只需要 dplyr 包,而不是整个 tidyverse 包。

df3 <- df %>%
  group_by(id) %>%
  summarize(across(starts_with("q"), .fns = ~sum(!is.na(.)))) %>%
  mutate(Total = rowSums(select(., starts_with("q")))) %>%
  mutate(evidence = ifelse(Total >= 10, "yes", "no")) %>%
  select(id, evidence) %>%
  right_join(df, by = "id") %>%
  relocate(evidence, .after = q5)

df3
# # A tibble: 17 x 9
#       id na_count task     q1    q2    q3    q4    q5 evidence
#    <int>    <int> <chr> <int> <int> <int> <int> <int> <chr>   
#  1     1        2 b         1     1    NA     1    NA no      
#  2     1        2 c         1     1    NA     1    NA no      
#  3     1        3 d        NA    NA     1    NA     1 no      
#  4     2        4 a         1    NA    NA    NA    NA yes     
#  5     2        2 b         1     2    NA     1    NA yes     
#  6     2        1 c         1     1     2    NA     2 yes     
#  7     2        1 d        NA     1     3     3     3 yes     
#  8     2        0 e         2     2     3     3     4 yes     
#  9     3        3 a         1    NA    NA     1    NA no      
# 10     3        1 b         1     1    NA     2     1 no      
# 11     7        3 a         1    NA    NA     2    NA no      
# 12     7        1 b         1     0     0    NA     0 no      
# 13     7        3 c        NA    NA     1    NA     1 no      
# 14     9        0 a         1     1     0     2     1 yes     
# 15     9        1 b         1     0     0     1    NA yes     
# 16     9        0 c         1     1     0     1     0 yes     
# 17     9        1 d         1     0    NA     1     1 yes
library(tidyverse)

threshold = 10

df %>% group_by(id) %>%
  mutate(evidence = ifelse(n()*5 - sum(na_count) >= threshold, "yes", "no"))

5 来自您拥有的列数,q1:q5。