设 A 是一个 n*n 对角矩阵。说,n=5:
A <- diag(1, 5)
A
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 0 1 0 0 0
[3,] 0 0 1 0 0
[4,] 0 0 0 1 0
[5,] 0 0 0 0 1
我需要按行随机化
A
,使 1 远离对角线。我想出了这个解决方案:n <- 5
count <- c(1:n)
for (i in count) {
while (A[count[i], count[i]] == 1) { #avoid 1 in diagonal
A[count[i],] <- sample(A[count[i],]) #permutes ith row
}
}
但我很确定应该有一种更有效的方法来做到这一点。感谢您的关注。
最佳答案
您可以从整数序列 1:n
、 n
次中采样一个随机数,但每次都排除与对角线对应的单元格编号。
一种方法如下:
n <- 5
rnd <- sample(n-1, repl=T)
i <- c(rnd + (rnd >= seq_len(n-1)) * 1, sample(n-1, 1))
i
# [1] 3 3 4 5 1
在这里,防止
i
的每个元素等于元素的索引(例如,元素 1 不能为 1,元素 2 不能为 2 等)。我们可以将 i
的每个元素依次考虑为每一行的选中列。接下来我们设置一个零矩阵,并且(对于上面的示例)将单元格
[1, 3]
、 [2, 3]
、 [3, 4]
、 [4, 5]
和 [5, 1]
填充为 1。m <- matrix(0, nc=n, nr=n)
m[cbind(seq_len(n), i)] <- 1
m
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0 0 1 0 0
# [2,] 0 0 1 0 0
# [3,] 0 0 0 1 0
# [4,] 0 0 0 0 1
# [5,] 1 0 0 0 0
最后一行代码使用矩阵子集将矩阵
m
子集到相关单元格。编辑
为了确保每一列和每一行只有一个
1
,并且它们远离对角线,以下矢量化方法将起作用。这里的技巧是对向量 n-1
进行置换,并将该置换向量的每个元素视为我们将分配给 n-1
的 1
非对角元素的每一行的索引。然后,我们检查置换向量的每个元素的值是否小于相应行的对角线索引。如果是,我们保持元素不变,否则我们加 1。这决定了第一个 n-1
行的列索引。最后一行的索引只是还没有 1
的列的索引。n <- 5
rnd <- sample(n-1)
i <- union(rnd + (rnd >= seq_len(n-1)) * 1, seq_len(n))
m <- matrix(0, nc=n, nr=n)
m[cbind(seq_len(n), i)] <- 1
m
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0 0 1 0 0
# [2,] 0 0 0 0 1
# [3,] 0 0 0 1 0
# [4,] 1 0 0 0 0
# [5,] 0 1 0 0 0
关于r - 随机化二进制对角矩阵的最佳方法,保持 1 不在对角线上,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23384700/