将大型data.frame的行作为参数传递给R中的函数的最快和最有效的方法

我想在 data.frame 中建立一个新列,myDF这是一个函数为每一行返回的值,该函数getval将该行中的元素作为参数。getval还使用外部向量v1作为参数。例如:

myn = 1000
a = seq(0, 1, length.out = myn)
b = seq(-1, 1, length.out = myn)
myDF = expand.grid(a=a, b=b)

set.seed(13)
v1 = rnorm(100)

getval = function(a, b, v) {
  return(sum(a*v + b/2*v))
}

myDF$val = apply(myDF, 1, function(x) {getval(a=x[1], b=x[2], v=v1)})
head(myDF)
#             a  b      val
# 1 0.000000000 -1 3.091267
# 2 0.001001001 -1 3.085078
# 3 0.002002002 -1 3.078889
# 4 0.003003003 -1 3.072700
# 5 0.004004004 -1 3.066512
# 6 0.005005005 -1 3.060323

但这太慢了(这里约 4 秒,但对于更高的会增加很多myn)。

我正在寻找最快的方法来实现这个 - 竞赛!;-)

欢迎所有解决方案(包括并行化?)和包(dplyrdata.table?) - 例如,我真的需要尽可能快的东西myn= 5000。


编辑
实际上,getval不是那么(容易?)可矢量化的......

getval = function(a, b, v) {
  return(sum(a/(a/v +1) + b/(b+2) * v))
}

myDF$val = apply(myDF, 1, function(x) {getval(a=x[1], b=x[2], v=v1)})
head(myDF)
#             a  b      val
# 1 0.000000000 -1 6.182533
# 2 0.001001001 -1 6.282782
# 3 0.002002002 -1 6.383424
# 4 0.003003003 -1 6.484682
# 5 0.004004004 -1 6.586980
# 6 0.005005005 -1 6.691260

回答

您应该尽可能努力避免在行上循环。对于您的示例:

getval = function(a, b, v) {
  return((a + b / 2) *sum(v))
}

myDF$val1 = getval(myDF$a, myDF$b, v1)
head(myDF)
#            a  b      val     val1
#1 0.000000000 -1 3.091267 3.091267
#2 0.001001001 -1 3.085078 3.085078
#3 0.002002002 -1 3.078889 3.078889
#4 0.003003003 -1 3.072700 3.072700
#5 0.004004004 -1 3.066512 3.066512
#6 0.005005005 -1 3.060323 3.060323

您将无法击败这种矢量化解决方案的性能。如果这在 R 中无法实现,请使用 Rcpp 实现所有内容(包括循环)。使用这么简单的功能并不难。

编辑:

这是第二个示例的 Rcpp 函数。由于 Rcpp 糖函数,例如sum.

library(Rcpp)
cppFunction(
  "
  NumericVector rcpp_geval(const NumericVector a, const NumericVector b, const NumericVector v) {
    const double n = a.length();
    NumericVector res(n);
    for (double i = 0; i < n; ++i) {
      res[i] = sum(a[i]/(a[i]/v +1) + b[i]/(b[i]+2) * v);
    }
    return res;
  }
  "
)

myDF$val1 <- rcpp_geval(myDF$a, myDF$b, v1)

head(myDF)
#            a  b      val     val1
#1 0.000000000 -1 6.182533 6.182533
#2 0.001001001 -1 6.282782 6.282782
#3 0.002002002 -1 6.383424 6.383424
#4 0.003003003 -1 6.484682 6.484682
#5 0.004004004 -1 6.586980 6.586980
#6 0.005005005 -1 6.691260 6.691260


以上是将大型data.frame的行作为参数传递给R中的函数的最快和最有效的方法的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>