注意已在dplyr的开发版本中修复了所描述的行为。你可以使用devtools :: install_github(“hadley / dplyr”)安装dplyr
请看这个最小的例子;我使用的是dplyr v0.3.0.2和data.table v1.9.4
library(dplyr)
library(data.table)
f <- function(x, y, bad) {
z <- data.table(x,y, key = "x")
z2 <- z %>% group_by(x) %>% summarise(sum.bad = sum(y == bad))
z2
}
f(rnorm(100), rnorm(100) < 0, bad = FALSE)
当我运行以上内容时,我得到了
Error in `[.data.table`(dt, , list(sum.bad = sum(y == bad)), by = vars) :
object 'bad' not found
然而,明确界定了不好的范围。
如果我只是在函数之外运行它可以工作
x <- rnorm(100)
y <- rnorm(100) <0
bad <- FALSE
z <- data.table(x,y, key = "x")
z2 <- z %>% group_by(x) %>% summarise(sum.bad = sum(y == bad))
z2
这是什么问题?它是data.table还是dplyr的错误?
答案 0 :(得分:4)
这似乎是dplyr
如何为data.table调用设置环境的问题。问题出现在dplyr:::summarise_.grouped_dt
函数中。它目前看起来像
function (.data, ..., .dots)
{
dots <- lazyeval::all_dots(.dots, ..., all_named = TRUE)
for (i in seq_along(dots)) {
if (identical(dots[[i]]$expr, quote(n()))) {
dots[[i]]$expr <- quote(.N)
}
}
list_call <- lazyeval::make_call(quote(list), dots)
call <- substitute(dt[, list_call, by = vars], list(list_call = list_call$expr))
env <- dt_env(.data, parent.frame())
out <- eval(call, env)
grouped_dt(out, drop_last(groups(.data)), copy = FALSE)
}
<environment: namespace:dplyr>
如果我们调试该函数并在调用它时查看跟踪,我们会看到
where 1: summarise_.grouped_dt(.data, .dots = lazyeval::lazy_dots(...))
where 2: summarise_(.data, .dots = lazyeval::lazy_dots(...))
where 3: summarise(., sum.bad = sum(y == bad))
where 4: function_list[[k]](value)
where 5: withVisible(function_list[[k]](value))
where 6: freduce(value, `_function_list`)
where 7: `_fseq`(`_lhs`)
where 8: eval(expr, envir, enclos)
where 9: eval(quote(`_fseq`(`_lhs`)), env, env)
where 10: withVisible(eval(quote(`_fseq`(`_lhs`)), env, env))
where 11 at #3: z %>% group_by(x) %>% summarise(sum.bad = sum(y == bad))
where 12: f(rnorm(100), rnorm(100) < 0, bad = FALSE)
所以重要的一行是
env <- dt_env(.data, parent.frame())
之一。这里设置环境路径,指定在调用中查找所有变量的位置。这里只是使用parent.frame来查看调用函数的位置,但是因为你实际上跳过了几个箍来从summarize
f()
内的env <- dt_env(.data, parent.frame(2))
调用中获取此函数,所以似乎是正确的父框架。如果,而不是你运行
summarize()
在调试模式下,似乎实际上得到了正确的父帧。所以我认为问题是从summarize_()
跳到ff <- function(x, y, bad) {
z <- data.table(x,y, key = "x")
z2 <- z %>% group_by(x) %>% summarise_(.dots=list(sum.bad = quote(sum(y == bad))))
z2
}
ff(rnorm(100), rnorm(100) < 0, bad = FALSE)
因为这个
summarize
似乎有效。因此,需要建立正确的环境才是真正的dplyr。如果您直接致电summarize_
或summarise()
,那么棘手的部分似乎有所不同。当summarise_
通过eval()
调用summarise <- function(.data, ...) {
call <- match.call()
call <- as.call(c(as.list(call)[1:2], list(.dots=as.list(call)[-(1:2)])))
call[[1]] <- quote(summarise_)
eval(call, envir=parent.frame())
}
来拥有相同的parent.frame时,data.table_1.9.2
可能会改变环境。但我可能会将此作为错误报告提交,让Hadley决定如何修复它。像
dplyr_0.3.0.2
将是一种“传统”的方式。不确定lazyeval包是否有更好的方法来执行此操作。
使用{{1}}和{{1}}
进行测试