【问题标题】:Replacing part of a triangle matrix by a vector用向量替换三角矩阵的一部分
【发布时间】:2020-07-23 08:05:51
【问题描述】:

我有v<- c(2,4,5)mat<- matrix(0,n,n)。 我想替换矩阵上部的向量,我识别的每个地方,数组都替换为向量的长度数。例如,对于 n=5,输出可以是:

       [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    4    0    0
[2,]    0    0    5    0    0
[3,]    0    0    0    0    0
[4,]    0    0    0    0    0
[5,]    0    0    0    0    0

我尝试使用以下代码:

mat <- matrix(0, nrow = 5, ncol = 5)
for (i in 1:5){
  for (j in 1:5){
    if (i<j & j<= 5){
      mat [upper.tri(mat, diag = FALSE)]<- v
    }
  }
}

但输出是:

       [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    4    2    2
[2,]    0    0    5    4    4
[3,]    0    0    0    5    5
[4,]    0    0    0    0    2
[5,]    0    0    0    0    0

我有两个问题:

  1. 我希望向量在矩阵中只替换一次,不要重复。

  2. 我不知道我必须在循环中的哪里替换 i 和 j 以替换矩阵的起点来替换向量。(也许我想从矩阵中的 [3,4] 开始向量。) .例如:

      [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    0    0    0
[2,]    0    0    0    0    0
[3,]    0    0    0    2    4
[4,]    0    0    0    0    5
[5,]    0    0    0    0    0

【问题讨论】:

    标签: r matrix vector replace


    【解决方案1】:

    当您从向量填充矩阵时,需要了解两件事:

    1. 它按列填充它们;和
    2. 如果向量比要填充的矩阵部分短,则向量将被回收(重复)。

    此外,在您的代码中,您使用了两个嵌套的 for 循环,其明显意图是仅对矩阵中的这些索引进行操作......但是您没有在矩阵子集或赋值,所以每次它尝试替换单个值时,它都会用整个向量替换整个矩阵 upper-tri。

    这是一种更快的方法:

    mat <- matrix(0, nrow = 5, ncol = 5)
    v <- c(2, 4, 5)
    mat[upper.tri(mat)][seq_along(v)] <- v
    mat
    #      [,1] [,2] [,3] [,4] [,5]
    # [1,]    0    2    4    0    0
    # [2,]    0    0    5    0    0
    # [3,]    0    0    0    0    0
    # [4,]    0    0    0    0    0
    # [5,]    0    0    0    0    0
    

    如您所知,mat 上的第一个索引是上三角形。第二个子集只是该子集的length(v)

    如果你想在上三角形的任意位置替换它,这里有一个镜头:

    mat <- matrix(0, nrow = 5, ncol = 5)
    ut <- upper.tri(mat)
    fullv <- integer(sum(ut)) # the size of the matrix subset
    fullv
    #  [1] 0 0 0 0 0 0 0 0 0 0
    fullv[5 + seq_along(v)] <- v
    fullv
    #  [1] 0 0 0 0 0 2 4 5 0 0
    mat[ut] <- fullv
    mat
    #      [,1] [,2] [,3] [,4] [,5]
    # [1,]    0    0    0    0    4
    # [2,]    0    0    0    0    5
    # [3,]    0    0    0    2    0
    # [4,]    0    0    0    0    0
    # [5,]    0    0    0    0    0
    

    这里我们展示了填充是按列完成的,这不是您所要求的。为了更好地了解这种填充是如何发生的,

    mat <- matrix(0, nrow = 5, ncol = 5)
    ut <- upper.tri(mat)
    mat[ut] <- seq_len(sum(ut))
    mat
    #      [,1] [,2] [,3] [,4] [,5]
    # [1,]    0    1    2    4    7
    # [2,]    0    0    3    5    8
    # [3,]    0    0    0    6    9
    # [4,]    0    0    0    0   10
    # [5,]    0    0    0    0    0
    

    因此,如果您希望您的 v 位于非常具体的位置,并且按照此顺序它们不是连续的,那么您需要具体:

    mat <- matrix(0, nrow = 5, ncol = 5)
    ut <- upper.tri(mat)
    mat[ut][c(6,9,10)] <- v
    mat
    #      [,1] [,2] [,3] [,4] [,5]
    # [1,]    0    0    0    0    0
    # [2,]    0    0    0    0    0
    # [3,]    0    0    0    2    4
    # [4,]    0    0    0    0    5
    # [5,]    0    0    0    0    0
    

    【讨论】:

    • 只需使用不同的子向量再次执行第三个代码块。例如,如果您先执行mat[ut][c(1,2,3)] &lt;- v,则执行mat[ut][c(6,9,10)] &lt;- c(8,9,10)
    【解决方案2】:

    您可以计算出长度为n 向量的每个元素的{r,c} 索引(您还需要适合此类向量所需的正方形三角形的尺寸。

    例如,对于从 {3,4} 开始的长度为 3 的向量(假设 R 中的列优先),您将需要索引

    i r c
    1 3,4
    
    2 3,5
    3 4,5
    
    4 3,6
    5 4,6
    6 5,6
    ...
    

    您可能已经看到了这些模式。对于行,有一个通用的 r 函数,它给出了模式3 3 4 3 4 5 ...,即sequence,特别是sequence(1:3) + 2

    接下来,4 5 5 6 6 6 ... 中的列有一个更简单的解决方案,即 rep(1:3, 1:3) + 3,因此我们可以将这两者结合起来以获得向量中每个元素的索引。

    ## use 1:(n - 1) for a length n vector
    mat <- matrix(0, 5, 5)
    v <- c(2, 4, 5)
    i <- cbind(sequence(1:2) + (3 - 1), rep(1:2, 1:2) + (4 - 1))
    mat[i] <- v
    mat
    
    #      [,1] [,2] [,3] [,4] [,5]
    # [1,]    0    0    0    0    0
    # [2,]    0    0    0    0    0
    # [3,]    0    0    0    2    4
    # [4,]    0    0    0    0    5
    # [5,]    0    0    0    0    0
    

    你可以在上面的代码中看到你的起始位置,所以我们可以概括这个逻辑:

    f <- function(matrix, vector = 1:3, start = c(1, 1)) {
      i <- sequence(rep(1:nrow(matrix), 1:ncol(matrix))[length(vector)])
      i <- cbind(
        sequence(i) + start[1] - 1,
        rep(i, i) + start[2] - 1
      )
      ## recycle vector so there are no incompatible length errors
      matrix[i] <- rep_len(vector, nrow(i))
    
      matrix
    }
    
    mat <- matrix(0, 5, 5)
    f(mat, v, c(3, 4))
    f(mat, v, c(2, 2))
    f(mat, c(2, 4, 5), c(1, 1))
    f(mat, c(v, v), c(1, 1))
    f(mat, c(v, v, v), c(1, 2))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-19
      • 1970-01-01
      • 1970-01-01
      • 2016-10-03
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多