Изменить элементы в одной матрице на основе позиций, заданных другой матрицей в R - PullRequest
0 голосов
/ 21 марта 2019

Допустим, у меня есть симметричная матрица A, например

> A <- matrix(runif(16),nrow = 4,byrow = T)
> ind <- lower.tri(A)
> A[ind] <- t(A)[ind]
> A
          [,1]      [,2]      [,3]       [,4]
[1,] 0.4212778 0.6874073 0.1551896 0.46757640
[2,] 0.6874073 0.5610995 0.1779030 0.54072946
[3,] 0.1551896 0.1779030 0.9515304 0.79429777
[4,] 0.4675764 0.5407295 0.7942978 0.01206526

У меня также есть 4 x 3 матрица B, которая дает конкретные позиции матрицы A, например:

> B<-matrix(c(1,2,4,2,1,3,3,2,4,4,1,3),nrow=4,byrow = T)
> B
      [,1] [,2] [,3]
[1,]    1    2    4
[2,]    2    1    3
[3,]    3    2    4
[4,]    4    1    3

Матрица B представляет следующие позиции A: (1,1), (1,2), (1,4), (2,2), (2,1), (2,3), (3,3), (3,2), (3,4), (4,4), (4,1), (4,3).

Я хочу изменить значения A, которые НЕ находятся в позициях, заданныхB, заменив их на Inf.Я хочу получить следующий результат:

          [,1]      [,2]      [,3]       [,4]
[1,] 0.4212778 0.6874073       Inf 0.46757640
[2,] 0.6874073 0.5610995 0.1779030        Inf
[3,]       Inf 0.1779030 0.9515304 0.79429777
[4,] 0.4675764       Inf 0.7942978 0.01206526

Как я могу сделать это быстро, избегая цикла for (который я могу кодировать)?Я видел много похожих постов, но никто не дал мне то, что я хочу.Спасибо!

Ответы [ 5 ]

5 голосов
/ 21 марта 2019

Вы хотите сделать что-то вроде подмножества матрицы (например, P[Q]), за исключением того, что вы не можете использовать отрицательное индексирование в подмножестве матрицы (например, P[-Q] не допускается).Вот обходной путь.

Сохраните элементы, которые вы хотите сохранить из A, в матрице из 2 столбцов, где каждая строка является координатой A:

Idx <- cbind(rep(1:4, each=ncol(B)), as.vector(t(B)))

Создатьматрица, в которой все значения равны Inf, а затем перезаписывают значения, которые вы хотели «сохранить» от A:

Res <- matrix(Inf, nrow=nrow(A), ncol=ncol(A))
Res[Idx] <- A[Idx]

Результат

Res
#          [,1]        [,2]        [,3]       [,4]
#[1,] 0.9043131 0.639718071         Inf 0.19158238
#[2,] 0.6397181 0.601327568 0.007363378        Inf
#[3,]       Inf 0.007363378 0.752123162 0.61428003
#[4,] 0.1915824         Inf 0.614280026 0.02932679
2 голосов
/ 21 марта 2019

Вот одна строка

A[cbind(1:nrow(A), sum(c(1:ncol(A))) - rowSums(B))] <- Inf

          [,1]       [,2]       [,3]      [,4]
[1,] 0.4150663 0.23440503        Inf 0.6665222
[2,] 0.2344050 0.38736067 0.01352211       Inf
[3,]       Inf 0.01352211 0.88319263 0.9942303
[4,] 0.6665222        Inf 0.99423028 0.7630221
1 голос
/ 21 марта 2019
A <- matrix(runif(16),nrow = 4,byrow = T)
ind <- lower.tri(A)
A[ind] <- t(A)[ind]

## >A[]
##        [,1]        [,2]      [,3]      [,4]
## [1,] 0.07317535 0.167118857 0.0597721 0.2128698
## [2,] 0.16711886 0.008661005 0.6419335 0.6114373
## [3,] 0.05977210 0.641933514 0.7269202 0.3547959
## [4,] 0.21286984 0.611437278 0.3547959 0.4927997

Первое, на что нужно обратить внимание, это то, что матрица B не очень полезна в ее текущем виде, потому что нам нужна информация о строках и каждом значении в B

 B<-matrix(c(1,2,4,2,1,3,3,2,4,4,1,3),nrow=4,byrow = T)
> B
##      [,1] [,2] [,3]
## [1,]    1    2    4
## [2,]    2    1    3
## [3,]    3    2    4
## [4,]    4    1    3

Таким образом, мы можемсоздайте его, просто используя melt, и используйте Var1 и значение.

>melt(B)
##    Var1 Var2 value
## 1     1    1     1
## 2     2    1     2
## 3     3    1     3
## 4     4    1     4
## 5     1    2     2
## 6     2    2     1
## 7     3    2     2
## 8     4    2     1
## 9     1    3     4
## 10    2    3     3
## 11    3    3     4
## 12    4    3     3

Нам нужно заменить несуществующий индекс в A на inf.Это не легко сделать напрямую.Таким простым способом было бы создать другую матрицу Inf и заполнить значения A согласно индексу melt (B)

> C<-matrix(Inf,nrow(A),ncol(A))

 idx <- as.matrix(melt(B)[,c("Var1","value")])
 C[idx]<-A[idx]

> C
##            [,1]        [,2]      [,3]      [,4]
## [1,] 0.07317535 0.167118857 0.0597721 0.2128698
## [2,] 0.16711886 0.008661005 0.6419335       Inf
## [3,]        Inf 0.641933514 0.7269202 0.3547959
## [4,] 0.21286984         Inf 0.3547959 0.4927997
1 голос
/ 21 марта 2019

Другим способом было бы отождествить ячейки с apply и установить затем на inf.

cnum <- 1:ncol(A)
A[cbind(1:nrow(A), apply(B, 1, function(x) cnum[-which(cnum %in% x)]))] <- Inf
A
#           [,1]      [,2]      [,3]      [,4]
# [1,] 0.9148060 0.9370754       Inf 0.8304476
# [2,] 0.9370754 0.5190959 0.7365883       Inf
# [3,]       Inf 0.7365883 0.4577418 0.7191123
# [4,] 0.8304476       Inf 0.7191123 0.9400145

Примечание: set.seed(42).

0 голосов
/ 21 марта 2019

Другой подход, который выполняет поднабор матрицы (например, P[Q]), заключается в создании индекса Q вручную. Вот один из подходов.

Определите, какой индекс столбца «отсутствует» в каждой строке B:

col_idx <- apply(B, 1, function(x) (1:nrow(A))[-match(x, 1:nrow(A))])

Создать матрицу поднабора Q

Idx <- cbind(1:nrow(A), col_idx)

сделать замену

A[Idx] <- Inf

Конечно, вы можете сделать это однострочным, если вы действительно хотите:

A[cbind(1:nrow(A), apply(B, 1, function(x) (1:nrow(A))[-match(x, 1:nrow(A))])]
...