【问题标题】:Calculate a conditional sum with NAs using tidyverse?使用 tidyverse 计算带有 NA 的条件和?
【发布时间】:2021-05-19 15:31:31
【问题描述】:

我正在用 dplyr 计算总和,但遇到了这个问题:

library(dplyr)

toto <- data.frame(
  classe = c("CP","CP2","CP2","CP2"),
  in_flores = c(1,0,1,1),
  effectif = c(10,50,20,30),
  effectif2 = c(10,50,14,NA)
)

toto %>% 
  group_by(classe) %>% 
  summarise(
    eff = if_else(in_flores>=1,effectif,0) %>% sum(na.rm = T),
    effeff2 = if_else(in_flores>=1,effectif+effectif2,0) %>% sum(na.rm = T)
  )

结果:

我希望 effeff2 得到 64 而不是 34... 如何处理缺失值? 非常感谢提前

【问题讨论】:

  • 使用您的代码,您需要重新定义+,因为在 R 的算术版本中 30+NA 是 NA。

标签: r dplyr tidyverse


【解决方案1】:

rowSums 函数应返回一个可用于您的if_else 操作的向量。它确实有一个na.rm 参数:

> rowSums(toto[3:4], na.rm=TRUE)
[1]  20 100  34  30

所以在某种意义上它确实以所需的方式重新定义了+ 操作。即使在 tidyverse 重新定义的语法中,你仍然不能在这个表达式中使用不带引号的列名:

if_else(in_flores>=1,
    rowSums(effectif,effectif2, na.rm=TRUE),0)  # nope ... error

但是如果你cbind他们做一个单一的对象,那么rowSums很高兴:

toto %>% 
    group_by(classe) %>% 
    summarise(
      eff = if_else(in_flores>=1,effectif,0) %>% sum(na.rm = T),
      effeff2 = if_else(in_flores>=1, 
                   rowSums(cbind(effectif,effectif2), na.rm=TRUE),
                   0) %>% sum(na.rm = T))

# A tibble: 2 x 3
  classe   eff effeff2
  <chr>  <dbl>   <dbl>
1 CP        10      20
2 CP2       50      64

【讨论】:

    【解决方案2】:

    na.rm = TRUE 指令删除包含NA 值的行,因此总和不考虑最后一行,因为effectif + effectif2 = NA。一个候选解决方案是将 NA 值替换为 0,前提是它与您要解决的问题的上下文一致。

    toto %>% 
      mutate(effectif2 = if_else(is.na(effectif2), 0, effectif2)) %>%
      group_by(classe) %>% 
      summarise(
        eff = if_else(in_flores>=1,effectif,0) %>% sum(na.rm = T),
        effeff2 = if_else(in_flores>=1,effectif+effectif2,0) %>% sum(na.rm = T)
      )
    

    【讨论】:

      【解决方案3】:

      如果以这种方式重写,也许很容易看出原因:

      # first: the if statement would be better be out of the summarise command:
      # second: create a new column for effectif+effectif2
      toto %>% 
        filter(in_flores != 0) %>% 
        group_by(classe) %>% 
        mutate(x = effectif+effectif2)
      
      #  classe in_flores effectif effectif2     x
      #   <chr>      <dbl>    <dbl>     <dbl> <dbl>
      # 1 CP             1       10        10    20
      # 2 CP2            1       20        14    34
      # 3 CP2            1       30        NA    NA
      
      # the code bellow do the same but it seems easy to me to understand the result:
      toto %>% 
        filter(in_flores != 0) %>% 
        group_by(classe) %>% 
        mutate(x = effectif+effectif2) %>% 
        summarise(
          eff = sum(effectif),
          effeff2 = sum(x, na.rm = T). # x is only 34 for CP2, see table above
        )
      
      

      【讨论】:

      • 感谢您的解释!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-11
      • 2020-06-17
      • 2018-10-10
      • 2011-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多