首先 - 如果以前曾经问过这个问题我很道歉,我已经看过了,并且找不到任何符合我想要做的事情。
我尝试创建一个根据数据框中用户生成的列来存储数据的函数。为此,我使用了来自dplyr的mutate()函数和来自基数R的cut()。但是,我无法弄清楚如何使用通过函数传递的列名在cut()函数内部(出现在mutate中)。
我花了几个小时翻阅this和this,但仍然无法理解。我的理解是foo(),bar()和下面代码中的最后一行都应该产生相同的输出。但是,我得到了函数的两个错误,并且没有包含在函数中的错误只是使用硬编码的列名称。
这里发生了什么?为什么foo()产生的输出与bar()不同?我如何正确使用lazyeval来允许函数中的正确行为?
library(dplyr)
library(lazyeval)
foo <- function(data, col, bins){
by = lazyeval::interp(quote(x), x = as.name(col))
print(paste0("typeof(by): ", typeof(by)))
print(paste0(" by: ", by))
df <- data %>%
dplyr::mutate(bins = cut(by,
breaks = bins,
dig.lab = 5,
include.lowest = T))
df
}
bar <- function(data, col, bins){
df <- data %>%
dplyr::mutate(bins = cut(lazyeval::interp(quote(x), x = as.name(col)),
breaks = bins,
dig.lab = 5,
include.lowest = T))
df
}
#produce sample data and bins list
df <- expand.grid(temp=0:8,precip=seq(0.7,1.3,by=0.1))
df$rel <- seq(40,100,length=63)
bins <- seq(40,100,by=10)
foo(df,"rel",bins) # produces "Error: 'rel' not found"
bar(df,"rel",bins) # produces "Error: 'x' must be numeric"
# but this works
dplyr::mutate(df, bins = cut(rel, breaks = bins, dig.lab = 5, include.lowest = T))
答案 0 :(得分:1)
正如@aosmith在评论中提到的,解决方案是使用mutate_(bins = interp(~cut(x, bins, dig.lab = 5, include.lowest = TRUE), x = as.name(col)))
。使用mutate_
代替mutate
可以让我们使用标准评估。
如果我们在interp
之外调用cut
,最简单的方法是查看interp
和mutate_
的内容。 (它以相同的方式执行。)假设col == "rel"
,
call = interp(~cut(x, bins, dig.lab = 5, include.lowest = TRUE), x = as.name(col)))
将给出
~cut(rel, bins, dig.lab = 5, include.lowest = TRUE)
将此表达式插入mutate允许我们完全按照here提供的示例进行操作。
muatate_(bins = call)
给出正确的结果。
您还可以允许用户提供替换“bins”的列名:
dplyr::mutate_(.dots = setNames(call, c(binName)))