How to aggregate matrices in a list based on a vector of names?

I want to aggregate (summarize) the matrices inside the list according to the names stored in the vector. Here are some sample data:

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) 

Expected Result:

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

So, the first and third matrices are summed (with na.rm = TRUE).

I tried to multiply agg.nam first:

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

but I have already failed at this point, without aggregation.

+7
list r aggregate
source share
2 answers

You can capture the relevant list items into a matrix using:

 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 

All that is required then calls colSums with na.rm=TRUE (thanks to @docendodiscimus to indicate this simplification):

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

If matrices had several lines, the above simplification would not work, and the following could make the trick better:

 # 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 
+4
source share

1) abind This works even if the constituent matrices are not single-row matrices. abind creates a 3-dimensional array from the L sublists, and then sum is applied along parallel elements using na.rm = TRUE .

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

In the case of the input of the question, we get the following output matrix:

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

2) an array . It also works and does not use any packages. It works the same way, except that it converts L to a 3D array using array . L on top.

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

3) mapply Using mapply defines a parallel sum that removes the NA and then applies it using Reduce . Packages are not used. L - from (1).

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

3a) . Option (3):

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

All Articles