首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Purrr::pmap 2或pmap避免for循环

使用Purrr::pmap 2或pmap避免for循环
EN

Stack Overflow用户
提问于 2022-07-02 23:10:52
回答 2查看 104关注 0票数 1

我正拼命避免for循环来计算自定义的财务指标(多只股票,每只股票5000行)。我正在尝试使用purrr::map2,在对现有向量进行数学计算时,这是很好的,但是我需要引用我试图创建的向量的滞后(以前)值。在不引用前一个值的情况下,purrr::map2可以正常工作:

代码语言:javascript
复制
some_function <- function(a, b) {   (a * b) + ((1 - a) * b)  }
a <- c(0.019, 0.026, 0.012, 0.022)  # some indicator
b <- c(15.5, 16.7, 14.8, 13.1)  # close price
purrr::map2(a, b, some_function)

,这只会导致原来的闭包值。

代码语言:javascript
复制
15.5, 16.7, 14.8, 13.1

但我真正想做的是创建一个新的向量(c),作为计算的一部分,回顾它本身(滞后)。如果是第一行,则为c == b,否则:

代码语言:javascript
复制
desired_function <- function(a, b, c) {   (a * b) + ((1 - a) * lag(c))  } 

因此,我创建了一个向量c并填充并尝试:

代码语言:javascript
复制
c <- c(15.5, 0, 0, 0)
purrr::map2(a, b, c, desired_function)

得到所有的空值,很明显。

C的值应该是:15.50, 15.53, 15.52, 15.47

引用以前的值是指示器中常见的事情,它迫使我使用笨拙、缓慢的“for循环”。如有任何建议,将不胜感激。

EN

回答 2

Stack Overflow用户

发布于 2022-07-03 15:01:14

如果在向量中计算某个值需要来自同一个向量的另一个值,那么它就不能被向量化;您必须一个接一个地计算它们。

For循环本身并不慢,而是如何使用它们。例如,从数据帧中一次检索一个值,或者一次插入一个值,这是一种非常慢的常见做法。

在过去的10年里,R中的for-循环的实现有了很大的改进,它们以前效率很低,在旧的帖子中,你会发现很多人都在抱怨它。

建议阅读:

https://www.r-bloggers.com/2018/06/why-loops-are-slow-in-r/

这两个老问题(嗯,他们的答案):

Speed up the loop operation in R

Why are loops slow in R?

一个小小的实验

让我们对最简单的(最愚蠢的?)进行基准测试。函数的purrr::map()的for -循环实现:c = a*b + (1-a) * b

在这个包含1000万项的基准测试中,for-循环的速度是purrr::map2()的15倍以上。

代码语言:javascript
复制
# functions ---------------------------------------------------------------

desired_function <- function(a,b) { a*b + (1-a) * b }

des_fnc_for <- function(a, b) {
  c <- numeric(length(a))
  c[1] <- b[1]
  for(i in seq_along(a)) c[i] <- a[i] * b[i] + (1 - a[i]) * b[i]
  return(c)
}


# verify --------------------------------------------------------------------

a <- c(0.019, 0.026, 0.012, 0.022)  # some indicator
b <- c(15.5, 16.7, 14.8, 13.1)  # close price

unlist(purrr::map2(a,b,desired_function))

[1] 15.5 16.7 14.8 13.1

des_fnc_for(a,b)

[1] 15.5 16.7 14.8 13.1


# benchmark ---------------------------------------------------------------

a <- runif(10000000, 0.01, 0.03)
b <- runif(10000000, 13, 17)

system.time( des_fnc_for(a,b) )

   user  system elapsed 
  1.143   0.007   1.163 

system.time( purrr::map2(a,b,desired_function) )

   user  system elapsed 
 18.570   0.627  19.761 
票数 0
EN

Stack Overflow用户

发布于 2022-07-03 15:31:13

这里有一些解决方案,第一种是使用stats::lag (使用stats::,因为dplyr包总是掩蔽lag!),

代码语言:javascript
复制
r <- numeric(4L)
for (i in 1:4) {
  r[i] <- c[i + 1] <- a[i]*b[i] + (1 - a[i])*stats::lag(c)[i]
}
r
# [1] 15.50000 15.53120 15.52243 15.46913

另一个使用的是在每次迭代中更新的起始值,大约快20%。

代码语言:javascript
复制
r <- numeric(4L)
sval <- 15.5
for (i in 1:4) {
  r[i] <- sval <- a[i]*b[i] + (1 - a[i])*sval
}
r
# [1] 15.50000 15.53120 15.52243 15.46913

数据:

代码语言:javascript
复制
a <- c(0.019, 0.026, 0.012, 0.022)
b <- c(15.5, 16.7, 14.8, 13.1)
c <- c(15.5, 0, 0, 0)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72842980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档