2016-11-30 5 views
13

Когда max(x, na.rm = TRUE) вызывается без значений NA, он возвращает -Inf с предупреждением. Однако, в некоторых случаях summarise функция dplyr не возвращает предупреждение:подведение итогов не возвращает предупреждения от max, если значения не-NA

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 

Хотя я использую «Dev» версии dplyr, я также проверил его на доступной версии в CRAN, с теми же результатами.

+1

Похож на ошибку в 'group_by' для меня как' summaryise' дает ожидаемый результат без него. Кроме того, 'mutate' не возвращает предупреждение ни для вашего второго случая. –

+1

Кроме того, во втором случае вы получаете 'NA' вместо' -Inf', что означает, что проблема накапливается где-то перед предупреждением –

+0

Хороший улов. 'df2%>% group_by (a)%>% summary (length (na.omit (b)))' похоже, подтверждает, что группа 'b' передает вектор нулевой длины в' max() ' – smci

ответ

2

Для max() доступна гибридная версия, которая работает намного быстрее для сгруппированных кадров данных, потому что вся оценка может быть выполнена на C++ без обратного вызова R для каждой группы. В dplyr 0.5.0, гибридная версия срабатывает, когда все из следующих условий:

  • Первый аргумент ссылается на переменную, которая существует в кадре данных
  • Второй аргумент является постоянной logical

См. hybrid vignette для более подробной информации.

Гибридная версия max() в некоторых аспектах отличается от реализации R:

  • Никаких предупреждений не поднимаются для пустого вектора, молча возвращался -Inf
    • Я думаю, что это было всегда; мы могли бы также добавить предупреждение, но я подозреваю, что other users won't be happy about this
  • все- NA вектор будет возвращать NA даже с na.rm = TRUE

В вашем примере c(NA, NA) является вектором logical, поэтому dplyr возвращается к «регулярной» оценке с помощью одного обратного вызова R для fo 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 
+0

Полезно знать. Как пользователь может указать из командной строки R, которую 'max()' отправляет 'dplyr', не глядя на источник C++? – smci

+1

@smci: В последнее время существуют внутренние функции 'verify_hybrid()' и 'verify_not_hybrid()', которые допускают такой тип теста, но они еще не документированы и могут быть изменены. См. Https://github.com/hadley/dplyr/pull/2306. – krlmlr

6

Ниже приведена частичная диагностика; доказывает, что каким-то образом dplyr испортил ссылку на имя функции max(). Кроме того, dplyr обычно использует SE (стандартная оценка) в своих аргументах: lazyeval::lazydots(..., .follow_symbols=F)), поэтому, возможно, это влияет на обещание, хотя я не вижу, как:

A) group_by() не является виновником. df2 %>% group_by(a) %>% summarise(length(na.omit(b))) делает доказать, что группа б проходит вектор с одним элементом НС в 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 SE (Standard Evaluation) на своих аргументах: lazyeval::lazydots(..., .follow_symbols=F)), но я не могу видеть, как это может вызвать это.

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 - последний Hadley

+2

Хороший детектив Работа. Я подозреваю, что внутренне max переопределяется функцией [C++] (https://github.com/hadley/dplyr/blob/80bfdc7b932b910af23d368996a4bd33a4393bcf/inst/include/dplyr/Result/Max.h) – nograpes

+0

Лично я подозреваю 'lazyeval :: lazydots (..., .follow_symbols = F))', но я не вижу, как это будет иметь значение в этом случае. – smci