Среднее значение вектора внутри списка списков

У меня есть список списков со следующей структурой:

> mylist <- list(list(a=as.numeric(1:3), b=as.numeric(4:6)), 
                 list(a=as.numeric(6:8), b=as.numeric(7:9)))
> str(mylist)
List of 2
 $ :List of 2
  ..$ a: num [1:3] 1 2 3
  ..$ b: num [1:3] 4 5 6
 $ :List of 2
  ..$ a: num [1:3] 6 7 8
  ..$ b: num [1:3] 7 8 9

Я хотел бы получить среднее по элементам между векторами a и b из mylist. Для вектора a результат будет следующим:

> a
[1] 3.5 4.5 5.5

Я знаю функции lapply, rbind и colMeans, но не могу решить проблему с их помощью. Как я могу достичь того, что мне нужно?


person Jonas Schmedtmann    schedule 29.06.2014    source источник


Ответы (5)


Еще одна идея:

tmp = unlist(mylist, F)
sapply(unique(names(tmp)), 
       function(x) colMeans(do.call(rbind, tmp[grep(x, names(tmp))])))
#       a   b
#[1,] 3.5 5.5
#[2,] 4.5 6.5
#[3,] 5.5 7.5
person alexis_laz    schedule 29.06.2014
comment
+1. Я только что опубликовал ответ, связанный с unlist, но он сильно отличается от этого :-) - person A5C1D2H2I1M1N2O1R2T1; 29.06.2014

Вот один из подходов, в котором используются melt и dcast из reshape2.

library(reshape2)

## "melt" your `list` into a long `data.frame`
x <- melt(mylist)

## add a "time" variable to let things line up correctly
## L1 and L2 are created by `melt`
## L1 tells us the list position (1 or 2)
## L2 us the sub-list position (or name)
x$time <- with(x, ave(rep(1, nrow(x)), L1, L2, FUN = seq_along))

## calculate whatever aggregation you feel in the mood for
dcast(x, L2 ~ time, value.var="value", fun.aggregate=mean)
#   L2   1   2   3
# 1  a 3.5 4.5 5.5
# 2  b 5.5 6.5 7.5

Вот подход в базе R:

x <- unlist(mylist)
c(by(x, names(x), mean))
#  a1  a2  a3  b1  b2  b3 
# 3.5 4.5 5.5 5.5 6.5 7.5 
person A5C1D2H2I1M1N2O1R2T1    schedule 29.06.2014
comment
Этот unlist намного лучше и чище! Я очень сомневался в использовании рекурсивного = T и никогда не замечал какого-либо возможного фактора группирования .. - person alexis_laz; 29.06.2014

Обновлено: еще лучше ..._ 1_ фактически дает нам хорошую матрицу, которую можно применить rowMeans.

> rowMeans(sapply(mylist, unlist))
#  a1  a2  a3  b1  b2  b3 
# 3.5 4.5 5.5 5.5 6.5 7.5 

Оригинал: еще один lapply метод с добавленным sapply.

> lapply(1:2, function(i) rowMeans(sapply(mylist, "[[", i)) )
# [[1]]
# [1] 3.5 4.5 5.5
#
# [[2]]
# [1] 5.5 6.5 7.5
person Rich Scriven    schedule 29.06.2014

Вот комбинация data.table и RcppRoll (должна быть очень быстрой для больших списков)

library(data.table)
library(RcppRoll)
roll_mean(as.matrix(rbindlist(mylist)), 4, weights=c(1,0,0,1))

##     [,1] [,2]
## [1,]  3.5  5.5
## [2,]  4.5  6.5
## [3,]  5.5  7.5
person David Arenburg    schedule 29.06.2014

Один из многих возможных подходов через data.frame

mylist <- list(list(a = 1:3, b = 4:6),list(a = 6:8, b = 7:9))

sapply(c("a","b"),function(x){
  listout <- lapply(mylist,"[[",x)
  rowMeans(do.call(cbind,listout))
})

       a   b
[1,] 3.5 5.5
[2,] 4.5 6.5
[3,] 5.5 7.5
person AndrewMacDonald    schedule 29.06.2014
comment
Это неправильный результат. (1 + 6) / 2 == 3,5, а не 2,5 - person GSee; 29.06.2014