【问题标题】:Custom sum function in dplyr returns inconsistent resultsdplyr 中的自定义 sum 函数返回不一致的结果
【发布时间】:2014-10-14 01:14:01
【问题描述】:

我创建了一个自定义求和函数,它会忽略 NAs,除非全部都是 NA。当我在dplyr 中使用它时,它会返回奇怪的结果,我不知道为什么。

require(dplyr)

dta <- data.frame(year=2007:2013, rrconf=c(79, NaN ,474,2792,1686,3313,3456), enrolled=c(NaN,NaN,458,1222,1155,1906,2184))

sum0 <- function(x, ...){
  # remove NAs unless all are NA
  if(is.na(mean(x, na.rm=TRUE))) return(NA)
  else(sum(x, ..., na.rm=TRUE))
} 

dta %>%
  group_by(year) %>%
  summarize(rrconf=sum0(rrconf), enrolled=sum0(enrolled))

给我

Source: local data frame [7 x 3]

  year rrconf enrolled
1 2007     79       NA
2 2008     NA       NA
3 2009    474     TRUE
4 2010   2792     TRUE
5 2011   1686     TRUE
6 2012   3313     TRUE
7 2013   3456     TRUE

在这种情况下,它只是对一个值求和,但在我更大的应用程序中,可能是对多个值求和。在as.integer() 中包装我的sum0 函数似乎可以解决它,但我无法告诉你原因。

这是解决此问题的正确方法吗?我有什么明显的遗漏吗?

> sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: i386-w64-mingw32/i386 (32-bit)

locale:
[1] LC_COLLATE=English_United Kingdom.1252  LC_CTYPE=English_United Kingdom.1252   
[3] LC_MONETARY=English_United Kingdom.1252 LC_NUMERIC=C                           
[5] LC_TIME=English_United Kingdom.1252    

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

other attached packages:
[1] dplyr_0.2

loaded via a namespace (and not attached):
[1] assertthat_0.1 magrittr_1.0.1 parallel_3.1.0 Rcpp_0.11.2    tools_3.1.0 

【问题讨论】:

  • 我不确定这是否是编写函数的最佳方式,但该行旨在测试是否所有值都是NAs。所以 sum0(c(NA,3,NA)) 返回 3,但 sum0(c(NA,NA,NA)) 返回 NA
  • sum(x, na.rm = ifelse(all(is.na(x)), FALSE, TRUE))工作?
  • meansum 在使用 na.rm=T 时的行为略有不同。如果都是NA,则mean返回NaN,而sum返回0。
  • @rawr 怎么样sum(x, na.rm = !all(is.na(x))
  • 令人困惑的是,如果我先运行dta$enrolled[1] &lt;- 10,我可以使代码工作,以确保处理的第一个值不是NaN。这对我来说似乎是一个错误,dplyr 假设变量类型。我还可以通过设置第一个值 NaN 来使任何列失败。

标签: r dplyr


【解决方案1】:

问题似乎在于dplyr 参考第一个返回的结果来确定列类型。如果你强制NA 值(默认为逻辑值)为NA_real_NA_integer_,那么你将被排序:

##Just to show what NA normally does first:
class(NA)
#[1] "logical"

sum0 <- function(x, ...){
  # remove NAs unless all are NA
  if(is.na(mean(x, na.rm=TRUE))) return(NA_real_)
  else(sum(x, ..., na.rm=TRUE))
} 

dta %>%
  group_by(year) %>%
  summarize(rrconf=sum0(rrconf), enrolled=sum0(enrolled))

#Source: local data frame [7 x 3]
# 
#  year rrconf enrolled
#1 2007     79       NA
#2 2008     NA       NA
#3 2009    474      458
#4 2010   2792     1222
#5 2011   1686     1155
#6 2012   3313     1906
#7 2013   3456     2184

【讨论】:

  • 谢谢@thelatemail,这很有意义。所以通常返回NA 的函数在“正确”class 中这样做?这就是为什么这个问题只发生在我的自定义函数中吗?例如,我注意到class(sum(NA))integer 而不是logical
  • @Tom - 是的,它与不同 R 对象类型的层次结构有关。这有点令人困惑,但也许这个问题会有所帮助:stackoverflow.com/questions/21763355/… 我认为这可能是 dplyr 特定的,尽管像 class(c(NA,1)) 这样的东西在基础 R 中得到了适当的处理。
  • 出于性能原因,dplyr 假设 mutate 结果是“类型稳定的” - 即第一个元素的类型是所有后续元素的类型。有一天我们或许可以放宽这一限制,但在那之前,请确保您的函数返回的结果类型一致。
  • @hadley - 如果它引用了第一个非 NA 值,它会变得更加健壮吗?不确定这对速度的影响,但我可以看到这个问题经常引起人们的注意。
  • @thelatemail 是的,有一些方法可以修复它,它们目前在待办事项列表中并不那么高。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 2016-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多