【问题标题】:Crossed for loops: Pick i th element of first loop then loop completely through second loop交叉 for 循环:选择第一个循环的第 i 个元素,然后完全循环通过第二个循环
【发布时间】:2014-08-28 05:00:30
【问题描述】:

假设我有以下代码:

    X    <- model.matrix(~factor(1:2))
    beta <- c(1, 2)

然后我从两个多元正态分布中抽取 70 和 40 个值:

    library(MASS)
    S1 <- mvrnorm(70, mu = c(0,0), Sigma = matrix(c(10, 3, 3, 2), ncol = 2))
    S2 <- mvrnorm(40, mu = c(0,0), Sigma = matrix(c(10, 4, 4, 2), ncol = 2))

很容易看出S170x2 矩阵和S2 一个40x2 矩阵。

现在我在 R 中构建一个 for 循环:

    z <- list()
    for(i in 1:dim(S2)[1]){
        z[[i]] <- X %*% beta + X %*% S1[1,] + X %*% S2[i,] + rnorm(2, mean = 0, sd = 0.45)
    Y <- do.call(rbind, z)
    }

这给了我一个矩阵,其中包含S2 中的40 元素与S11st 元素的所有组合。我想要的是完全跨越S1S2 这两个矩阵。也就是说,我希望 for 循环首先挑选出S1[1,],然后完全遍历S2[i,](例如在内部循环中)并将结果存储在矩阵中,然后挑选出S1[2,] 再次遍历S2[i,] 并存储结果在矩阵中等等。如果我需要给我正在寻找的东西命名,我会说"crossed for loops"。我发现很难想出允许我这样做的R-code。任何提示将不胜感激。


也许这个例子会让这个想法变得更清晰:

我的想法相当于为S1[i,] 中的每个元素构造70 个for-loops 并将结果绑定到70*40*2x1 矩阵中:

    for(i in 1:dim(S2)[1]){
    z[[i]] <- X %*% beta+X %*% S1[1,]+X %*% S2[i,]+rnorm(2, mean = 0 , sd = sigma)
    Y1 <- unname(do.call(rbind, z))
    }

    for(i in 1:dim(S2)[1]){
    z[[i]] <- X %*% beta+X %*% S1[2,]+X %*% S2[i,]+rnorm(2, mean = 0 , sd = sigma)
    Y2 <- unname(do.call(rbind, z))
    }

    for(i in 1:dim(S2)[1]){
    z[[i]] <- X %*% beta+X %*% S1[3,]+X %*% S2[i,]+rnorm(2, mean = 0 , sd = sigma)
    Y3 <- unname(do.call(rbind, z))
    }

    .
    .
    .

    for(i in 1:dim(S2)[1]){
    z[[i]] <- X %*% beta+X %*% S1[70,]+X %*% S2[i,]+rnorm(2, mean = 0 , sd = sigma)
    Y70 <- unname(do.call(rbind, z))
    }

    Y <- rbind(Y1, Y2, Y3, …, Y70)

我最理想的做法是使用for-loops 或任何其他可以处理S1S2 不同维度的灵活方式。

【问题讨论】:

  • 您的示例不是complete or reproducible,因此很难准确回答。似乎您可以在这里使用outer,但不清楚您期望的结果是什么(假设您的代码不可运行)。
  • 很抱歉。该示例现在应该可以重现了。
  • 是的,我想我在文中提到了这一点:“将结果存储在矩阵中”。但我可能不清楚。理想情况下,输出将是一个矩阵。我考虑在每次通过S2[j,] 迭代后连接每个S1[i,], i = 1, …, 70 的矩阵以形成一个大矩阵。
  • 它应该是一个(70*40*2)x2 = 5600x2-矩阵:70 := number of elements in S140 := number of elements in S22 := number of rows in X
  • 是的,对不起,我的速度这么慢,半决赛明天开始。

标签: r for-loop


【解决方案1】:

好的。我可能会做一些事情来使其尽可能高效。首先,我们可以预先计算所有的矩阵乘法

Xb <- X %*% beta
XS1 <- X %*% t(S1)
XS2 <- X %*% t(S2)

然后我们可以用expand.grid计算所有S1/S2值的组合

idx <- unname(c(expand.grid(A=1:ncol(XS1), B=1:ncol(XS2))))

然后我们可以定义转换

fx<-function(a, b) {
    t(Xb + XS1[,a, drop=F] + XS2[,b,drop=F] + rnorm(2, mean = 0, sd = 0.45))
}

我们假设我们将传递一个 S1 的索引和一个 S2 的索引。然后我们按照您的公式合并数据。最后,我们使用这个辅助函数和带有一组do.calls 的索引

xx <- do.call(rbind, do.call(Map,c(list(fx), idx)))

首先我们使用Map 来计算所有的组合,然后我们使用rbind 来合并所有的结果。这实际上产生了一个 2800x2 矩阵。 (70*40)*2。行的顺序是 S1 移动最快,然后是 S2。

【讨论】:

    【解决方案2】:

    我意识到这不是for-loops 的问题,而是我存储变量的方式。我想要的解决方案是:

    library(MASS)
    z <- list()
    y <- list()
    for(j in 1:dim(S1)[1]){
        for(i in 1:dim(S2)[1]){
            z[[i]] <- X %*% beta+X %*% S1[j,]+X %*% S2[i,]+matrix(rnorm(2, mean = 0 , sd = sigma), ncol = 2, nrow = 2)
            Z <- unname(do.call(rbind, z))
        }
            y[[j]] <- Z
            Y <- unname(do.call(rbind, y))
    }
    

    【讨论】:

      猜你喜欢
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-03
      • 2014-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多