создайте матрицу n * n из матрицы n-1 * n, добавив диагональные элементы как 1 в R

#r #matrix

#r #матрица

Вопрос:

Например, у меня есть матрица 2 * 3

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

Я хочу иметь матрицу 3 * 3, вставляющую 1 по диагонали в R
Вывод :

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

Ответ №1:

Одним из вариантов может быть:

 mat_new <- `diag<-`(matrix(ncol = ncol(mat), nrow = nrow(mat)   1, 0), 1)
mat_new[mat_new == 0] <- mat

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

Или вариацию оригинальной идеи (предложенной @Henrik):

 mat_new <- diag(ncol(mat))
mat_new[mat_new == 0] <- mat
  

Пример данных:

 mat <- structure(2:7, .Dim = 2:3, .Dimnames = list(c("[1,]", "[2,]"), 
    NULL))
  

Ответ №2:

Используя append .

 unname(mapply(function(x, y) append(x, 1, y), as.data.frame(m), 1:ncol(m) - 1))

#      [,1] [,2] [,3]
# [1,]    1    4    6
# [2,]    2    1    7
# [3,]    3    5    1
  

Или используя replace .

 replace(diag(3), diag(3) < 1, m)
#      [,1] [,2] [,3]
# [1,]    1    4    6
# [2,]    2    1    7
# [3,]    3    5    1
  

Данные:

 m <- structure(2:7, .Dim = 2:3)
  

Ответ №3:

В случае вашей матрицы вы могли бы поиграть с верхней и нижней матрицами. Я включаю код, который может быть полезен:

 #Input matrix
A <- matrix(c(2,4,6,3,5,7),nrow = 2,ncol = 3,byrow = T)

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


#Output matrix
B <- matrix(0,nrow = 3,ncol = 3)

     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    0    0    0
[3,]    0    0    0
  

Теперь мы заменим:

 #Replace
B[upper.tri(B)] <- A[upper.tri(A)] 
B[lower.tri(B)] <- A[lower.tri(A,diag = T)]
diag(B) <- 1
#Final output
B
  

Результат:

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

Комментарии:

1. Вы можете создать B <- diag(max(nrow(A), ncol(A))) и избежать назначения единиц в конце.

2. @RuiBarradas Большое спасибо за ваш комментарий. Это отличное предложение. Я добавил в конце, чтобы код мог быть более усвояемым для OP.

Ответ №4:

Я просто сравниваю функции, приведенные в предыдущих ответах:

 add_diagonal <- function(mat) {
  res <- diag(ncol(mat))
  res[res == 0] <- mat
}

add_diagonal_1 <- function(mat) {
  n <- max(dim(mat))
  res <- matrix(0, nrow=n, ncol=n)
  res[upper.tri(res)] <- mat[upper.tri(mat)]
  res[lower.tri(res)] <- mat[lower.tri(mat)]
  diag(res) <- 1
  res
}

add_diagonal_2 <- function(mat) {
  n <- max(dim(mat))
  replace(diag(n), diag(n) < 1, mat)
}

add_diagonal_3 <- function(mat) {
  unname(mapply(function(x, y) append(x, 1, y), as.data.frame(mat), 1:ncol(mat) - 1))
}

require(microbenchmark)

A <- matrix(c(2,4,6,3,5,7),nrow = 2,ncol = 3,byrow = T)

microbenchmark(add_diagonal(A), add_diagonal_1(A), add_diagonal_2(A), add_diagonal_3(A), times=10000)
  

Результат:

 Unit: microseconds
              expr     min       lq      mean   median       uq       max neval
   add_diagonal(A)   8.569  10.3865  13.17156  11.8440  14.4760  5256.301 10000
 add_diagonal_1(A)  40.601  44.2130  51.68039  48.7940  51.7795 11519.797 10000
 add_diagonal_2(A)  14.279  16.8790  20.60770  18.8860  21.7520  5966.649 10000
 add_diagonal_3(A) 166.582 173.1480 189.50570 175.8495 179.2100  8586.079 10000
  cld
 a   
   c 
  b  
    d

  

Как мы видим, первая функция является самой быстрой, за ней следует replace метод.

Как часто, apply функции довольно плохи по производительности.

Комментарии:

1. Было бы интересно посмотреть, как различные параметры ведут себя на больших наборах данных.

Ответ №5:

Вот еще один базовый параметр R, использующий diag expand.grid replace

 replace(
  diag(ncol(mat)),
  as.matrix(subset(do.call(expand.grid, replicate(2, 1:ncol(mat), simplify = FALSE)), Var1 != Var2)),
  mat
)
  

что дает

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