2016-01-19 20 views
7

Voglio aggregare (sommare) matrici all'interno di una lista secondo i nomi memorizzati in un vettore. Ecco alcuni dati esempio:Come aggregare matrici in un elenco basato sul vettore di nomi?

lst <- list("111"=matrix(c(1, 0, 6, NA, 1, 0), 
           nrow = 1, byrow = T), 
      "112"=matrix(c(6, 2, 2, 0, 3, NA), 
           nrow = 1, byrow = T), 
      "113"=matrix(c(2, 3, 0, 0, 1, 1), 
         nrow = 1, byrow = T)) 
agg.nam <- c(111,113) 

mio risultato atteso è:

> res 
$ 
    [,1] [,2] [,3] [,4] [,5] [,6] 
[1,] 3 3 6 0 2 1 

Così, il primo e terzo matrici si riassumono (con na.rm = TRUE).

ho provato prima a sottoinsieme del agg.nam:

lapply(lst, function(x) x[, which(names(x) %in% agg.nam)]) 

ma ho già fallito in questo punto, senza aggregazione.

risposta

4

È possibile afferrare gli elementi della lista rilevanti in una matrice con:

do.call(rbind, lst[as.character(agg.nam)]) 
#  [,1] [,2] [,3] [,4] [,5] [,6] 
# [1,] 1 0 6 NA 1 0 
# [2,] 2 3 0 0 1 1 

Tutto ciò che è necessario quindi sta chiamando colSums con na.rm=TRUE (grazie a @docendodiscimus per sottolineare questa semplificazione):

colSums(do.call(rbind, lst[as.character(agg.nam)]), na.rm=TRUE) 
# [1] 3 3 6 0 2 1 

Se le matrici avevano più righe, la semplificazione di cui sopra non funzionerebbe davvero, e quanto segue avrebbe fatto meglio il trucco:

# Grab relevant list elements 
mats <- lst[as.character(agg.nam)] 

# Replace any instance of NA with 0 
mats <- lapply(mats, function(x) { x[is.na(x)] <- 0 ; x }) 

# Sum them up 
Reduce("+", mats) 
#  [,1] [,2] [,3] [,4] [,5] [,6] 
# [1,] 3 3 6 0 2 1 
1

1) abind Questo funziona anche se le matrici costituenti non sono matrici a riga singola. abind crea una matrice tridimensionale dalla sottolista L e quindi sum viene applicata lungo elementi paralleli utilizzando na.rm = TRUE.

library(abind) 

L <- lst[as.character(agg.nam)] 
apply(abind(L, along = 3), 1:2, sum, na.rm = TRUE) 

Nel caso dei dati di ingresso della questione otteniamo la seguente matrice di uscita:

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

2) matrice Questo funziona anche e non utilizza alcun pacchetto. Funziona allo stesso modo, tranne che rimodella L in un array 3d usando array. L è da sopra.

make3d <- function(List) array(unlist(List), c(dim(List[[1]]), length(List))) 
apply(make3d(L), 1:2, sum, na.rm = TRUE) 

3) mapply Utilizzando questo mapply definisce una somma parallelo che rimuove AN e quindi applica utilizzando Reduce. Non vengono utilizzati pacchetti. L proviene da (1).

psum <- function(x, y) array(mapply(sum, x, y, MoreArgs = list(na.rm = TRUE)), dim(x)) 
Reduce(psum, L) 

3a) Una variazione di (3) è:

sumNA <- function(...) sum(..., na.rm = TRUE) 
array(do.call(mapply, c(sumNA, L)), dim(L[[1]]))