Замена части треугольной матрицы вектором - PullRequest
2 голосов
/ 10 апреля 2020

У меня есть v<- c(2,4,5) и mat<- matrix(0,n,n). и я хочу заменить вектор в верхней части матрицы, каждое место, которое я идентифицирую, массивы заменяют на число длины вектора. например, для n = 5 вывод может быть:

       [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    4    0    0
[2,]    0    0    5    0    0
[3,]    0    0    0    0    0
[4,]    0    0    0    0    0
[5,]    0    0    0    0    0

Я пытаюсь с этим кодом:

mat <- matrix(0, nrow = 5, ncol = 5)
for (i in 1:5){
  for (j in 1:5){
    if (i<j & j<= 5){
      mat [upper.tri(mat, diag = FALSE)]<- v
    }
  }
}

, но вывод:

       [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    4    2    2
[2,]    0    0    5    4    4
[3,]    0    0    0    5    5
[4,]    0    0    0    0    2
[5,]    0    0    0    0    0

I есть две проблемы:

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

  2. Я не знаю, где я должны заменить i и j в l oop для начальной точки матрицы, чтобы заменить вектор (возможно, я хочу начать вектор с [3,4] в матрице.). Например:

      [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    0    0    0
[2,]    0    0    0    0    0
[3,]    0    0    0    2    4
[4,]    0    0    0    0    5
[5,]    0    0    0    0    0

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Вы можете вычислить индексы {r,c} для каждого элемента вектора длины n (вам также понадобятся размеры квадратного треугольника, необходимые для подгонки к такому вектору.

Например, для вектор длины 3, начинающийся с {3,4} (при условии, что столбец-мажор, как в R), вам понадобятся индексы

i r c
1 3,4

2 3,5
3 4,5

4 3,6
5 4,6
6 5,6
...

Вероятно, вы уже можете видеть шаблоны. Для строк есть общая функция r, которая дает шаблон 3 3 4 3 4 5 ..., который sequence определенно sequence(1:3) + 2.

Далее столбцы имеют более простое решение в 4 5 5 6 6 6 ..., равное rep(1:3, 1:3) + 3, поэтому мы можем просто объединить эти два, чтобы получить индексы для каждого элемента вектора.

## use 1:(n - 1) for a length n vector
mat <- matrix(0, 5, 5)
v <- c(2, 4, 5)
i <- cbind(sequence(1:2) + (3 - 1), rep(1:2, 1:2) + (4 - 1))
mat[i] <- v
mat

#      [,1] [,2] [,3] [,4] [,5]
# [1,]    0    0    0    0    0
# [2,]    0    0    0    0    0
# [3,]    0    0    0    2    4
# [4,]    0    0    0    0    5
# [5,]    0    0    0    0    0

Вы можете видеть свои начальные позиции в приведенном выше коде, поэтому мы можем обобщить эту логику c:

f <- function(matrix, vector = 1:3, start = c(1, 1)) {
  i <- sequence(rep(1:nrow(matrix), 1:ncol(matrix))[length(vector)])
  i <- cbind(
    sequence(i) + start[1] - 1,
    rep(i, i) + start[2] - 1
  )
  ## recycle vector so there are no incompatible length errors
  matrix[i] <- rep_len(vector, nrow(i))

  matrix
}

mat <- matrix(0, 5, 5)
f(mat, v, c(3, 4))
f(mat, v, c(2, 2))
f(mat, c(2, 4, 5), c(1, 1))
f(mat, c(v, v), c(1, 1))
f(mat, c(v, v, v), c(1, 2))
1 голос
/ 10 апреля 2020

Когда вы заполняете матрицы из векторов, нужно знать две полезные вещи:

  1. Заполняет их по столбцам; и
  2. Если вектор короче части матрицы, которую нужно заполнить, вектор будет переработан (повторен).

Далее, в вашем коде вы используете два for циклы, вложенные, с очевидным намерением работать только с этими индексами в матрице ... но тогда вы не будете ссылаться на i и j в подмножестве или назначении матрицы, поэтому каждый раз, когда он пытается заменить одно значение, это замена всей верхней матрицы три на весь вектор.

Вот более быстрый способ:

mat <- matrix(0, nrow = 5, ncol = 5)
v <- c(2, 4, 5)
mat[upper.tri(mat)][seq_along(v)] <- v
mat
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    0    2    4    0    0
# [2,]    0    0    5    0    0
# [3,]    0    0    0    0    0
# [4,]    0    0    0    0    0
# [5,]    0    0    0    0    0

Первое индексирование на mat - это верхний треугольник, так как знаешь. Второе подмножество равно length(v) из этого подмножества.

Если вы хотите заменить его в произвольных местах в верхнем треугольнике, то вот пример:

mat <- matrix(0, nrow = 5, ncol = 5)
ut <- upper.tri(mat)
fullv <- integer(sum(ut)) # the size of the matrix subset
fullv
#  [1] 0 0 0 0 0 0 0 0 0 0
fullv[5 + seq_along(v)] <- v
fullv
#  [1] 0 0 0 0 0 2 4 5 0 0
mat[ut] <- fullv
mat
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    0    0    0    0    4
# [2,]    0    0    0    0    5
# [3,]    0    0    0    2    0
# [4,]    0    0    0    0    0
# [5,]    0    0    0    0    0

Здесь мы продемонстрируйте, что заполнение выполняется по столбцу , а это не то, что вы просили. Чтобы лучше понять, как происходит это заполнение,

mat <- matrix(0, nrow = 5, ncol = 5)
ut <- upper.tri(mat)
mat[ut] <- seq_len(sum(ut))
mat
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    0    1    2    4    7
# [2,]    0    0    3    5    8
# [3,]    0    0    0    6    9
# [4,]    0    0    0    0   10
# [5,]    0    0    0    0    0

Итак, если вы хотите, чтобы ваши v находились в очень специфических c местах, и они не являются последовательными для этого заказа, вам нужно будет указать c:

mat <- matrix(0, nrow = 5, ncol = 5)
ut <- upper.tri(mat)
mat[ut][c(6,9,10)] <- v
mat
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    0    0    0    0    0
# [2,]    0    0    0    0    0
# [3,]    0    0    0    2    4
# [4,]    0    0    0    0    5
# [5,]    0    0    0    0    0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...