为什么我需要在J`lapply`调用中将`get`包装在一个虚函数中?

时间:2013-08-05 17:58:17

标签: r data.table lapply

我希望通过grep按类或共同模式匹配等标准处理列。

我的第一次尝试不起作用:

require(data.table)
test.table <- data.table(a=1:10,ab=1:10,b=101:110)
##this does not work and hangs on my machine
test.table[,lapply(names(test.table)[grep("a",names(test.table))], get)]

Ricardo Saporta notes in an answer您可以使用此构造,但必须将get包装在虚函数中:

##this works
test.table[,lapply(names(test.table)[grep("a",names(test.table))], function(x) get(x))]

为什么需要匿名功能?

(首选/清洁方法是通过.SDcols:)

test.table[,.SD,.SDcols=grep("a",names(test.table))]
test.table[, grep("a", names(test.table), with = FALSE]

3 个答案:

答案 0 :(得分:3)

虽然@Ricardo是正确的,在包装器中包装依赖于方法分派的原语或函数更安全,但我们可以通过为environment设置正确的get来避免这种情况。使用lapply的诀窍是使用sys.parent(n)(在这种情况下n = 0将起作用)以获得适当的调用环境。

test.table[,lapply(grep('a',names(test.table),value=TRUE), 
                    get, envir = sys.parent(0))]

(更多信息可在此处找到Using get inside lapply, inside a function

答案 1 :(得分:2)

这是lapply的函数,而不是data.table来自lapply文档:

  

由于历史原因,lapply创建的调用未被评估,并且代码已经编写(例如bquote)依赖于此。这意味着记录的调用始终为FUN(X [[0L]],...)形式,0L由当前整数索引替换。这通常不是问题,但是如果FUN使用sys.call或match.call,或者它是一个使用该调用的原始函数。这意味着用包装器调用原始函数通常更安全,因此例如R 2.7.1中需要lapply(ll,function(x)is.numeric(x))以确保正确发生is.numeric的方法分派。

更新@Hadley和@Ddin的评论:

EE <- new.env()
EE$var1 <- "I am var1 in EE"
EE$var2 <- "I am var2 in EE"

## Calling get directly
with(EE, lapply(c("var1", "var2"), get))
Error in FUN(c("var1", "var2")[[1L]], ...) : object 'var1' not found

## Calling get via an anonymous function
with(EE, lapply(c("var1", "var2"), function(x) get(x)))
[[1]]
[1] "I am var1 in EE"

[[2]]
[1] "I am var2 in EE"

with(EE, lapply(c("var1", "var2"), rm))
Error in FUN(c("var1", "var2")[[1L]], ...) : 
  ... must contain names or character strings

with(EE, lapply(c("var1", "var2"), function(x) rm(x)))
[[1]]
NULL

[[2]]
NULL

# var1 & var2 have now been removed
EE
<environment: 0x1154d0060>

答案 2 :(得分:-1)

这只是因为data.table评估j() expression(简单来说,DT[,...])中第一个逗号之后的所有内容都是实际表达式。所以DT[,"Column1"]返回"Column1",就像with(DT, "Column1")返回"Column1"一样。它位于数据表常见问题中。

如果您愿意,可以这样做:

DT[,names(test.table),with=F]