围绕现有值将序列放入矩阵中

Putting a sequence into a matrix around existing values

我想生成一个围绕零对角线的对称矩阵以及围绕它们的预定序列。理论上,这些行应该显示为

0 1 3 5 7 9
1 0 3 5 7 9

我试过调整条件,但我怀疑它因为索引而变得不稳定,我还远没有足够的技能来修复它。

bend <- function(n){
  m <- seq(1, n, by=2)
  a <- length(m)
  y <- matrix(nrow= a, ncol = a, byrow= TRUE)
  y <- ifelse(row(y) == col(y), 0, m)
  y
}

假设输入是 9,预期输出是

0 1 3 5 7 9    
1 0 3 5 7 9 
1 3 0 5 7 9    
1 3 5 0 7 9    
1 3 5 7 0 9    
1 3 5 7 9 0

实际输出为

0 3 5 7 9 1    
3 0 7 9 1 3    
5 7 0 1 3 5    
7 9 1 0 5 7    
9 1 3 5 0 9    
1 3 5 7 9 0

有一种更简单的方法可以满足您的需要。您可以先创建一个包含 length(x) + 1 列和行的 matrix,并将所有元素作为逻辑 TRUE。然后使用 diag() 制作对角线 FALSE。现在您可以将 TRUE 替换为您想要的向量。 FALSE 的对角线不受影响。由于值被替换 column-wise 您需要最终转置 t() 以获得正确的结果。

这样,您就无需担心跟踪索引。

x <- c(1,3,5,7,9)

make_matrix <- function(x) {
  m <- matrix(TRUE, ncol = length(x) + 1, nrow = length(x) + 1)
  diag(m) <- FALSE
  m[m] <- x
  t(m)
}

make_matrix(x)

     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    0    1    3    5    7    9
[2,]    1    0    3    5    7    9
[3,]    1    3    0    5    7    9
[4,]    1    3    5    0    7    9
[5,]    1    3    5    7    0    9
[6,]    1    3    5    7    9    0

这是 sapply 的另一种方式。这会在每次迭代中创建必要的行元素,并将它们按列放入矩阵中。同样,您需要 t() 才能获得正确的结果。 -

sapply(0:length(x), function(a) append(x, 0, after = a)) %>% t()

     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    0    1    3    5    7    9
[2,]    1    0    3    5    7    9
[3,]    1    3    0    5    7    9
[4,]    1    3    5    0    7    9
[5,]    1    3    5    7    0    9
[6,]    1    3    5    7    9    0

基准 -

sapply 较慢,可能是因为它一次创建一行矩阵元素并为每一行调用 appendmake_matrix() 方法避免了所有这些开销。

x <- sample(100)

microbenchmark(
  make_matrix = make_matrix(x),
  sapply = t(sapply(0:length(x), function(a) append(x, 0, after = a))),
  akrun_forloop = {
    n <- length(x) + 1
    m1  <- matrix(0, n, n)
    for(i in seq_len(nrow(m1))) m1[i, -i] <- x
  },
  times = 1000
)

Unit: microseconds
          expr      min        lq      mean   median        uq       max neval
   make_matrix  111.495  117.5610  128.3135  126.890  135.7540   225.323  1000
        sapply  520.620  551.1765  592.2642  573.335  602.2585 10477.221  1000
 akrun_forloop 3380.292 3526.3080 3837.1570 3648.765 3812.5075 20943.245  1000

使用简单的 for 循环

n <- length(x) + 1
m1  <- matrix(0, n, n)
for(i in seq_len(nrow(m1))) m1[i, -i] <- x
m1
#     [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]    0    1    3    5    7    9
#[2,]    1    0    3    5    7    9
#[3,]    1    3    0    5    7    9
#[4,]    1    3    5    0    7    9
#[5,]    1    3    5    7    0    9
#[6,]    1    3    5    7    9    0

数据

x <- c(1,3,5,7,9)