当没有非NA值时,汇总不会从最大值返回警告

时间:2016-11-30 18:50:36

标签: r dplyr warnings

如果调用max(x, na.rm = TRUE)时没有非NA值,则会返回-Inf并发出警告。但是,在某些情况下,summarise中的dplyr函数不会返回警告:

library(magrittr)
library(dplyr)

df1 <- data.frame(a = c("a","b"), b = c(NA,NA))
df1 %>% group_by(a) %>% summarise(x = max(b, na.rm = TRUE))
# Three warnings, as expected.

df2 <- data.frame(a = c("a","b"), b = c(1,NA))
df2 %>% group_by(a) %>% summarise(x = max(b, na.rm = TRUE))
# No warning. Unexpected.

有趣的是,如果我重命名该功能,我会按预期收到警告:

# Pointer to same function.
stat <- max

df1 <- data.frame(a = c("a","b"), b = c(NA,NA))
df1 %>% group_by(a) %>% summarise(x = stat(b, na.rm = TRUE))
# Three warnings, as expected.

df2 <- data.frame(a = c("a","b"), b = c(1,NA))
df2 %>% group_by(a) %>% summarise(x = stat(b, na.rm = TRUE))
# Single warning, as expected.

实际上,我认为它应该是两个警告而不是三个,因为summarise只有两个组。但我不确定内部警告系统是如何工作的,所以也许三个警告是预期的。

我的问题是:为什么summarise在特定情况下不输出警告,如果这是预期的,为什么函数的简单重命名会改变这种行为?

我的sessionInfo()

R version 3.3.2 (2016-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 14.04.5 LTS

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C
 [9] LC_ADDRESS=C               LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

other attached packages:
[1] dplyr_0.5.0.9000 magrittr_1.5

loaded via a namespace (and not attached):
[1] lazyeval_0.2.0.9000 R6_2.2.0            assertthat_0.1
[4] tools_3.3.2         DBI_0.5-1           tibble_1.2
[7] Rcpp_0.12.8

虽然我使用dplyr的“dev”版本,但我也在CRAN中提供的版本上测试了它,结果相同。

2 个答案:

答案 0 :(得分:6)

以下是部分诊断;证明dplyr以某种方式弄乱了对函数名max()的引用。此外,dplyr通常在其args:lazyeval::lazydots(..., .follow_symbols=F))上使用SE(标准评估),所以这可能会影响承诺,尽管我看不出如何:

A)group_by()不是罪魁祸首。 df2 %>% group_by(a) %>% summarise(length(na.omit(b))) 确实证明组b正在将带有一个NA元素的向量传递给max()

B)当我们通过其限定名称base::max引用最大值时,我们会看到警告:

> df2 %>% group_by(a) %>% summarise(x = base::max(b, na.rm = TRUE))
       a     x
1      a     1
2      b  -Inf
Warning message:
In base::max(NA_real_, na.rm = TRUE) :
  no non-missing arguments to max; returning -Inf

我检查过没有dplyr:::max(),所以它不是命名空间阴影。

B2)同样,do.call(max, ...)会按预期发出警告。

> df2 %>% group_by(a) %>% summarise(x = do.call(max, list(b, na.rm = TRUE)))
       a     x
1      a     1
2      b  -Inf
Warning message:
In .Primitive("max")(NA_real_, na.rm = TRUE) :
  no non-missing arguments to max; returning -Inf

C)另外,请注意dplyr通常在其args:lazyeval::lazydots(..., .follow_symbols=F))上使用SE(标准评估),但我看不出这会导致这种情况。

C2)我尝试用:

重新创建group_by的内部结果
grouped_df(as.numeric(NA), list()), na.rm=T)

并用以下内容重新创建承诺:

p <- lazyeval::lazy_dots( max, list( grouped_df(as.numeric(NA), list()), na.rm=T )  , .follow_symbols=F)

我无法用.follow_symbols=T

来制定这一点

我对标准评估几乎一无所知,所以在http://adv-r.had.co.nz/Expressions.html#metaprogramming

上有所了解

使用的版本:dplyr 0.5.0; lazyeval 0.1.10;虽然lazyeval 0.2.0是哈德利最新的

答案 1 :(得分:2)

对于max(),可以使用混合版本,对于分组数据帧,它的工作速度要快得多,因为整个评估可以在C ++中执行,而不需要对每个组进行R回调。在dplyr 0.5.0中,当满足以下所有条件时,将触发混合版本:

  • 第一个参数是指数据框中存在的变量
  • 第二个参数是logical常数

有关详细信息,请参阅hybrid vignette

max()的混合版本在某些方面与R实现不同:

  • 没有针对空向量引发警告,以静默方式返回-Inf
  • 全部 - NA向量即使NA也会返回na.rm = TRUE

在您的示例中,c(NA, NA)logical的向量,因此dplyr会回退到“常规”评估,每个组都有一个R回调。如果您需要原始行为,只需使用包装器或别名;混合评估员将回归常规评估:

max_ <- max
data_frame(a = NA_real_) %>% summarise(a = max_(a, na.rm = TRUE))
## # A tibble: 1 × 1
##       a
##   <dbl>
## 1  -Inf
## Warning message:
## In max_(a, na.rm = TRUE) : no non-missing arguments to max; returning -Inf