R 中具有相同长度向量的列表上逐行应用的计算高效替代方案

问题描述 投票:0回答:1

我有一个相同长度向量的列表,我需要对列表中的每个向量元素运行不同的统计函数。我知道我可以通过首先创建一个数据框然后按行运行函数来使用

apply
来做到这一点:

apply(X = do.call(what = "data.frame", args = foo), MARGIN = 1, FUN = "sum", na.rm = TRUE)

当运行几十万次时,这个过程非常慢。 通过

Reduce
我设法得到了部分解决方案,例如当使用
+
而不是
sum
时,速度要快得多:

Reduce(f = "+", x = foo)

不过,我没有设法获得纯

Reduce
版本,可以使用
mean
sd
等函数以及其他参数,以及关于参数
na.rm = TRUE

在依赖

apply
的同时加快速度的次优解决方案仍然只是使用
Reduce
加速矩阵创建:

apply(X = Reduce(function(...) cbind(...), foo), MARGIN = 1, FUN = "sum", na.rm = TRUE)

这是可重现的示例以及我迄今为止提出的解决方案的比较。

foo <- lapply(X = 1:1e2, FUN = function(x) 1:10)
microbenchmark::microbenchmark("apply_do.call" = apply(X = do.call(what = "data.frame", args = foo), MARGIN = 1, FUN = "sum", na.rm = TRUE),
                               "apply_Reduce" = apply(X = Reduce(f = function(...) cbind(...), x = foo), MARGIN = 1, FUN = "sum", na.rm = TRUE),
                               "Reduce" = Reduce(f = "+", x = foo))

这会在我的机器(Linux)上产生以下输出

Unit: microseconds
          expr      min       lq       mean    median        uq      max neval cld
 apply_do.call 4256.337 4406.775 5211.12032 4603.8670 5180.1275 13508.14   100   c
  apply_Reduce  292.775  326.124  480.88223  346.5525  436.1935  7559.97   100  b 
        Reduce   37.505   43.197   51.53856   46.7935   55.2790   131.72   100 a 

如您所见,与第一个示例相比,

Reduce
版本仅需要大约 1% 的计算时间,计算改进的潜力是巨大的。

有没有一种方法可以在不依赖外部库的情况下有效地解决我的问题(与最小值、最大值、总和、平均值、标准差...兼容)?如果答案能够正确计算

mean
sd
等统计数据,并保留
POSIXct
等对象类型,即可获得加分。

r statistics apply reduce microbenchmark
1个回答
0
投票

apply
是为矩阵设计的,将其应用在data.frames上效率非常低。尝试使用
cbind
代替,或者使用
matrixStats::rowSums2
等 cpp 函数。

> microbenchmark::microbenchmark(
+   apply_df=apply(do.call("data.frame", foo), 1, sum, na.rm=TRUE),
+   apply_mat=apply(do.call("cbind", foo), 1, sum, na.rm=TRUE),
+   ms=matrixStats::rowSums2(do.call(what="cbind", args=foo)), 
+   check='equal')
Unit: microseconds
      expr      min        lq       mean   median        uq       max neval cld
  apply_df 9192.141 9475.6885 9975.73942 9702.244 9989.6995 18370.500   100  a 
 apply_mat   93.222   98.1140  104.11094  101.521  107.2095   145.461   100   b
        ms   39.455   42.2835   49.48344   48.328   56.0690    66.346   100   b
© www.soinside.com 2019 - 2024. All rights reserved.