设 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:nn 次中采样一个随机数,但每次都排除与对角线对应的单元格编号。

一种方法如下:

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-11 非对角元素的每一行的索引。然后,我们检查置换向量的每个元素的值是否小于相应行的对角线索引。如果是,我们保持元素不变,否则我们加 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/

10-10 22:29
查看更多