2017-06-29 92 views
1

我使用R來調查返回如何影響個人的養老金賬戶。爲了做到這一點,我計算了退休金賬戶從25歲到退休到70歲退休的1000種不同的回報情況。我使用變量費用(e),月度存款(m),百分比(r)回報,賬戶餘額(y)和歐元回報(x)。它們都存儲在尺寸爲46x1000的數據框中。替換R中的for循環以加速代碼

我成功設法使用for循環來計算它。然而,這是非常緩慢的,因爲我正在做很多這些我想知道如果有人有一個想法加快代碼。我已經嘗試過應用函數和矢量化,但無法使其工作。我的問題是,在計算第i + 1年的數字之前,我必須計算第i年的數字。我已經在網上搜索了一個解決方案,但是很難找到適用於我的特定問題的答案。我要指出,我還是很新的R.

一個已經使用編寫的代碼IM的簡化版本:

for (i in 3:46) { 
x[i-1,]<-(y[i-1,]+m[i-1,]*6-0.5*e[i-1,])*r[i-1,] 
y[i,]<-y[i-1,]+x[i-1,]-e[i-1,]+m[i-1,]*12 
} 

我希望有人能夠幫助,並在此先感謝。

問候 拉斯穆斯

+1

您可以使用'RCpp'包並在'C++'中編寫計算。這樣你就可以保證有良好的性能,你的代碼看起來很容易遷移。 –

+1

看看這個:https://stackoverflow.com/questions/2908822/speed-up-the-loop-operation-in-r/8474941#8474941。問題和答案都非常好。 – p0bs

回答

4

你的過程在我看來就像它需要循環,因爲每次迭代依賴於面前的一個。正如@Gregor de Cillia在評論中提到的那樣,你可以用C++來提高速度。

首先,設置一些數據。

set.seed(1) 
e <- matrix(data = rnorm(n = 46000, mean = 1000, sd = 200), 
         nrow = 46, 
         ncol = 1000) 
m <- matrix(data = rnorm(n = 46000, mean = 2000, sd = 200), 
         nrow = 46, 
         ncol = 1000) 
r <- matrix(data = rnorm(n = 46000, mean = 4, sd = 0.5), 
         nrow = 46, 
         ncol = 1000) 
x <- matrix(data = NA_real_, nrow = 45, ncol = 1000) 
y <- matrix(data = NA_real_, nrow = 46, ncol = 1000) 
y[1,] <- rnorm(n = 1000, 10000, 1000) 

然後在Rcpp文件中定義一個C++函數。此方法返回的兩個矩陣xy列表項的列表:

List pension(NumericMatrix e, 
       NumericMatrix m, 
       NumericMatrix r, 
       NumericVector yfirstrow) { 

    int ncols = e.cols(); 
    int nrows = e.rows(); 

    NumericMatrix x(nrows - 1, ncols); 
    NumericMatrix y(nrows, ncols); 

    y(0, _) = yfirstrow; 

    for(int i = 1; i < nrows; i++) { 
     x(i-1, _) = (y(i-1, _) + m(i-1, _) * 6 - 0.5 * e(i-1, _)) * r(i-1, _); 
     y(i, _) = y(i-1, _) + x(i-1, _) - e(i-1, _) + m(i-1, _)* 12; 
    }; 

    List ret; 
    ret["x"] = x; 
    ret["y"] = y; 

    return ret; 

} 

比較對速度的兩種方法。

microbenchmark::microbenchmark(
    R = { 
     for (i in 2:46) { 
      x[i-1,] <- unlist((y[i-1,] + m[i-1,]*6 - 0.5*e[i-1,]) * r[i-1,]) 
      y[i,]<- unlist(y[i-1,]+x[i-1,]-e[i-1,]+m[i-1,]*12) 
     } 
    }, 
    cpp = { 
     cppList <- pension(e, m, r, y[1,]) 
    }, 
    times = 100 
) 

確保輸出匹配:

> identical(x, cppList$x) 
[1] TRUE 
> identical(y, cppList$y) 
[1] TRUE 

速度測試結果:

Unit: microseconds 
expr  min  lq  mean median  uq  max neval 
    R 3309.962 3986.569 6961.838 5244.479 6219.215 96576.592 100 
    cpp 879.713 992.229 1266.014 1124.345 1273.691 3041.966 100 

所以Rcpp解決方案是圍繞更快這裏5倍,但說實話,在R循環你所做的對於你正在使用的數據集來說並不是太簡單(只有45次迭代,R循環的開銷並不是太大的障礙)。如果你真的需要這個速度,C++可以提供幫助。

+0

非常感謝你的迴應,我會看看它,希望它能解決我的問題。我知道我的例子中的循環並沒有花費太多時間來運行,但是我的代碼中有更復雜的循環,它們有這樣的循環,並且一旦你必須在我的示例中運行循環多次,它需要很多時間時間。 – Rasmus

+0

感謝您將我的評論轉換爲答案:)。只是一句話:由於「R」的內部存儲模型,列式計算('y [,i] < - unlist(...')可能稍好一些。在這個測試用例中,差異是不可測量的。 –

+0

@GregordeCillia對不起,如果你打算回答(很難檢測到諷刺或缺乏文字)。\ n我不知道有一個不同的內部存儲方法,用於行方式和列方式計算?你只是指data.frames(即:列作爲列表項)還是矩陣? – rosscova