【问题标题】:row wise NA count across some columns - grouped by id跨某些列的逐行 NA 计数 - 按 id 分组
【发布时间】:2021-12-19 04:03:12
【问题描述】:

我有一个数据框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. (首选) 如果可能,我想使用列 na_count 中非 NA 值的计数,而不是实际计算列 q1:q5 上的 NA

输出

对于阈值为 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())

相关帖子

以下帖子相关但不解决我的问题How to make n() do not count NAs too in tidyverse?Taking a count() after group_by() for non-missing valuesCount number of non-NA values by group

输入()

为了编码,我也复制了dataframe的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")

对此的任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: r dplyr multiple-columns rows na


    【解决方案1】:

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

    【讨论】:

    • 感谢您发布解决方案。我将在我的主数据框上尝试一下。
    【解决方案2】:
    library(tidyverse)
    
    threshold = 10
    
    df %>% group_by(id) %>%
      mutate(evidence = ifelse(n()*5 - sum(na_count) >= threshold, "yes", "no"))
    

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

    【讨论】:

    • 这是一个非常简单的解决方案,让我在我的原始数据框上尝试一下,然后我会接受你的答案。
    • 另外,不确定您的最终目标,但如果您稍后要检查它们,将 evidence 编码为 TRUEFALSE 可能会更容易。
    • 是的,TrueFalse 绝对没问题。我只是想找到一种方法来区分什么时候有足够的证据,什么时候没有!
    • 如果你想要TRUEFALSE你可以去掉ifelse(),所以只需evidence = n()*5 - sum(na_count) &gt;= threshold
    猜你喜欢
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    • 2022-09-27
    • 2021-05-09
    • 2022-07-15
    相关资源
    最近更新 更多