Как суммировать числовые элементы списка

#r

#r

Вопрос:

Мне интересно узнать об элегантном способе, позволяющем суммировать (или вычислять среднее значение) числовые значения списка. например

 x <- list( a = matrix(c(1,2,3,4), nc=2), b = matrix(1, nc=2, nr=2))
  

и хотите получить

 x[[1]] x[[2]] 
  

или среднее:

 (x[[1]] x[[2]])/2
  

Комментарии:

1. Какой вывод вы хотите для них? Я вижу два способа, которыми можно интерпретировать то, что вы просите, и они разные. Для двух вычислений exmaple укажите, какой ожидаемый результат, пожалуйста.

2. В этом примере это просто with(x, a b) , но это не масштабируется до большого количества элементов или элементов разных размеров или списков с нечисловыми элементами. Как сказал Гэвин: расскажите нам больше о том, что вы делаете.

Ответ №1:

Вы можете использовать Reduce для последовательного применения двоичной функции к элементам в списке.

 Reduce(" ",x)
     [,1] [,2]
[1,]    2    4
[2,]    3    5

Reduce(" ",x)/length(x)
     [,1] [,2]
[1,]  1.0  2.0
[2,]  1.5  2.5
  

Ответ №2:

Даже если Reduce() это стандартный ответ на вопрос о суммировании списка матриц, и на это указывалось много раз, я собрал некоторые из наиболее известных способов достижения этой цели в следующем коде. Основная цель — показать, есть ли какой-либо выбор, который явно лучше других по скорости и «точности».

 # load libraries
library(microbenchmark)
library(ggplot2)

# generate the data with ten matrices to sum
mat_list <- lapply(1:10, function(x) matrix(rnorm(100), nrow = 10, ncol = 10))
# larger and longer test set
mat_list_large <- lapply(1:1000, function(x) matrix(rnorm(100000), nrow = 1000, ncol = 100))

# function with reduce @james
f1 <- function(mat_list){
  Reduce(` `, mat_list)
}
# function with apply @Jilber Urbina
f2 <- function(mat_list){
  apply(simplify2array(mat_list), c(1:2), sum)
}
# function with do.call @Tyler Rinker
f3 <- function(mat_list){
  x <- mat_list[[1]]
  lapply(seq_along(mat_list)[-1], function(i){
    x <<- do.call(" ", list(x, mat_list[[i]]))
  })
  return(x)
}
# function with loop modified from @Carl Witthoft
f4 <- function(mat_list){
  out_mat <- mat_list[[1]]
  for (i in 2:length(mat_list)) out_mat <- out_mat   mat_list[[i]]
  return(out_mat)
}

# test to see if they are all equal
all.equal(f1(mat_list), f2(mat_list), f3(mat_list), f4(mat_list), tolerance = 1.5e-8) # TRUE 
# ps: the second method seems to differ slightly from the others

# run 100 times all the functions for having a statistic on their speed
mb <- microbenchmark("Reduce" = f1(mat_list),
                     "apply" = f2(mat_list),
                     "do.call" = f3(mat_list),
                     "loop" = f4(mat_list), 
                     times = 100)
mb2 <- microbenchmark("Reduce" = f1(mat_list_large),
                 "apply" = f2(mat_list_large),
                 "do.call" = f3(mat_list_large),
                 "loop" = f4(mat_list_large), 
                 times = 100)

# see output using a violin plot
autoplot(mb)
  

mat_list_sum_speed

 autoplot(mb2) # longer version for bigger datasets
  

mat_list_sum_speed_large

Поэтому, вероятно, лучше использовать Reduce() as для средней скорости и четкости кода.