替换R中的for循环以加速代码

时间:2017-06-29 09:44:48

标签: r

我正在使用R调查退货如何影响一个人的养老金账户。为了做到这一点,我正在计算养老金账户的发展,从25岁到70岁退休,1000个不同的回归情景。我使用变量费用(e),每月存款(m),以百分比(r)表示的回报,帐户余额(y)和以欧元(x)表示的回报。它们都存储在尺寸为46x1000的数据框中。

我已成功设法使用for循环计算它。然而,这是非常缓慢的,因为我正在做很多这些,我想知道是否有人有想法加快代码。我已尝试使用应用函数和矢量化但无法使其工作。我的问题是我必须在计算第i + 1年的数字之前计算第i年的数字。我在互联网上搜索了一个解决方案,但很难找到适用于我特定问题的答案。我应该注意到我还是R的新手。

A使用以下方法编写了代码的简化版本:

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 个答案:

答案 0 :(得分: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 ++可以提供帮助。