Взяв среднее значение столбца над списком фреймов данных в R

Вот что я пытаюсь сделать. У моего фрейма данных есть фактор-переменная "страна", и я хочу разделить фрейм данных по стране. Затем я хочу взять среднее значение столбца по каждой переменной для фрейма данных каждой страны.

Данные здесь: https://github.com/pourque/country-data

Я сделал это до сих пор...

myList <- split(df1, df1$country)
for(i in 1:length(myList)) {
aggregate <- mapply(myList[[i]][,-c(38:39)], colMeans)
}

(Я не включаю 38-й и 39-й столбцы, потому что это факторы.)

Я прочитал это ( функция более чем в одном списке), что заставляет меня думать, что mapply является ответом здесь... но я получаю эту ошибку:

Error in match.fun(FUN) : 
'myList[[i]][, -c(38:39)]' is not a function, character or symbol 

Может я неправильно форматирую?

4 ответа

Решение

Ответ data.table:

library(data.table)

setDT(df1)[, lapply(.SD, mean), by = country, .SDcols = -c('age', 'gender')]

Теперь более аккуратный синтаксис с отменой выбора в.SDcols благодаря пользователю Arun

Чтобы объяснить, что здесь происходит:

  • setDT(df1) сделать data.frame data.table
  • lapply(.SD, mean) для каждого столбца в подмножестве данных возьмите mean
  • by = county сделать это по группам в соответствии с country
  • .SDcols = -c('age', 'gender') пропускать age а также gender столбцы из подмножества данных

Это просто в базе R, используя aggregate без необходимости split data.frame в список заранее. Вот пример использования встроенных данных радужной оболочки, где вы вычисляете mean всех переменных, кроме тех, которые в первом и втором столбце по группам Species:

data(iris)
aggregate(. ~ Species, iris[-(1:2)], mean)
#     Species Petal.Length Petal.Width
#1     setosa        1.462       0.246
#2 versicolor        4.260       1.326
#3  virginica        5.552       2.026

. внутри aggregate используется, чтобы указать, что вы хотите использовать все оставшиеся столбцы data.frame, кроме переменной группировки (в данном случае - Species). И потому что вы указываете iris[-(1:2)] в качестве входных данных первый и второй столбцы также не используются.


Для ваших данных это должно быть что-то вроде:

aggregate(. ~ country, df1[-c(38:39)], mean)
library(dplyr)

df1 %>%
    group_by(country) %>%
    select(-age, -gender) %>%
    summarise_each(funs(mean))

Если вы настаиваете на сохранении всего в списке:

#split and make list of df
myList <- split(df, df$country)

#aggregate without age and gender
my_aggregate <- function(df_inlist) {
  df_inlist <- aggregate(.~country, df_inlist[ , -c(38, 39)], mean)
}

#Apply aggregate function on all data frames in the list
out <- lapply(myList, function (x) {
  my_aggregate(x)
})

out это list data.frames для каждой страны и colmeans по переменным. Как собрать все это вместе в data.frame:

composite_df <- do.call(rbind, out)
Другие вопросы по тегам