R 語言的 parallel 多核心運算

用 R 來進行交易策略開發,在建立交易模型後,有時候交易模型會有參數可以選擇,例如大家熟悉的 RSI、KD 指標…等的參數選擇,常見的作法就是將所有的參數範圍列出來,一一拿去做回測,取績效最好的幾組參數,再分別去觀察各組回測當中的獲利情形,選擇獲利較穩定的一組參數來當最後的交易策略。其中的回測步驟會花費非常多的時間,所以小編今天要在這裡分享簡單用 R 的 parallel 套件來進行 CPU 多核心的運算。

一般使用 R 來做 apply 系列函數運算都只使用到單核心來運算,所以如果使用兩個核心理論上可以快兩倍。在 apply 函數中的運算中,一個核心負責一組運算,如果本來單核心需運算10次,用雙核心運算只要各算5次即可。在使用 parallel 套件前要先熟悉一下 apply 系列函數,例如 sapply,lapply…等。

> lapply( 2:4 , function(x) x^3 )

[[1]]

[1] 8

[[2]]

[1] 27

[[3]]

[1] 64

lapply 當中的function可以是回測的函數,而 2:4便是參數的可能值,如此一來便可以求出每個參數所對應的回測值或是績效的統計量。

接下來要使用 parallel 套件來進行多核心運算。使用 detectCores() 函數可以知道電腦 CPU 有幾個運算核心,小編的電腦是 Intel i7 CPU,共有 4 核心 8 執行緒,這是 intel 的超執行緒技術(Hyper-Threading),使得實體 4 核心 CPU 可擁有 8 個邏輯執行緒。設定 7 個核心數來進行運算,如果在電腦運行 R 的時候,不打算利用電腦做其他事情,也可以設定全部的核心數 8 來進行運算。運算完之後,要輸入 stopCluster(cl) 指令,以防止 R 繼續占用電腦資源。

> library(parallel)

> detectCores()

[1] 8

> cl <- makeCluster(7)

> parLapply(cl, 2:4, function(x) x^3)

[[1]]

[1] 8

[[2]]

[1] 27

[[3]]

[1] 64

> stopCluster(cl)

這樣就結束運算了,因為這是很簡單的運算,用多核心看不出任何的優勢,但有些細項得要注意,makeCluster() 函數在 windows 作業系統下,其預設的 type = “PSOCK"。詳情可使用 ?makeCluster 指令並閱讀其中 type 的參數解說。所以 parLapply() 的運算下無法自動取得環境變數來進行運算,同樣的也無法直接使用 user 的套件。如果要在 parLapply() 的計算中加入環境變數與套件需要另外使用 clusterExport(cl, “a”) 與 clusterEvalQ(cl, library(xts)) 函數。

> cl <- makeCluster(7)

> a <- 3

> parLapply(cl, 2:4, function(x) x^a)

Error in checkForRemoteErrors(val) : 

  3 nodes produced errors; first error: 找不到物件 'a'

> clusterExport(cl, "a")

> parLapply(cl, 2:4, function(x) x^a)

[[1]]

[1] 8

[[2]]

[1] 27

[[3]]

[1] 64

> stopCluster(cl)

接著來測試加速運算的效果如何。先創造 1000 X 30000 的矩陣,其中的值是由平均值為 0 且標準差為 1 的常態分布生成,再將每一列的 30000 個值取最小值,但是小編故意增加其運算量所以先排序再取第一個值。分別測試三個方法,第一個利用 for 迴圈,第二個利用 lapply 函數,第三個利用 parLapply 函數:

> x <- matrix(rnorm(1000*30000), nrow=1000)

> system.time({

+   min.for <- rep(NA, nrow(x))

+   for(i in 1:nrow(x)) min.for[i] <- sort(x[i,])[1]

+ })

   user  system elapsed 

    2.5     0.0     2.5 

> system.time(min.lapply <- lapply(1:nrow(x), function(z) sort(x[z,])[1]))

   user  system elapsed 

   2.45    0.00    2.45 

> cl <- makeCluster(7)

> clusterExport(cl, "x")

> system.time(

+   min.par <- parLapply(cl,1:nrow(x), function(z) sort(x[z,])[1])

+ )

   user  system elapsed 

   0.00    0.00    0.63 

> stopCluster(cl)

同樣的計算,7 核心跑的時間只有 0.63 秒大約是單核心的 4 分之一,所以 parallel 套件可以用來做簡單加速運算,如果是 4 天的運算量,依照這個速率可以 1 天就跑完,省下不少時間。R 語言的加速還有很多種,但 parallel 套件是門檻較低的方法,如果電腦擁有多核心的 CPU 就應該物盡其用,不要浪費了。

 

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s