/ / Executar operação em colunas agrupadas de uma matriz - r, matriz

Executar operação em colunas agrupadas de uma matriz - r, matriz

Suponha que eu tenha uma matriz M e vetor G de inteiros, tais que G tem tantas entradas quantas as colunas M. Por exemplo (esquematicamente):

G:     1    1    1    2    2    3    3    3    3

M:     4   20   12    4   71   46   45   25   64
50   54   88    1   80    8   86   71   26
28    7   31   44   84   46   35   32    0
45   15   46   76   39   67   10   59   59

O vetor G codifica um agrupamento de M"s colunas. No exemplo acima, G codifica os três grupos de colunas, correspondentes às três submatrizes mostradas abaixo:

  4   20   12
50   54   88
28    7   31
45   15   46

4   71
1   80
44   84
76   39


46   45   25   64
8   86   71   26
46   35   32    0
67   10   59   59

(NB: Por uma questão de clareza, neste exemplo eu escolhi grupos consistindo de colunas contíguas, mas em geral, as colunas em um grupo não precisam ser contíguas. Neste caso, a ordenação dos grupos deve ser a ordem da primeira aparição em G.)

Eu quero executar um "colapso" (ou"resumindo") a operação em cada linha de cada uma dessas submatrizes e concatene as colunas resultantes em uma nova matriz. Por exemplo, se a operação de recolhimento for max, o procedimento que acabamos de descrever geraria as três colunas mostradas abaixo à direita da seta:

  4   20   12           20
50   54   88        -> 88
28    7   31           31
45   15   46           46

4   71                71
1   80             -> 80
44   84                84
76   39                76


46   45   25   64      64
8   86   71   26   -> 86
46   35   32    0      46
67   10   59   59      67

O resultado final seria, portanto, a matriz:

 20   71   64
88   80   86
31   84   46
46   76   67

Como se faz esse tipo de manipulação em R?


(FWIW, abaixo é o código para criar o M e G Mostrado acima.)

G <- c(1, 1, 1, 2, 2, 3, 3, 3, 3)

M <- matrix(c( 4, 20, 12,  4, 71, 46, 45, 25, 64,
50, 54, 88,  1, 80,  8, 86, 71, 26,
28,  7, 31, 44, 84, 46, 35, 32,  0,
45, 15, 46, 76, 39, 67, 10, 59, 59),
nrow = 4,
byrow = TRUE)

Respostas:

4 para resposta № 1

Aqui está uma possibilidade:

## I know your matrix has 4 rows, that is what the `4` in the following means
lst <- split(M, rep(G, each = 4L))
sapply(lst, function (x) sapply(split(x, 1:4), max) )

#   1  2  3
#1 20 71 64
#2 88 80 86
#3 31 84 46
#4 46 76 67

A função function (x) sapply(split(x, 1:4), max) está realmente fazendo fila máxima.


3 para resposta № 2

Aqui está outra opção com rowMaxs

library(matrixStats)
sapply(split.default(as.data.frame(M), G), function(x) rowMaxs(as.matrix(x)))
#     1  2  3
#[1,] 20 71 64
#[2,] 88 80 86
#[3,] 31 84 46
#[4,] 46 76 67

Ou uma variação do acima é

sapply(split(t(M), G), function(x) rowMaxs(matrix(x, nrow=4, byrow=TRUE)))

2 para resposta № 3

Outra possibilidade, confiando no fato de que as matrizes são normalmente preenchidas por ordem de coluna:

simplify2array(by(t(M), G, function(x) sapply(x,max) ))
#    1  2  3
#V1 20 71 64
#V2 88 80 86
#V3 31 84 46
#V4 46 76 67