Как заполнить недиагонали и игнорировать диагонали в матрице в R? - PullRequest
1 голос
/ 22 октября 2019

Я пытаюсь заполнить матрицу в R, где конечный результат будет игнорировать диагональные элементы, а значения будут заполняться по диагонали. Простой пример того, что я имею в виду, если я возьму простую матрицу 3x3, подобную показанной ниже:

ab <- c(1:9)
mat <- matrix(ab,nrow=3,ncol=3)
colnames(mat)<- paste0("x", 1:3)
rownames(mat)<- paste0("y", 1:3)
mat

    x1 x2 x3
y1  1  4  7
y2  2  5  8
y3  3  6  9

То, чего я хочу достичь, это заполнить диагонали 0 и сдвинуть все остальные значения вокругдиагональ. Так, например, если я просто использую diag(mat)<-0, что приводит к следующему:

   x1 x2 x3
y1  0  4  7
y2  2  0  8
y3  3  6  0

В то время как результат, который я ищу, выглядит примерно так (где значения оборачиваются вокруг диагонали):

   x1 x2 x3
y1  0  3  5
y2  1  0  6
y3  2  4  0

Меня не волнуют значения, которые выталкиваются из матрицы (т. Е. 7,8,9).

Есть предложения?

Спасибо

РЕДАКТИРОВАТЬ: Решение, приведенное ниже, кажется, решил проблему

Ответы [ 3 ]

4 голосов
/ 22 октября 2019

Одно из решений, которое работает для вашего примера, - это сначала объявить матрицу, полную единиц, кроме диагонали:

M <- 1 - diag(3)

А затем заменить все единицы на желаемые недиагональные значения

M[M == 1] <- 1:6
M
#      [,1] [,2] [,3]
# [1,]    0    3    5
# [2,]    1    0    6
# [3,]    2    4    0

Более сложный сценарий (например, диагональные коэффициенты, которые не равны 0, или несоответствующее число недиагональных элементов) может потребовать немного дополнительной работы.

0 голосов
/ 22 октября 2019

Это будет работать нормально для вашего примера. Не уверен, что мне нужно n1 & n2, можно изменить на одно значение, если всегда симметричный

# original data
ab <- c(1:9)
n1 <- 3
n2 <- 3

# You could add the 0's to the diagonal, by adding a 0 before every n1 split
# of the data e.g. 0,1,2,3 & 0,4,5,6 & 0,7,8,9
split_ab <- split(ab, ceiling((1:length(ab))/n1))
update_split_ab <- lapply(split_ab, function(x){
  c(0, x)
}) 
new_ab <- unlist(update_split_ab)

mat <- matrix(new_ab, nrow=n1, ncol=n2)
colnames(mat)<- paste0("x", 1:n2)
rownames(mat)<- paste0("y", 1:n1)
mat

# turn this in to a function

makeShiftedMatrix <- function(ab=1:9, n1=3, n2=3){

  split_ab <- split(ab, ceiling((1:length(ab))/n1))
  update_split_ab <- lapply(split_ab, function(x){
    c(0, x)
  }) 
  new_ab <- unlist(update_split_ab)

  mat <- matrix(new_ab, nrow=n1, ncol=n2)
  colnames(mat)<- paste0("x", 1:n2)
  rownames(mat)<- paste0("y", 1:n1)
  mat
  return(mat)
}

# default
makeShiftedMatrix()

# to read in original matrix and shift:
old_mat <- matrix(ab, nrow=n1, ncol=n2)
makeShiftedMatrix(ab=unlist(old_mat))
0 голосов
/ 22 октября 2019

Вам может понадобиться цикл:

n <- 9
seqs <- seq(1:n)
mats <- matrix(0, nrow = 3, ncol = 3)
ind <- 0
for(i in 1:nrow(mats)){
     for(j in 1:nrow(mats)){

         if(i == j) {
             mats[i,j] <- 0 }
             else {
                 ind <- ind + 1
                 mats[j,i] <- seqs[ind]
             }
         }
     }

В результате:

>mats
     [,1] [,2] [,3]
[1,]    0    3    5
[2,]    1    0    6
[3,]    2    4    0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...