Среднее элементов в списке data.frames - PullRequest
23 голосов
/ 04 октября 2011

Предположим, у меня был список data.frames (из одинаковых строк и столбцов)

dat1 <- as.data.frame(matrix(rnorm(25), ncol=5))
dat2 <- as.data.frame(matrix(rnorm(25), ncol=5))
dat3 <- as.data.frame(matrix(rnorm(25), ncol=5))

all.dat <- list(dat1=dat1, dat2=dat2, dat3=dat3)

Как я могу вернуть один data.frame, который является средним значением (или суммой и т. Д.) Для каждогоэлемент в data.frames по всему списку (например, среднее значение первой строки и первого столбца из списков 1, 2, 3 и т. д.)?Я пробовал lapply и ldply в plyr, но они возвращают статистику для каждого data.frame в списке.

Редактировать: По какой-то причине это было помечено как домашнее задание.Не то чтобы это было так или иначе, но это не домашнее задание.Я просто не знаю, почему я не могу заставить это работать.Спасибо за понимание!

Edit2: Для дальнейшего пояснения: я могу получить результаты с помощью циклов, но я надеялся, что был способ (более простой и быстрый способ, потому что данные, которые я использую, имеют data.framesэто 12 строк на 100 столбцов и список из 1000+ этих фреймов данных).

z <- matrix(0, nrow(all.dat$dat1), ncol(all.dat$dat1))

for(l in 1:nrow(all.dat$dat1)){
   for(m in 1:ncol(all.dat$dat1)){
      z[l, m] <- mean(unlist(lapply(all.dat, `[`, i =l, j = m)))
   }
}

В результате получается следующее значение:

> z
        [,1]        [,2]        [,3]        [,4]       [,5]
[1,] -0.64185488  0.06220447 -0.02153806  0.83567173  0.3978507
[2,] -0.27953054 -0.19567085  0.45718399 -0.02823715  0.4932950
[3,]  0.40506666  0.95157856  1.00017954  0.57434125 -0.5969884
[4,]  0.71972821 -0.29190645  0.16257478 -0.08897047  0.9703909
[5,] -0.05570302  0.62045662  0.93427522 -0.55295824  0.7064439

Мне было интересно,был менее неуклюжий и более быстрый способ сделать это.Спасибо!

Ответы [ 6 ]

17 голосов
/ 05 октября 2011

Вот один вкладыш с plyr. Вы можете заменить mean на любую другую функцию.

ans1 = aaply(laply(all.dat, as.matrix), c(2, 3), mean)
11 голосов
/ 04 октября 2011

Вам было бы проще изменить структуру данных, объединив три двумерные матрицы в один трехмерный массив (используя библиотеку abind). Тогда решение будет более прямым, используя apply и указав размеры для усреднения.

EDIT:

Когда я ответил на вопрос, он был помечен homework, поэтому я просто дал подход. Оригинальный постер убрал этот тег, поэтому я возьму его / ее на слово, что это не так.

library("abind")

all.matrix <- abind(all.dat, along=3)
apply(all.matrix, c(1,2), mean)
10 голосов
/ 04 октября 2011

Я дал один ответ, который использует совершенно другую структуру данных для достижения результата. В этом ответе используется структура данных (список фреймов данных), предоставленная напрямую. Я думаю, что он менее элегантен, но все равно хотел его предоставить.

Reduce(`+`, all.dat) / length(all.dat)

Логика состоит в том, чтобы добавлять кадры данных вместе элемент за элементом (что + будет делать с кадрами данных), а затем делить на количество кадров данных. Использование Reduce необходимо, поскольку + может принимать только два аргумента за раз (и сложение является ассоциативным).

6 голосов
/ 05 октября 2011

Другой подход, использующий только base функции для изменения структуры объекта:

listVec <- lapply(all.dat, c, recursive=TRUE)
m <- do.call(cbind, listVec)

Теперь вы можете вычислить mean с rowMeans или median с apply:

means <- rowMeans(m)
medians <- apply(m, 1, median)
2 голосов
/ 05 октября 2011

Я бы выбрал немного другой подход:

library(plyr)
tmp <- ldply(all.dat) # convert to df
tmp$counter <- 1:5 # 1:12 for your actual situation
ddply(tmp, .(counter), function(x) colMeans(x[2:ncol(x)]))
1 голос
/ 04 октября 2011

Не могли бы вы просто использовать вложенные lapply() звонки?

Похоже, что это дает правильный результат на моей машине

mean.dat <- lapply(all.dat, function (x) lapply(x, mean, na.rm=TRUE))
...