如何使用data.table创建一个带有函数输入的函数?

3

当我使用data.table进行练习时遇到了一个问题。这是我的问题。我写了一个简单的减法函数:

minus <- function(a, b){
      return(a - b)
  }

我的数据集是一个简单的 data.table:

dt <- as.data.table(data.frame(first=c(5, 6, 7), second=c(1,2,3)))
dt
  first second
1     5      1
2     6      2
3     7      3

我想要编写另一个函数,

myFunc <- function(dt, FUN, ...){
      return(dt[, new := FUN(...)])
  }

使用方法很简单:
res <- myFunc(dt, minus, first, second)

结果将会如下所示:
res
   first second new
1:     5      1   4
2:     6      2   4
3:     7      3   4

我该如何实现这样的目标?谢谢!
2个回答

2
也许有更好的方法,但您可以尝试类似以下的方式:
myFunc <- function(indt, FUN, ...) {
  FUN <- deparse(substitute(FUN))    # Get FUN as a string
  FUN <- match.fun(FUN)              # Match it to an existing function
  dots <- substitute(list(...))[-1]  # Get the rest of the stuff
  # I've used `copy(indt)` so that it doesn't affect your original dataset
  copy(indt)[, new := Reduce(FUN, mget(sapply(dots, deparse)))][]
}

(请注意,这非常特定于您如何创建minus()函数。)
这是它的运行效果:
res <- myFunc(dt, minus, first, second)
dt  ## Unchanged
#    first second
# 1:     5      1
# 2:     6      2
# 3:     7      3

res
#    first second new
# 1:     5      1   4
# 2:     6      2   4
# 3:     7      3   4

谢谢!如果我想根据输入更改新列名称怎么办? - morningfin
@Nal-rA,也许可以使用 setnames - A5C1D2H2I1M1N2O1R2T1
你可能需要使用do.call而不是Reduce。我现在没有电脑在身边... - A5C1D2H2I1M1N2O1R2T1
我已经尝试使用do.call,但感觉有点奇怪。你能再帮我一次吗?谢谢。 - morningfin
@Nal-rA,你可能会使用哪些函数?你可以重新定义minus如下:minus <- function(...) Reduce("-", list(...))。然后,将myFunc中的最后一行更改为:copy(indt)[, new := do.call(FUN, .SD), .SDcols = sapply(dots, deparse)][] - A5C1D2H2I1M1N2O1R2T1
显示剩余3条评论

0

这里有一个使用do.call的解决方案:

myFunc <- function(dt, FUN, ...){
  arg.names <- as.character(match.call()[-(1:3)])
  copy(dt)[, "new" := do.call(FUN, lapply(arg.names, function(x) get(x)))]
}
#test
myFunc(dt, minus, first, second)
#   first second new
#1:     5      1   4
#2:     6      2   4
#3:     7      3   4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接