gpt4 book ai didi

r - 开发引用 n-1 行的更有效的 for 循环

转载 作者:行者123 更新时间:2023-12-03 23:07:15 24 4
gpt4 key购买 nike

我需要运行一个逻辑,其中“n”步骤基于“n-1”步骤的结果,因此我在 for 循环中实现了逻辑。这里的代码:

library(data.table)
df<-as.data.table(matrix(rexp(100000, rate=.1), ncol=1000))
weight<-as.data.table(matrix(rexp(100, rate=10), ncol=1))

for (row in 1:nrow(weight))
{
if (row > 2){

# from second row start the logic
# We create weighted averages of variables values: value(n-1)* (1-weight) + value(n) * weight
df[row] <-
df[row-1,] * as.numeric(1 - weight[row]) + df[row,] * as.numeric(weight[row])

}
}

但是,它需要很长时间才能运行,因为 data.table 实际上由 1098 列和 200k 行组成。

有人对如何开发更有效的解决方案有想法吗?

最佳答案

让我解释一下我将如何提高此类任务的性能的故事。

基本时间

首先,我重新创建您的数据(稍微小一点)并测量运行它所需的时间:

library(data.table)
library(tictoc) # for timing only

# easier way to create a data.table
NROWS <- 100
NCOLS <- 100
set.seed(123)

df_orig <- data.table(matrix(rexp(NROWS * NCOLS, rate = 0.1), ncol = NCOLS))
wt <- data.table(V1 = rexp(NROWS, rate = 10))


df1 <- copy(df_orig)
tic()
for (r in 1:nrow(wt)) {
if (r >= 2) { # assuming you mean >= 2 not >= 3 (:= >2)
# from second row start the logic
# We create weighted averages of variables values: value(n-1)* (1-weight) + value(n) * weight
df1[r, ] <- df1[r-1,] * as.numeric(1 - wt[r]) + df1[r,] * as.numeric(wt[r])
}
}
toc()
#> 1.274 sec elapsed

reprex package 创建于 2020-05-08| (v0.3.0)

模型 2

然后我研究改进代码的方法。例如, as.numeric()可能很贵, if ()检查循环。让我们删除它,但确保结果保持不变

# no if check in the loop and replace as.numeric with [[1]]
# loop only from 2
df2 <- copy(df_orig)
tic()
for (r in 2:nrow(wt)) {
df2[r, ] <- df2[r - 1, ] * (1 - wt[r][[1]]) + df2[r, ] * wt[r][[1]]
}
toc()
#> 1.149 sec elapsed

# check that the results are identical
all.equal(df1, df2)
#> [1] TRUE

reprex package 创建于 2020-05-08| (v0.3.0)

好一点,但我们还没有。

矩阵模型

一般 data.table是提高速度的好方法,但这种访问最好在基础结构中实现,即 matrix() .

所以让我们这样做:

# Matrix based
mdf <- as.matrix(df_orig)
mwt <- as.matrix(wt)

tic()
for (r in 2:nrow(wt)) {
mdf[r, ] <- mdf[r - 1, ] * (1 - mwt[r, ]) + mdf[r, ] * mwt[r, 1]
}
toc()
#> 0.005 sec elapsed

df3 <- data.table(mdf)

all.equal(df3, df1)
#> [1] TRUE

reprex package 创建于 2020-05-08| (v0.3.0)

这看起来是一个不错的加速!

但还有更多...
Rcpp模型

尤其是在这类任务中, Rcppc++写起来更麻烦,但提供了漂亮的加速。
这里我们使用 Armadillo c++ 的矩阵库及其 Rcpp RcppArmadillo 的绑定(bind).

将您的代码翻译成 Rcpp产生这个:

# using rcpp
rcpp_code <- "// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
// [[Rcpp::export]]
arma::mat my_rcpp_fun(arma::mat data, arma::mat weights) {
const int len = weights.size();

// Cpp starts indexing at 0, so 1 is the second row!
for (int i = 1; i < len; i++) {
data.row(i) = data.row(i - 1) * (1 - weights.row(i)(0)) + data.row(i) * weights.row(i)(0);
}
return data;
}
"

Rcpp::sourceCpp(code = rcpp_code)
mdf2 <- as.matrix(df_orig)
mwt2 <- as.matrix(wt)

tic()
mdf4 <- my_rcpp_fun(mdf2, mwt2)
toc()
#> 0.002 sec elapsed

df4 <- data.table(mdf4)
all.equal(df4, df1)
#> [1] TRUE

reprex package 创建于 2020-05-08| (v0.3.0)

从 1.274s 到 0.002s 听起来不错吧?!

关于r - 开发引用 n-1 行的更有效的 for 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61673970/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com