在R中对数据框列表进行列均值计算

7
这是我想做的事情。我的数据框有一个因子变量“国家”,我想根据国家拆分数据框。然后,我想对每个国家的数据框中的每个变量取列平均值。
数据在这里: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 

也许我格式化不正确?

1
为什么要将数据拆分成单独的数据框?直接使用data.table或dplyr即可。 - Gregor Thomas
这篇文章现在变得很好了! - vagabond
4个回答

7

使用基本的R语言,您可以直接使用aggregate函数进行操作,而无需事先将数据框分割为列表。aggregate函数可以很好地完成此任务。这里提供了一个示例,使用内置的鸢尾花数据,通过每个Species分组计算除第一和第二列以外所有变量的mean:

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中的.表示您希望使用数据框中除分组变量(在此示例中是Species)以外的所有剩余列。由于您将iris[-(1:2)]指定为输入数据,因此也不使用第一列和第二列。
对于您的数据,应该像这样:
aggregate(. ~ country, df1[-c(38:39)], mean)

@Anshu,请您再试一次,使用底部稍作修改的代码。 - talat
1
或者尝试在聚合函数中使用 df1[-c("age", "gender")] - talat
特别奇怪的是,我得到的平均性别值大于3,而实际上性别选择只应该是1或2。例如,df1[df1 $ country =="AF",]只给出一个性别为2的观测结果,但聚合函数却显示出性别= 3! - Anshu Chen
很奇怪,我还没有下载你的数据。等我回到电脑前可能会下载。 - talat
@Anshu,我下载了你的数据,将其读入R并运行了x <- aggregate(. ~ country, df1[-c(38:39)], mean)。它产生了正确的输出,并且不包括"gender"或"age"列。你尝试的代码可能有错别字,或者与GitHub上的示例中的数据结构不同。 - talat
显示剩余3条评论

6
library(dplyr)

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

您还可以在 summarise_each 函数内取消选择这两列。 - talat

4

一个data.table的解答:

library(data.table)

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

感谢用户Arun,现在使用deselection语法可以更加整洁地在.SDcols中操作,

以下是对这段代码的解释:

  • setDT(df1)将数据框转换为数据表
  • lapply(.SD, mean)对于子集数据中的每一列,取其平均值mean
  • by = country按照country分组执行上述操作
  • .SDcols = -c('age', 'gender')从子集数据中省略掉agegender两列

我有点不喜欢这个答案的可读性,与其他答案相比。还有其他data.table的人想提出改进建议吗? - arvi1000
你可以使用.SDcols,而不是setdiff吗? - Frank
可以在.SDcols中指定所有所需的列,但这似乎与上述方法相同。有没有一种简洁的方法可以使用.SDcols来省略指定的列? - arvi1000
setDT(df1)[, lapply(.SD, mean), by = country, .SDcols = -c("age", "gender")] - Arun
看起来最新版本的.SDcols语法更好,是吗?在这里的14-17项:https://github.com/Rdatatable/data.table#changes-in-v195--in-development-on-github即使使用`data.table`的CRAN版本,您也可以执行`df1[ , lapply(.SD, mean), by=country,.SDcols=setdiff(names(df1),c('age','gender'))]`,对吧? - Frank
啊哈,谢谢@Arun!我不知道你可以在.SDcols中使用-进行取消选择。@Frank,是的,但那似乎很相似,就是我所说的(因为它仍然需要setdiff)。 - arvi1000

4
如果您坚持将所有内容都放在列表中:
#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,其中包含列平均值。如何将它们放在一个数据框中:

composite_df <- do.call(rbind, out)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接