使用 Rcpp 為迴圈加速難以向量化
考慮以下難以向量化的 for 迴圈,它建立一個長度為 len
的向量,其中指定第一個元素(first
)並且每個元素 x_i
等於 cos(x_{i-1} + 1)
:
repeatedCosPlusOne <- function(first, len) {
x <- numeric(len)
x[1] <- first
for (i in 2:len) {
x[i] <- cos(x[i-1] + 1)
}
return(x)
}
這段程式碼涉及一個快速操作的 for 迴圈(cos(x[i-1]+1)
),它通常受益於向量化。然而,用基 R 對該操作進行向量化並不是一件容易的事,因為 R 不具有“x + 1 的累積餘弦”函式。
加速此功能的一種可能方法是使用 Rcpp 包在 C++中實現它:
library(Rcpp)
cppFunction("NumericVector repeatedCosPlusOneRcpp(double first, int len) {
NumericVector x(len);
x[0] = first;
for (int i=1; i < len; ++i) {
x[i] = cos(x[i-1]+1);
}
return x;
}")
這通常會為大型計算提供顯著的加速,同時產生完全相同的結果:
all.equal(repeatedCosPlusOne(1, 1e6), repeatedCosPlusOneRcpp(1, 1e6))
# [1] TRUE
system.time(repeatedCosPlusOne(1, 1e6))
# user system elapsed
# 1.274 0.015 1.310
system.time(repeatedCosPlusOneRcpp(1, 1e6))
# user system elapsed
# 0.028 0.001 0.030
在這種情況下,Rcpp 程式碼使用基本 R 方法在 0.03 秒內生成長度為 100 萬的向量,而不是 1.31 秒。