【问题标题】:With min() in R return NA instead of Inf在 R 中使用 min() 返回 NA 而不是 Inf
【发布时间】:2018-06-28 19:18:34
【问题描述】:

请考虑以下几点:

我最近“发现”了很棒的 plyrdplyr 软件包,并使用它们来分析数据框中可用的患者数据。这样的数据框可能如下所示:

df <- data.frame(id = c(1, 1, 1, 2, 2), # patient ID
                 diag = c(rep("dia1", 3), rep("dia2", 2)), # diagnosis
                 age = c(7.8, NA, 7.9, NA, NA)) # patient age

我想用中位数和平均值总结所有患者的最小患者年龄。我做了以下事情:

min.age <- df %>% 
  group_by(id) %>% 
  summarise(min.age = min(age, na.rm = T))

由于数据框中有NAs,我收到警告:

`Warning message: In min(age, na.rm = T) :
no non-missing arguments to min; returning Inf`

对于Inf,我无法以有意义的方式调用summary(df$min.age)

使用pmin() 而不是min 返回错误消息:

Error in summarise_impl(.data, dots) :
 Column 'in.age' must be length 1 (a summary value), not 3

我能做些什么来避免任何Inf 而是获得NA 以便我可以进一步进行: summary(df$min.age)?

非常感谢!

【问题讨论】:

    标签: r dplyr plyr min


    【解决方案1】:

    这个看起来很有趣,因为它避免了警告:

    myMin <- function(vec) {
          ifelse(length(vec[!is.na(vec)]) == 0, NA_real_, min(vec, na.rm = TRUE))
        }
    

    【讨论】:

      【解决方案2】:

      更简单的解决方案是 hablar 包中的 s 函数。它在以 min/max 评估之前用 NA 替换空向量。 @awchisholm 的代码块可能是:

      library(hablar)
      
      min.age <- df %>% 
        group_by(id) %>% 
        summarise(min.age = min(s(age)))
      

      免责声明自从我编写了这个包以来,我对这个解决方案有偏见。

      【讨论】:

        【解决方案3】:

        问题已得到解答,但需要指出的是,如果所讨论的列是日期或日期时间,那么它在汇总表中仍会显示为 NA,但实际上并非如此。这令人倍感困惑!考虑:

        library(dplyr)
        #> 
        #> Attaching package: 'dplyr'
        #> The following objects are masked from 'package:stats':
        #> 
        #>     filter, lag
        #> The following objects are masked from 'package:base':
        #> 
        #>     intersect, setdiff, setequal, union
        df <- data.frame(date = as.Date(c("2013-01-01", "2013-05-23", "", "2017-04-15", "", "")),
                         int = c(1L, 2L, NA, 4L, NA, NA),
                         group = rep(LETTERS[1:3],2))
        
        s1 <- df %>% group_by(group) %>% summarise(min_date = min(date), min_int = min(int)) %>% mutate(min_date_missing = is.na(min_date), min_int_missing = is.na(min_int))
        #> Warning: package 'bindrcpp' was built under R version 3.4.4
        s2 <- df %>% group_by(group) %>% summarise(min_date = min(date, na.rm = TRUE), min_int = min(int, na.rm = TRUE)) %>% mutate(min_date_missing = is.na(min_date), min_int_missing = is.na(min_int))
        
        df
        #>         date int group
        #> 1 2013-01-01   1     A
        #> 2 2013-05-23   2     B
        #> 3       <NA>  NA     C
        #> 4 2017-04-15   4     A
        #> 5       <NA>  NA     B
        #> 6       <NA>  NA     C
        s1
        #> # A tibble: 3 x 5
        #>   group min_date   min_int min_date_missing min_int_missing
        #>   <fct> <date>       <dbl> <lgl>            <lgl>          
        #> 1 A     2013-01-01      1. FALSE            FALSE          
        #> 2 B     NA             NA  TRUE             TRUE           
        #> 3 C     NA             NA  TRUE             TRUE
        s2
        #> # A tibble: 3 x 5
        #>   group min_date   min_int min_date_missing min_int_missing
        #>   <fct> <date>       <dbl> <lgl>            <lgl>          
        #> 1 A     2013-01-01      1. FALSE            FALSE          
        #> 2 B     2013-05-23      2. FALSE            FALSE          
        #> 3 C     NA            Inf  FALSE            FALSE
        
        s1[[3,2]]
        #> [1] NA
        s2[[3,2]]
        #> [1] NA
        
        is.na(s1[[3,2]])
        #> [1] TRUE
        is.na(s2[[3,2]])
        #> [1] FALSE
        
        s1[[3,2]] == Inf
        #> [1] NA
        s2[[3,2]] == Inf
        #> [1] TRUE
        
        s1[[3,3]]
        #> [1] NA
        s2[[3,3]]
        #> [1] Inf
        
        is.na(s1[[3,3]])
        #> [1] TRUE
        is.na(s2[[3,3]])
        #> [1] FALSE
        
        s1[[3,2]] == Inf
        #> [1] NA
        s2[[3,2]] == Inf
        #> [1] TRUE
        
        sessionInfo()
        #> R version 3.4.3 (2017-11-30)
        #> Platform: x86_64-apple-darwin15.6.0 (64-bit)
        #> Running under: macOS High Sierra 10.13.5
        #> 
        #> Matrix products: default
        #> BLAS: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRblas.0.dylib
        #> LAPACK: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRlapack.dylib
        #> 
        #> locale:
        #> [1] en_AU.UTF-8/en_AU.UTF-8/en_AU.UTF-8/C/en_AU.UTF-8/en_AU.UTF-8
        #> 
        #> attached base packages:
        #> [1] stats     graphics  grDevices utils     datasets  methods   base     
        #> 
        #> other attached packages:
        #> [1] bindrcpp_0.2.2 dplyr_0.7.4   
        #> 
        #> loaded via a namespace (and not attached):
        #>  [1] Rcpp_0.12.17     utf8_1.1.3       crayon_1.3.4     digest_0.6.15   
        #>  [5] rprojroot_1.3-2  assertthat_0.2.0 R6_2.2.2         backports_1.1.2 
        #>  [9] magrittr_1.5     evaluate_0.10.1  pillar_1.2.1     cli_1.0.0       
        #> [13] rlang_0.2.0.9001 stringi_1.1.7    rmarkdown_1.9    tools_3.4.3     
        #> [17] stringr_1.3.0    glue_1.2.0       yaml_2.1.18      compiler_3.4.3  
        #> [21] pkgconfig_2.0.1  htmltools_0.3.6  bindr_0.1.1      knitr_1.20      
        #> [25] tibble_1.4.2
        

        reprex package (v0.2.0.9000) 于 2018 年 6 月 27 日创建。

        【讨论】:

          【解决方案4】:

          我更喜欢选择我自己的无效值。说200 将是Age 的无效值。

          现在可以稍微扭曲一下min函数的使用。例如min(age, 200, na.rm = TRUE) 。这可确保在缺少所有值时年龄显示为 200 而不是 +Infdf 上的结果将是:

          min.age <- df %>% 
            group_by(id) %>% 
            summarise(min.age = min(age, 200, na.rm = T))
          
          > min.age
          # A tibble: 2 x 2
          #     id min.age
          #  <dbl>   <dbl>
          #1  1.00    7.80
          #2  2.00  200 
          

          现在,由程序员决定如何使用/替换这个无效值。

          【讨论】:

            【解决方案5】:

            您的代码执行以下操作:

            1. 将数据框按id 分组
            2. 将每个组中的min 函数应用于age 变量,并启用na.rm=TRUE 选项。

            所以对于1 中的id,你得到min(c(7.8, NA, 7.9), na.rm=TRUE),这与min(c(7.8, 7.9)) 相同,只有7.8。

            然后,对于2 中的id,您将得到min(c(NA, NA), na.rm=TRUE),这与min(c()) 相同。

            现在,一组空数字的最小值是多少? “最小值”的定义是“小于集合中所有值的值”,并且必须满足当 B 是 A 的子集时 min(A)

            在这种情况下,您无法避免收到Inf。但是您可以将另一个mutate 添加到您的链中,以将任何Inf 更改为您喜欢的任何内容,例如NA


            df %>% group_by(id) %>% summarize(min_age = min(age, na.rm = TRUE)) %>% 
                mutate(min_age = ifelse(is.infinite(min_age), NA, min_age))
            

            【讨论】:

              【解决方案6】:
              (min.age <- df %>% 
                  group_by(id) %>% 
                  summarise(min.age = ifelse(all(is.na(age)),NA,min(age, na.rm = T))))
              # A tibble: 2 x 2
                   id min.age
                <dbl>   <dbl>
              1     1     7.8
              2     2      NA
              

              【讨论】:

                【解决方案7】:

                您可以使用is.infinite() 检测无穷大,并使用ifelse 有条件地将它们设置为NA

                #using your df and the dplyr package
                min.age <- 
                  df %>% 
                  group_by(id) %>% 
                  summarise(min.age = min(age, na.rm = T)) %>%
                  mutate(min.age = ifelse(is.infinite(min.age), NA, min.age))
                

                【讨论】:

                  猜你喜欢
                  • 2013-09-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-08-21
                  • 1970-01-01
                  • 2018-02-05
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多