r 中嵌套 for 循环的替代方案或可能需要 Rcpp 吗?
an alternative to nested for loops in r OR possible Rcpp needed?
我有一个嵌套循环
X <- matrix(c(0.5,0,0,0.75), nrow = 2)
k = nrow(X)
ans1 <- 0
ans2 <- 0
for (aa in 1:k) {
for (bb in 1:k) {
for (cc in 1:k) {
for (dd in 1:k) {
ans1 = ans1 + (0.45 * X[aa,bb] * X[cc,dd])
for (xx in 1:k) {
for (yy in 1:k){
ans2 = ans2 + (1.7*X[aa,bb]*X[xx,yy]*X[cc,dd] + 0.2*X[aa,xx]*X[bb,yy]*X[cc,dd])
}
}
}
}
}
}
但是必须是方阵的矩阵X
可以有很高的维度。因此,这会大大减慢循环速度。例如X = matrix(rnorm(10000),nrow = 100,byrow = T)
我想知道是否有更短的压缩方法。这将是可读的,最重要的是稍微快一点。我试过 expand.grid
但这没什么用。
例如ans1
library(tidyverse)
an1 <- expand.grid(rep(list(seq(length(X))),2)) %>% arrange_all()
an11 <- t(apply(an1, 1, function(x) as.vector(t(X))[x]))
但是正如我提到的,这并没有提高速度。有什么建议么?我也在想 Rcpp 可能会有所帮助,但我不确定,我还没有尝试过(C++ 语法不是很好)。
与 C++ 中的 for
循环相比,R 中的 for
循环非常慢。
C++ for
循环语法与某些风格的 R 没有太大区别。
我高度怀疑您可以显着压缩代码。但只是按照你非常嵌套的语法:
Rcpp 函数:
//[[Rcpp::export]]
Rcpp::NumericVector foo(Rcpp::NumericMatrix& X) {
Rcpp::NumericVector ans(2);
int k = X.rows();
for (int aa = 0; aa < k; ++aa) {
for (int bb = 0; bb < k; ++bb) {
for (int cc = 0; cc < k; ++cc) {
for (int dd = 0; dd < k; ++dd) {
ans[0] += 0.45 * X[aa, bb] * X[cc, dd]l;
for (int xx = 0; xx < k; ++xx) {
for (int yy = 0; yy < k; ++yy) {
ans[1] += (1.7 * X[aa, bb] * X[xx, yy] * X[cc, dd] + 0.2 * X[aa, xx] * X[bb, yy] * X[cc, dd]);
}
}
}
}
}
}
return ans;
}
R端:
X <- matrix(c(0.5,0,0,0.75), nrow = 2)
ans <- foo(X)
ans1 <- ans[1]
ans2 <- ans[2]
用上面的代码即插即用并不是不优化代码的借口。再次,减少循环次数。你不应该全部都需要。
在看到@user2554330 的回答后(我怀疑是这种情况,但懒得解决),Rcpp 实现不会比 R 实现快得多(我怀疑你是否担心这种边际收益)
你根本不需要使用循环。由于 ans1
和 ans2
的代码只是项的总和,而这些项根本不相互作用,因此表达式简化为
ans1simple <- 0.45*sum(X)^2
ans2simple <- 1.9*sum(X)^3
您可以在随机数据上进行测试。如果您不相信,请更改 X
的种子或大小:
set.seed(123)
X <- matrix(rnorm(9), nrow = 3)
k = nrow(X)
ans1 <- 0
ans2 <- 0
for (aa in 1:k) {
for (bb in 1:k) {
for (cc in 1:k) {
for (dd in 1:k) {
ans1 = ans1 + (0.45 * X[aa,bb] * X[cc,dd])
for (xx in 1:k) {
for (yy in 1:k){
ans2 = ans2 + (1.7*X[aa,bb]*X[xx,yy]*X[cc,dd] + 0.2*X[aa,xx]*X[bb,yy]*X[cc,dd])
}
}
}
}
}
}
ans1simple <- 0.45*sum(X)^2
ans2simple <- 1.9*sum(X)^3
ans1 - ans1simple
#> [1] 2.220446e-16
ans2 - ans2simple
#> [1] -7.993606e-15
由 reprex package (v1.0.0)
于 2021-04-19 创建
差异只是舍入误差。
我有一个嵌套循环
X <- matrix(c(0.5,0,0,0.75), nrow = 2)
k = nrow(X)
ans1 <- 0
ans2 <- 0
for (aa in 1:k) {
for (bb in 1:k) {
for (cc in 1:k) {
for (dd in 1:k) {
ans1 = ans1 + (0.45 * X[aa,bb] * X[cc,dd])
for (xx in 1:k) {
for (yy in 1:k){
ans2 = ans2 + (1.7*X[aa,bb]*X[xx,yy]*X[cc,dd] + 0.2*X[aa,xx]*X[bb,yy]*X[cc,dd])
}
}
}
}
}
}
但是必须是方阵的矩阵X
可以有很高的维度。因此,这会大大减慢循环速度。例如X = matrix(rnorm(10000),nrow = 100,byrow = T)
我想知道是否有更短的压缩方法。这将是可读的,最重要的是稍微快一点。我试过 expand.grid
但这没什么用。
例如ans1
library(tidyverse)
an1 <- expand.grid(rep(list(seq(length(X))),2)) %>% arrange_all()
an11 <- t(apply(an1, 1, function(x) as.vector(t(X))[x]))
但是正如我提到的,这并没有提高速度。有什么建议么?我也在想 Rcpp 可能会有所帮助,但我不确定,我还没有尝试过(C++ 语法不是很好)。
for
循环相比,R 中的 for
循环非常慢。
C++ for
循环语法与某些风格的 R 没有太大区别。
我高度怀疑您可以显着压缩代码。但只是按照你非常嵌套的语法:
Rcpp 函数:
//[[Rcpp::export]]
Rcpp::NumericVector foo(Rcpp::NumericMatrix& X) {
Rcpp::NumericVector ans(2);
int k = X.rows();
for (int aa = 0; aa < k; ++aa) {
for (int bb = 0; bb < k; ++bb) {
for (int cc = 0; cc < k; ++cc) {
for (int dd = 0; dd < k; ++dd) {
ans[0] += 0.45 * X[aa, bb] * X[cc, dd]l;
for (int xx = 0; xx < k; ++xx) {
for (int yy = 0; yy < k; ++yy) {
ans[1] += (1.7 * X[aa, bb] * X[xx, yy] * X[cc, dd] + 0.2 * X[aa, xx] * X[bb, yy] * X[cc, dd]);
}
}
}
}
}
}
return ans;
}
R端:
X <- matrix(c(0.5,0,0,0.75), nrow = 2)
ans <- foo(X)
ans1 <- ans[1]
ans2 <- ans[2]
用上面的代码即插即用并不是不优化代码的借口。再次,减少循环次数。你不应该全部都需要。
在看到@user2554330 的回答后(我怀疑是这种情况,但懒得解决),Rcpp 实现不会比 R 实现快得多(我怀疑你是否担心这种边际收益)
你根本不需要使用循环。由于 ans1
和 ans2
的代码只是项的总和,而这些项根本不相互作用,因此表达式简化为
ans1simple <- 0.45*sum(X)^2
ans2simple <- 1.9*sum(X)^3
您可以在随机数据上进行测试。如果您不相信,请更改 X
的种子或大小:
set.seed(123)
X <- matrix(rnorm(9), nrow = 3)
k = nrow(X)
ans1 <- 0
ans2 <- 0
for (aa in 1:k) {
for (bb in 1:k) {
for (cc in 1:k) {
for (dd in 1:k) {
ans1 = ans1 + (0.45 * X[aa,bb] * X[cc,dd])
for (xx in 1:k) {
for (yy in 1:k){
ans2 = ans2 + (1.7*X[aa,bb]*X[xx,yy]*X[cc,dd] + 0.2*X[aa,xx]*X[bb,yy]*X[cc,dd])
}
}
}
}
}
}
ans1simple <- 0.45*sum(X)^2
ans2simple <- 1.9*sum(X)^3
ans1 - ans1simple
#> [1] 2.220446e-16
ans2 - ans2simple
#> [1] -7.993606e-15
由 reprex package (v1.0.0)
于 2021-04-19 创建差异只是舍入误差。