使用函数的字符名称和参数作为字符向量

时间:2015-11-24 22:33:20

标签: r data.table do.call

我想在data.table上按字符名称调用函数。每个函数都有一个参数向量(因此有一长串要应用于data.table的函数)。参数是data.table列。我的第一个想法是,do.call将是一个很好的方法来完成这项任务。下面是一个简单的示例,其中包含一个要运行的函数名称,它是要传递的列的向量:

# set up dummy data 
set.seed(1)
DT <- data.table(x = rep(c("a","b"),each=5), y = sample(10), z = sample(10))
# columns to use as function arguments
mycols <- c('y','z')
# function name 
func <- 'sum'
# my current solution:
DT[, do.call(func, list(get('y'), get('z'))), by = x]
#    x V1
# 1: a 47
# 2: b 63  

我对此不满意,因为它需要专门命名每一列。而且我想传递一个字符向量mycols

在这种情况下我需要的其他解决方案是:

DT[, do.call(func, .SD), .SDcols = mycols, by = x]

但是自定义功能出现了问题,唯一对我有用的解决方案是第一个:

#own dummy function    
myfunc <- function(arg1, arg2){
  arg1+arg2
}
func <- 'myfunc'
DT[, do.call(func, list(get('y'), get('z'))), by = x] 
#   x V1
#  1: a  6
#  2: a  6
#  3: a 11
#  4: a 17
#  5: a  7
#  6: b 15
#  7: b 17
#  8: b 10
#  9: b 11
# 10: b 10
# second solution does not work 
DT[, do.call(func, .SD), .SDcols = mycols, by = x]
# Error in myfunc(y = c(3L, 4L, 5L, 7L, 2L), z = c(3L, 2L, 6L, 10L, 5L)) : 
#  unused arguments (y = c(3, 4, 5, 7, 2), z = c(3, 2, 6, 10, 5))

据我了解,它假设myfunc的参数y, z不正确。应该有变量y,z,应该传递给参数arg1, arg2

我也尝试了mget功能,但也没有成功:

DT[, do.call(func, mget(mycols)), by = x] 
# Error: value for ‘y’ not found

我可能会遗漏一些相当明显的东西,提前感谢任何指导。

3 个答案:

答案 0 :(得分:1)

这很可能取决于您要使用的功能类型,但您可能会感兴趣Reduce

以下是两个例子:

mycols <- c('y','z')
func <- 'sum'

DT[, Reduce(func, mget(mycols)), by = x]
#    x V1
# 1: a 47
# 2: b 63

myfunc <- function(arg1, arg2){
  arg1+arg2
}
func <- 'myfunc'

DT[, Reduce(func, mget(mycols)), by = x]
#     x V1
#  1: a  6
#  2: a  6
#  3: a 11
#  4: a 17
#  5: a  7
#  6: b 15
#  7: b 17
#  8: b 10
#  9: b 11
# 10: b 10

答案 1 :(得分:0)

这是一个帮助我实现我想要的解决方案。

func <- 'sum'
mycols <- c('y','z')
DT[, do.call(func, lapply(mycols, function(x) get(x))), by = x]
#    x V1
# 1: a 47
# 2: b 63

可以传递给它base函数或自定义函数(不像Reduce解决方案那样具体)。

答案 2 :(得分:0)

是的,你错过了一些东西(嗯,这不是很明显,但仔细调试错误可以确定问题)。您的函数需要命名参数arg1arg2。您通过y = ...(您已注意到)传递参数z = ...do.call。解决方案是传递没有名称的列表:

> DT[, do.call(func, unname(.SD[, mycols, with = F])), by = x]
    x V1
 1: a  6
 2: a  6
 3: a 11
 4: a 17
 5: a  7
 6: b 15
 7: b 17
 8: b 10
 9: b 11
10: b 10
相关问题