我想根据一个函数按行填充矩阵,该函数给出数字 seq(1) 1 seq(2) 1 2 等等的 seq()

    matrixinp = matrix(data=NA, nrow=6, ncol=6) 

> print(matrixinp) 
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]   NA   NA   NA   NA   NA   NA
[2,]   NA   NA   NA   NA   NA   NA
[3,]   NA   NA   NA   NA   NA   NA
[4,]   NA   NA   NA   NA   NA   NA
[5,]   NA   NA   NA   NA   NA   NA
[6,]   NA   NA   NA   NA   NA   NA
    
    # display matrix 
    print(matrixinp) 
    
    # fill the elements with some  
    # 90 in a matrix 
    for (i in 1:6){
      aaa<-seq(i)
      print(aaa)
      for(j in 1:6){ 
        matrixinp[j,] = aaa
      } 
    }

这给了我这个:

> print(matrixinp)
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    2    3    1    2    3
[2,]    1    2    3    1    2    3
[3,]    1    2    3    1    2    3
[4,]    1    2    3    1    2    3
[5,]    1    2    3    1    2    3
[6,]    1    2    3    1    2    3

但我想要这个:

> print(matrixinp)
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    NA   NA   NA   NA   NA
[2,]    1    2    NA   NA   NA   NA
[3,]    1    2    3    NA   NA   NA
[4,]    1    2    3    4    NA   NA
[5,]    1    2    3    4    5    NA
[6,]    1    2    3    4    5    6

3

  • 1
    您是否特别需要使用循环和来执行此操作seq()?您可以使用 R 的矩阵代数能力非常轻松地创建该矩阵 – 将所有 1 的行向量乘以 1-6 的列向量,matrixinp <- rep(1,6) %*% t(1:6)得到全 1 列、全 2 列等(),然后使用matrixinp[upper.tri(matrixinp)] <- NA将上三角设置为 NA。


    – 


  • @TiredSquirrel 愿意发表答案吗?


    – 

  • @RuiBarradas – 完成了!谢谢!


    – 


8 个解决方案
8

我敢打赌一行代码就能解决这个问题,R 是一种矢量化语言。

matrixinp <- matrix(data=NA, nrow=6, ncol=6)
matrixinp[lower.tri(matrixinp, diag = TRUE)] <- rep(1:6, 6:1)

matrixinp
#>      [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,]    1   NA   NA   NA   NA   NA
#> [2,]    1    2   NA   NA   NA   NA
#> [3,]    1    2    3   NA   NA   NA
#> [4,]    1    2    3    4   NA   NA
#> [5,]    1    2    3    4    5   NA
#> [6,]    1    2    3    4    5    6

创建于 2024-09-17,使用

等一下,我打赌赢了。

诀窍是要知道 R 的矩阵是列主序的,因此使用索引矩阵,
lower.tri值将放在正确的位置。

2

  • 是的,一个简单的赌注(+1)。


    – 

  • 1
    很酷!!!但这取决于你如何计算,从技术上讲,这可能是两行代码。下面是(丑陋的)真正的一行代码,只是为了证明这是可以做到的:matrixinp <- ifelse(lower.tri(matrix(nrow=6,ncol=6),diag=T),rep(1,6) %*% t(1:6),NA)


    – 


作为函数:

f <- function(n) `dim<-`(rep(rbind(NA, 1:n), rbind(0:(n - 1), n:1)), c(n, n))
f(6)
#>      [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,]    1   NA   NA   NA   NA   NA
#> [2,]    1    2   NA   NA   NA   NA
#> [3,]    1    2    3   NA   NA   NA
#> [4,]    1    2    3    4   NA   NA
#> [5,]    1    2    3    4    5   NA
#> [6,]    1    2    3    4    5    6
f(10)
#>       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#>  [1,]    1   NA   NA   NA   NA   NA   NA   NA   NA    NA
#>  [2,]    1    2   NA   NA   NA   NA   NA   NA   NA    NA
#>  [3,]    1    2    3   NA   NA   NA   NA   NA   NA    NA
#>  [4,]    1    2    3    4   NA   NA   NA   NA   NA    NA
#>  [5,]    1    2    3    4    5   NA   NA   NA   NA    NA
#>  [6,]    1    2    3    4    5    6   NA   NA   NA    NA
#>  [7,]    1    2    3    4    5    6    7   NA   NA    NA
#>  [8,]    1    2    3    4    5    6    7    8   NA    NA
#>  [9,]    1    2    3    4    5    6    7    8    9    NA
#> [10,]    1    2    3    4    5    6    7    8    9    10

2

  • 对于维度大于 10 或 12 的矩阵,这是最快的。对于较小的维度,TiredSquirrel 似乎比其他解决方案更快。


    – 


  • 有道理。dimrep都很快,但它还需要两个rbinds。TiredSquirrel 可以使用 来加速,tcrossprod(rep(1,6), 1:6)而不是rep(1,6) %*% t(1:6)


    – 

你可以尝试

> replace(m <- diag(1:6) * NA, lower.tri(m, TRUE), rep(1:6, 6:1))
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1   NA   NA   NA   NA   NA
[2,]    1    2   NA   NA   NA   NA
[3,]    1    2    3   NA   NA   NA
[4,]    1    2    3    4   NA   NA
[5,]    1    2    3    4    5   NA
[6,]    1    2    3    4    5    6

在哪里

  • diag(1:6)*NA产生一个6-by-6矩阵NA
  • lower.tri检索下三角部分m
  • replacem根据掩码指标替换值

或者,如果你想要按行进行操作

> do.call(rbind, lapply(1:6, \(k) `length<-`(seq.int(k), 6)))
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1   NA   NA   NA   NA   NA
[2,]    1    2   NA   NA   NA   NA
[3,]    1    2    3   NA   NA   NA
[4,]    1    2    3    4   NA   NA
[5,]    1    2    3    4    5   NA
[6,]    1    2    3    4    5    6

在哪里

  • `length<-`将长度设置为给定的向量
  • do.call(rbind, ...)按行将向量堆叠在列表中

3

  • 请考虑添加一段解释,说明这段代码的作用。这些富有创意的单行代码很棒,但我们正在处理一个新用户的问题,他正在学习 R,如果他们能从中学到一些东西就好了。另外,我真的想知道你的第二个例子在做什么,你使用的方式让我困惑`length<-`


    – 


  • 1
    @TiredSquirrel 说得好!请参阅我的评论


    – 

  • 太棒了!我没有意识到length可以与赋值一起使用来截断向量 – 谢谢你的解释!


    – 


1)创建一个 6×6 的对角矩阵,用列号填充它,然后 NA 出上三角。

library(magrittr)
diag(6) %>% col() %>% { ifelse(row(.) < ., NA, .) }

给予

     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1   NA   NA   NA   NA   NA
[2,]    1    2   NA   NA   NA   NA
[3,]    1    2    3   NA   NA   NA
[4,]    1    2    3    4   NA   NA
[5,]    1    2    3    4    5   NA
[6,]    1    2    3    4    5    6

2)或者使用本机管道:

diag(6) |> col() |> list(x = _) |> with(ifelse(row(x) < x, NA, x))

3)将 cc 定义为 6×6 矩阵,其列号如上,然后使用所示的公式。

cc <- col(diag(6))
cc * NA ^ (cc > t(cc))

您可以尝试以下操作,

# Create an empty 6x6 matrix
matrixinp <- matrix(data=NA, nrow=6, ncol=6)

# Fill the matrix row by row
for (i in 1:6) {
  matrixinp[i, 1:i] <- seq(i)
}

# Display the matrix
print(matrixinp)

保留初始创建的空矩阵,其中包含 NA 值。使用单个循环遍历行(1 到 6)。对于每一行 i,我们仅使用序列 seq(i) 填充前 i 列。每行中的其余元素保持初始设置的 NA。

该方法确保每行都具有直到其行号的序列,其余部分保持为 NA。

您是否特别需要使用循环来执行此操作seq()

你可以利用 R 的矩阵代数功能轻松地创建该矩阵:

# Multiply a row vector of all 1s by a column vector of 1-6
matrixinp <- rep(1,6) %*% t(1:6)

# You have a matrix with an all-1s column, and all-2s column, etc. - now set the upper triangle to NA
matrixinp[upper.tri(matrixinp)] <- NA

但如果你想了解为什么你的循环不起作用:

    for (i in 1:6){
      aaa<-seq(i)
      print(aaa)
      for(j in 1:6){ 
        matrixinp[j,] = aaa
      } 
    }

运行时,seq(4)您会得到一个长度为 4 的向量c(1,2,3,4)。然后您尝试将其分配给的每一行,但该矩阵中的行长度为 6 个元素。当您进行循环的第 4 次迭代时,matrixinp该分配将失败并出现错误。number of items to replace is not a multiple of replacement length

在进行第 4 次迭代之前,6 是 1、2 和 3 的倍数,因此对于那些迭代,R 会用 aaa 向量的重复填充矩阵:

  • 当i=1时aaa=1,它用填充矩阵行c(1,1,1,1,1,1)
  • 当 i=2 时,aaa=c(1,2)它用 填充矩阵行c(1,2,1,2,1,2)
  • 当i=3时aaa=c(1,2,3),它用填充矩阵行c(1,2,3,1,2,3)
  • 当 i=4 时,它会因错误而停止,而不是填充矩阵。

这就是为什么你会得到那个奇怪的矩阵,其中每一行都是 1 2 3 1 2 3 – 当 i=3 时,内部循环将 j 分配c(1,2,3,1,2,3)给矩阵的每一行。然后你的循环在 i=4 处遇到错误时停止,只剩下 i=3 版本的矩阵。

1

  • 明白了,难怪我会收到这个错误,谢谢


    – 

为了帮助原始提问者理解,以下是我在给 RuiBarradas 的评论中写的一句话:

matrixinp <- ifelse(lower.tri(matrix(nrow=6,ncol=6),diag=T),rep(1,6) %*% t(1:6),NA)

这是混乱而过于复杂的代码,因为它很愚蠢,试图在一行中完成所有操作。通常,您不应该在实际代码中这样做,这会让其他人难以阅读代码(或者几个月后您再次查看时难以阅读)。但它确实展示了 R 的一些有用功能,并且尝试这样的事情有时可以帮助您更多地了解 R。

最好从外向内阅读此代码,例如从最外层的函数开始:

  • ifelse()是一个检查其第一个参数是否为真的函数 – 如果是,则返回其第二个参数,否则返回其第三个参数。

    • 所以ifelse(c(T,F,T,F),'A','B')会回来c('A','B','A','B')
  • 我给出的第一个参数ifelse()lower.tri(matrix(nrow=6,ncol=6),diag=T),一个 TRUE/FALSE 值矩阵,表示 6×6 矩阵中的哪些单元格位于下三角(包括对角线为“在下三角”)
  • 我给出的第二个参数是rep(1,6) %*% t(1:6),来自我对你的问题的另一个回答的矩阵代数,它创建一个列全为 1 的矩阵,列全为 2 的矩阵,等等。

    • 这部分实际上是在 R 中创建 1 列、2 列等矩阵的好方法,我这样做并不是在开玩笑。R 针对矩阵代数运算进行了优化,速度非常快,因此矩阵代数解决方案通常是最快的。
  • 我给出的第三个论点是 NA

因此,此代码检查 6×6 矩阵的每个单元格是否位于下三角。如果是,它会从矩阵中获取该单元格的值,该单元格的列为全 1、全 2 等。但如果位于上三角,它会将该单元格设置为 NA。

我的第二句台词是:(!upper.tri(diag(6)) | NA) * (rep(1,6) %*% t(1:6))

  • 再说一遍,这是愚蠢的代码,不要真的这么做
  • 要理解这一点,需要将其分解为几个部分 – 它是两个矩阵的元素乘积,一个由 创建(!upper.tri(diag(6)) | NA),另一个由(rep(1,6) %*% t(1:6))
  • 左边的矩阵使用 R 的处理方法和/或逻辑创建一个在下三角为 TRUE、在上三角为 NA 的矩阵。

    • diag(6)创建一个 6×6 矩阵,对角线上为 1,其余部分为 0。其目的只是以比 更短的方式创建一个 6×6 矩阵matrix(nrow=6,ncol=6)
    • !upper.tri(diag(6))使用upper.tri()该矩阵创建一个矩阵,其中上三角(不包括对角线)为 TRUE,下三角为 FALSE。然后它使用!(“非”运算符)将 TRUE 转换为 false,反之亦然。

      • 我也可以写成lower.tri(diag(6),diag=T)制作相同的 T/F 矩阵,但由于这要求diag=T矩阵包含对角线,因此写起来更短(尽管可读性较差)!upper.tri(diag(6))
    • 最后,整个左矩阵:(!upper.tri(diag(6)) | NA)。我取该 T/F 矩阵,并与 NA 进行逻辑“或”。“真或 NA”计算结果为“真”,而“假或 NA”计算结果为 NA。
  • 左边的矩阵与我在其他答案中使用的基于矩阵代数的方法相同,该方法创建了全 1 列、全 2 列等的矩阵。
  • 当我逐个元素地将真值和 NA 矩阵与全 X 列矩阵相乘时,R 会将值 TRUE 转换为 1(如果存在任何 FALSE,它还会将值 FALSE 转换为 0)。因此,对于下半部分,我乘以 1*1、1*2、1*3 等。对于上半部分,我乘以 NA、NA*1、NA*2 等,结果为 NA。

6

  • ifelse()当完整的矢量化解决方案也不超过一行时,为什么要使用它呢?


    – 


  • 正在进行中 – 仍在尝试提出更好的单行代码,这只是第一个。对于完全矢量化且不跨越多行,您有什么想法?


    – 

  • 它已经存在了:


    – 

  • 从技术上讲,这是两行,第一行创建全 NA 矩阵。;-) 但是我现在有一个(非常丑陋的)真正的单行代码,可以避免 ifelse():(!upper.tri(diag(6)) | NA) * (rep(1,6) %*% t(1:6))


    – 


  • 1
    重点不在于争论,重点在于以创造性的方式使用 R 功能,用尽可能少的行来完成这项工作。无论是 2 行还是 1 行实际上并不重要,重点在于看看你可以用 R 做什么,从而获得乐趣。


    – 


这是我的:


# For a `k` between `0` and `n-1`, create a list with `n` vectors
# each containing `k` `NA_integer_` values and `n-k` numbers `i+1`
# then simplify it into a matrix.

n <- 6
matrixinp <- sapply(0:(n-1), \(i) c(rep.int(NA_integer_, i), rep.int(i + 1, n - i)))

matrixinp
#>      [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,]    1   NA   NA   NA   NA   NA
#> [2,]    1    2   NA   NA   NA   NA
#> [3,]    1    2    3   NA   NA   NA
#> [4,]    1    2    3    4   NA   NA
#> [5,]    1    2    3    4    5   NA
#> [6,]    1    2    3    4    5    6

创建于 2024-09-18,使用