为什么在使用data.table进行分组时,不能在lapply中使用FUN函数?

7

在使用data.table进行聚合时,我遇到了以下问题:当使用.SD并指定lapply的FUN参数时,必须显式地声明。这是意外行为还是我漏了什么?为什么我不能在lapply中显式声明FUN呢?以下是一个可重现的例子。

require(data.table)
dt <- as.data.table(iris)
dt$Sepal.Length[sample(1:nrow(dt), 10)] <- NA
dt[, lapply(.SD, function(x) sum(!is.na(x), na.rm=TRUE)), by = Species]
      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1:     setosa           47          50           50          50
2: versicolor           46          50           50          50
3:  virginica           47          50           50          50
dt[, lapply(.SD, FUN=function(x) sum(!is.na(x), na.rm=TRUE)), by = Species]
Error in ..FUN(FUN = Sepal.Length) : 
  unused argument(s) (FUN = Sepal.Length)

更新:

已报告为错误:#4839。(Arun的修复现在在v1.8.9中)

1个回答

8
我认为您没有漏掉任何内容。您可能需要在此处提交一个bug并链接这篇文章。非常好的发现!
这是因为当您在j中使用.SD时,使用lapply时,data.table尝试查找是否有可能优化由于函数调用而产生的开销的方法。然而,在这个过程中,它没有调用函数:
..FUN(Sepal.Length)

..FUN = function(x) sum(!is.na(x), na.rm=TRUE) 时,它变成:

..FUN(FUN = Sepal.Length)

由于该函数没有名为FUN的参数,因此会返回错误。您可以通过在函数调用中将x更改为FUN来验证此问题:

dt[, lapply(.SD, FUN=function(FUN) sum(!is.na(FUN), na.rm=TRUE)), by = Species]
#       Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1:     setosa           49          50           50          50
# 2: versicolor           44          50           50          50
# 3:  virginica           47          50           50          50

内部:通过查看[.data.table函数,解决此问题的一种方法是重新编写以下行:

txt <- as.list(jsub)[-1L]
# [[1]]
# .SD

# $FUN <~~~~ this name FUN gets caught up in building the expression later
# function(x) sum(!is.na(x), na.rm = TRUE)

使用:

txt <- as.list(jsub)[-1L]
names(txt)[2] <- ""
# [[1]]
# .SD

# [[2]]
# function(x) sum(!is.na(x), na.rm = TRUE)

CHECK 运行成功。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接