在 R return NA 中使用 min() 而不是 Inf
With min() in R return NA instead of Inf
请考虑以下几点:
我最近 'discovered' 很棒的 plyr
和 dplyr
包,并使用它们来分析数据框中我可用的患者数据。这样的数据框可能如下所示:
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)
?
非常感谢!
您可以使用 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))
(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
您的代码执行以下操作:
- 按
id
将数据框分成几组
- 将每个组中的
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())
相同。
现在,一组空数的最小值是多少? "minumum" 的定义是 "a value smaller than all values in the set",并且必须满足 属性 即 min(A) <= min(B) 只要 B 是 A 的子集。定义最小值的一种方法空集就是说它是 "infinity",这就是 R 处理这种情况的方式。
在这种情况下,您真的无法避免获得 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))
我更愿意选择我自己的无效值。假设 200
将是 Age
的无效值。
现在可以稍微扭曲 min
函数的使用。例如min(age, 200, na.rm = TRUE)
。这确保在缺少所有值时年龄显示为 200
而不是 +Inf
。 df
的结果将是:
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
现在,由程序员决定如何 use/replace 这个无效值。
问题已得到解答,但需要指出的是,如果有问题的列是日期或日期时间,那么它在摘要中仍将显示为 NA table,但是实际上不是。这是双重混乱!考虑:
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-06-27。
一个更简单的解决方案是 hablar 包中的 s 函数。它在 min/max 中计算之前用 NA 替换空向量。 @awchisholm 的代码块可能是:
library(hablar)
min.age <- df %>%
group_by(id) %>%
summarise(min.age = min(s(age)))
免责声明我对这个解决方案有偏见,因为我编写了这个包。
这个看起来很有趣,因为它避免了警告:
myMin <- function(vec) {
ifelse(length(vec[!is.na(vec)]) == 0, NA_real_, min(vec, na.rm = TRUE))
}
请考虑以下几点:
我最近 'discovered' 很棒的 plyr
和 dplyr
包,并使用它们来分析数据框中我可用的患者数据。这样的数据框可能如下所示:
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)
?
非常感谢!
您可以使用 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))
(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
您的代码执行以下操作:
- 按
id
将数据框分成几组
- 将每个组中的
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())
相同。
现在,一组空数的最小值是多少? "minumum" 的定义是 "a value smaller than all values in the set",并且必须满足 属性 即 min(A) <= min(B) 只要 B 是 A 的子集。定义最小值的一种方法空集就是说它是 "infinity",这就是 R 处理这种情况的方式。
在这种情况下,您真的无法避免获得 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))
我更愿意选择我自己的无效值。假设 200
将是 Age
的无效值。
现在可以稍微扭曲 min
函数的使用。例如min(age, 200, na.rm = TRUE)
。这确保在缺少所有值时年龄显示为 200
而不是 +Inf
。 df
的结果将是:
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
现在,由程序员决定如何 use/replace 这个无效值。
问题已得到解答,但需要指出的是,如果有问题的列是日期或日期时间,那么它在摘要中仍将显示为 NA table,但是实际上不是。这是双重混乱!考虑:
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-06-27。
一个更简单的解决方案是 hablar 包中的 s 函数。它在 min/max 中计算之前用 NA 替换空向量。 @awchisholm 的代码块可能是:
library(hablar)
min.age <- df %>%
group_by(id) %>%
summarise(min.age = min(s(age)))
免责声明我对这个解决方案有偏见,因为我编写了这个包。
这个看起来很有趣,因为它避免了警告:
myMin <- function(vec) {
ifelse(length(vec[!is.na(vec)]) == 0, NA_real_, min(vec, na.rm = TRUE))
}