我想根据一个函数按行填充矩阵,该函数给出数字 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
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 似乎比其他解决方案更快。
–
-
有道理。
dim
和rep
都很快,但它还需要两个rbind
s。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
replace
m
根据掩码指标替换值
或者,如果你想要按行进行操作
> 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,使用
|
seq()
?您可以使用 R 的矩阵代数能力非常轻松地创建该矩阵 – 将所有 1 的行向量乘以 1-6 的列向量,matrixinp <- rep(1,6) %*% t(1:6)
得到全 1 列、全 2 列等(),然后使用matrixinp[upper.tri(matrixinp)] <- NA
将上三角设置为 NA。–
–
–
|