我正在使用data.table
包并尝试编写一个函数(如下所示):
require(data.table)
# Function definition
f = function(path, key) {
table = data.table(read.delim(path, header=TRUE))
e = substitute(key)
setkey(table, e) # <- Error in setkeyv(x, cols, verbose = verbose) : some columns are not in the data.table: e
return(table)
}
# Usage
f("table.csv", ID)
这里我尝试将表达式传递给函数。为什么这段代码不起作用?
我已尝试过substitute()
,quote()
和eval()
的不同组合。所以,如果你还能解释如何让它发挥作用,那就太棒了。
答案 0 :(得分:10)
setkey
函数如何处理来自data.table
包的内容:# setkey function
function (x, ..., verbose = getOption("datatable.verbose"))
{
if (is.character(x))
stop("x may no longer be the character name of the data.table. The possibility was undocumented and has been removed.")
cols = getdots()
if (!length(cols))
cols = colnames(x)
else if (identical(cols, "NULL"))
cols = NULL
setkeyv(x, cols, verbose = verbose)
}
所以,当你这样做时:
require(data.table)
dt <- data.table(ID=c(1,1,2,2,3), y = 1:5)
setkey(dt, ID)
它调用getdots
内部的函数data.table
(也就是说,它不会被导出)。我们来看看这个功能:
# data.table:::getdots
function ()
{
as.character(match.call(sys.function(-1), call = sys.call(-1),
expand.dots = FALSE)$...)
}
那么,这是做什么的?它采用您在setkey
中输入的参数,并使用match.call
分别提取参数。也就是说,此示例案例的match.call
参数将为:
setkey(x = dt, ... = list(ID))
由于它是一个列表,您可以使用...
访问$...
参数,以获取包含其值ID
的1个元素的列表,并将此列表转换为包含{的字符{1}}会产生as.character
(字符向量)。然后"ID"
在内部将此传递给setkey
以设置密钥。
setkeyv
时这不起作用?这正是因为setkey(table, key)
的方式。 setkey/getdots
函数用于在第一个参数(即setkey
)之后获取任何参数,然后将data.table
参数作为字符返回。
也就是说,如果您提供...
,那么它将返回setkey(dt, key)
。如果您提供cols <- "key"
,则会返回setkey(dt, e)
。它不会查找“key”是否为现有变量,如果是,则替换变量的值。它只是将您提供的值(无论是符号还是字符)转换回字符。
当然,这不适用于您的情况,因为您希望在cols <- "e"
中提供key
= ID中的值。至少我想不出办法做到这一点。
正如@agstudy已经提到的,最好/最简单的方法是通过setkey
并使用"ID"
。但是,如果你真的坚持使用setkeyv
那么,这就是你能做的:
f("table.csv", ID)
在这里,您首先使用f <- function(path, key) {
table = data.table(read.delim(path, header=TRUE))
e = as.character(match.call(f)$key)
setkeyv(table, e)
return(table)
}
获取与参数match.call
对应的值,然后将其转换为key
,然后将其传递给character
。
简而言之,setkeyv
内部使用setkey
。而且,当您已经知道需要设置密钥的setkeyv
的列名时,setkey是一个方便的函数。希望这会有所帮助。
答案 1 :(得分:2)
我无法从你的代码中看出你想要实现的目标,所以我会回答标题要求的问题; “如何通过函数传递表达式?”
如果您想这样做(应尽可能避免这种情况),您可以执行以下操作:
f <- function(expression) {
return(eval(parse(text=expression)))
}
例如:
f("a <- c(1,2,3); sum(a)")
# [1] 6