【问题标题】:Create a matrix with gradually changing values without a for loop创建一个值逐渐变化的矩阵,而不使用 for 循环
【发布时间】:2015-02-06 12:14:43
【问题描述】:

在 R 中,我正在构建一个矩阵 M,它为 20 轮游戏中的每一轮存储 4 个变化的权重。

我从权重向量W1 (4x1) 开始,以权重向量W2 (4x1) 结束游戏。

在更改启动轮 C1 (=5) 之前,权重值保持不变。

在一轮 C1 之后,权重开始以相等的增量 w2cw3cC (=10) 轮上发生变化。

权重必须始终添加到1

我使用for 循环来构建矩阵M。结果如下所示:

      [,1] [,2] [,3] [,4]
 [1,] 0.30 0.50 0.10 0.10
 [2,] 0.30 0.50 0.10 0.10
 [3,] 0.30 0.50 0.10 0.10
 [4,] 0.30 0.50 0.10 0.10
 [5,] 0.30 0.50 0.10 0.10
 [6,] 0.28 0.46 0.12 0.14
 [7,] 0.26 0.42 0.14 0.18
 [8,] 0.24 0.38 0.16 0.22
 [9,] 0.22 0.34 0.18 0.26
[10,] 0.20 0.30 0.20 0.30
[11,] 0.18 0.26 0.22 0.34
[12,] 0.16 0.22 0.24 0.38
[13,] 0.14 0.18 0.26 0.42
[14,] 0.12 0.14 0.28 0.46
[15,] 0.10 0.10 0.30 0.50
[16,] 0.10 0.10 0.30 0.50
[17,] 0.10 0.10 0.30 0.50
[18,] 0.10 0.10 0.30 0.50
[19,] 0.10 0.10 0.30 0.50
[20,] 0.10 0.10 0.30 0.50

这是我的 R 代码:

输入:

N=4 # 4 number of weights
R=20 #rounds
M <- matrix(0, ncol=N, nrow=R) 
C=10 # change duration in rounds
C1=5 # round at which change starts
C2=C1+C # round at which change ends
w1=0.1 #small weight
w2=0.3 #average weight
w3=0.5 #large weight
w2c=(w2-w1)/C #change increment for average weight mutation
w3c=(w3-w1)/C #change increment for large weight mutation
W1<-c(w2, w3, w1, w1) #starting weight vector
W2<-c(w1, w1, w2, w3) #ending weight vector 

for循环,构建矩阵M

for(n in 1:N){
  M[,n]<-W1[n]
  for(r in 1:R) {
    if(r>=C2){M[r,n] <- W2[n]}
  }
}

for(r in C1:(C2-1)) {
  T<-r-C1;
  M[r,1] =  M[r,1]-w2c*T;
  M[r,2] =  M[r,2]-w3c*T;
  M[r,3] =  M[r,3]+w2c*T;
  M[r,4] =  M[r,4]+w3c*T;
}
M

没有for 循环,有没有更有效的方法来实现相同的结果?

【问题讨论】:

    标签: r for-loop matrix vector s


    【解决方案1】:

    分别填充顶部、中间和底部的三个调用:

    M[1:C1,  ] <- rep(W1, each = C1)
    M[C1:C2, ] <- mapply(seq, from = W1, to = W2, length = C2 - C1 + 1)
    M[C2:R,  ] <- rep(W2, each = R - C2 + 1)
    

    如果您像我一样喜欢非常对称(或一致)的代码,您可以概括并说顶部和底部就像中间部分:它们从W1 线性移动到W1 并从@分别为 987654324@ 至 W2。因此:

    M[1:C1,  ] <- mapply(seq, from = W1, to = W1, length = C1 -  1 + 1)
    M[C1:C2, ] <- mapply(seq, from = W1, to = W2, length = C2 - C1 + 1)
    M[C2:R,  ] <- mapply(seq, from = W2, to = W2, length =  R - C2 + 1)
    

    【讨论】:

    • 我很欣赏您的解决方案的对称性和视觉清晰度。特别是,如果W1W2 长度或其他值发生变化(例如R、C、C1),则不需要修改。
    【解决方案2】:

    您可以将权重乘以更改时间步数,然后将这些向量添加到更改前的值(例如使用sweep)。

    x <- rbind(c(0.30, 0.50, 0.10, 0.10))
    M <- rbind(x[rep(1, C1), ],
               sweep( sapply(c(-w2c, -w3c, w2c, w3c), '*', seq_len(C)),
                        2, x, '+'))
    M <- rbind(M, M[ nrow(M), , drop=FALSE][ rep(1, R-C1-C), ])
    
    #       [,1] [,2] [,3] [,4]
    #  [1,] 0.30 0.50 0.10 0.10
    #  [2,] 0.30 0.50 0.10 0.10
    #  [3,] 0.30 0.50 0.10 0.10
    #  [4,] 0.30 0.50 0.10 0.10
    #  [5,] 0.30 0.50 0.10 0.10
    #  [6,] 0.28 0.46 0.12 0.14
    #  [7,] 0.26 0.42 0.14 0.18
    #  [8,] 0.24 0.38 0.16 0.22
    #  [9,] 0.22 0.34 0.18 0.26
    # [10,] 0.20 0.30 0.20 0.30
    # [11,] 0.18 0.26 0.22 0.34
    # [12,] 0.16 0.22 0.24 0.38
    # [13,] 0.14 0.18 0.26 0.42
    # [14,] 0.12 0.14 0.28 0.46
    # [15,] 0.10 0.10 0.30 0.50
    # [16,] 0.10 0.10 0.30 0.50
    # [17,] 0.10 0.10 0.30 0.50
    # [18,] 0.10 0.10 0.30 0.50
    # [19,] 0.10 0.10 0.30 0.50
    # [20,] 0.10 0.10 0.30 0.50
    

    【讨论】:

    • 希望您不介意格式编辑。我在精神上无法解析原件。很不错的答案。我想返回 rbind()-ed 结果的 Reduce( . , . ) 策略可能有效,但我怀疑它会提高清晰度或性能。
    • @jbaums,这是一个非常好的解决方案!我更喜欢@flodel 的答案的唯一原因是我可以轻松地将其扩展到更复杂的场景。例如,如果我们添加在 R 轮中保持不变的第 5 个权重(M 中的第 5 列),据我所知,代码应按以下方式修改:x &lt;- rbind(c(0.30, 0.50, 0.1,0.1, 0.1, 0.1));M &lt;- rbind(x[rep(1, C1), ], sweep( sapply(c(-w2c, -w3c, w2c, w3c, 0), '*', seq_len(C)), 2, x, '+'));M &lt;- rbind(M, M[ nrow(M), , drop=FALSE][ rep(1, R-C1-C), ])
    • @inarts - 当然,没问题。我也更喜欢弗洛德尔的回答!我没有意识到我们可以使用最终的重量。是的,你的修改是正确的。 :)
    猜你喜欢
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 2021-05-28
    • 2017-11-22
    • 1970-01-01
    相关资源
    最近更新 更多