簡體   English   中英

使用 Purrr::map2 或 pmap 避免 for 循環

[英]Using Purrr::map2 or pmap to avoid for loops

我拼命地試圖避免 for 循環來計算自定義財務指標(多只股票,每只股票 5,000 行)。 我正在嘗試使用purrr::map2 ,並且在對現有向量進行數學運算時很好,但我需要引用我正在嘗試創建的向量的滯后(先前)值。 在不引用先前值的情況下, purrr::map2可以正常工作:

 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)

這只會產生原始的收盤價

15.5, 16.7, 14.8, 13.1

但我真正想做的是創建一個新的向量 (c),它作為計算的一部分回顧自身 (滯后)。 如果是第一行,c == b,否則:

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

所以我創建了一個向量c並填充並嘗試:

 c <- c(15.5, 0, 0, 0) purrr::map2(a, b, c, desired_function)

顯然,得到所有 NULL 值。
c 的值應為: 15.50, 15.53, 15.52, 15.47

引用以前的值在指標中是很常見的事情,它迫使我將 go 變成笨重、緩慢的“for 循環”。 非常感謝任何建議。

如果計算一個向量中的某個值需要來自同一個向量的另一個值,那么它就不能被向量化; 你必須一個接一個地計算它們。

For循環本身並不慢; 這就是你使用它們的方式。 例如,一次從數據幀中檢索一個值,或者一次插入一個值,是一種非常緩慢的常見做法。

在過去 10 年中,R 中 for 循環的實現有了很大的改進,據說它們過去效率較低,在舊帖子中你會發現很多人抱怨它。

推薦閱讀:

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

這兩個老問題(嗯,他們的答案):

加快 R 中的循環操作

為什么 R 中的循環很慢?

一個小實驗

讓我們用 purrr::map() 對沒有滯后的 function 的最簡單(最愚蠢的?)for循環實現進行基准測試: c = a*b + (1-a) * b

在這個包含 1000 萬個項目的基准測試中,for 循環比 purrr::map2() 快 15 倍以上。

 # 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

Here some solutions, first one refers to your idea using stats::lag (using stats::, because the dplyr package always masks lag!),

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

and another one using a starting value that updates in every iteration, which is about 20% faster.

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

Data:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM