R 使用列表中数据帧的加权平均值创建新数据帧

R 使用列表中数据帧的加权平均值创建新数据帧,r,R,我有许多数据帧存储在一个列表中,我想从这些数据帧中创建加权平均值,并将结果存储在一个新的数据帧中。例如,使用列表: dfs <- structure(list(df1 = structure(list(A = 4:5, B = c(8L, 4L), Weight = c(TRUE, TRUE), Site = c("X", "X")), .Names = c("A", "B", "Weight", "Site")

我有许多数据帧存储在一个列表中,我想从这些数据帧中创建加权平均值,并将结果存储在一个新的数据帧中。例如,使用列表:

dfs <- structure(list(df1 = structure(list(A = 4:5, B = c(8L, 4L), Weight = c(TRUE, TRUE), Site = c("X", "X")), 
                                      .Names = c("A", "B", "Weight", "Site"), row.names = c(NA, -2L), class = "data.frame"), 
                      df2 = structure(list(A = c(6L, 8L), B = c(9L, 4L), Weight = c(FALSE, TRUE), Site = c("Y", "Y")), 
                                      .Names = c("A", "B", "Weight", "Site"), row.names = c(NA, -2L), class = "data.frame")), 
                 .Names = c("df1", "df2"))
上面只是一个非常简单的例子,但我的真实数据在列表中有许多数据帧,并且比我想要计算加权平均值的
a
B
更多的列。我还有几个类似于
Site
的列,它们在每个数据帧中都是常量,我希望移动到结果

我可以使用以下方法手动计算加权平均值

weighted.mean(dfs$df1$A, dfs$df1$Weight)
weighted.mean(dfs$df1$B, dfs$df1$Weight)
weighted.mean(dfs$df2$A, dfs$df2$Weight)
weighted.mean(dfs$df2$B, dfs$df2$Weight)

但我不确定如何以一种更短、更少“手动”的方式完成这项工作。有人有什么建议吗?我最近学会了如何在列表中跨数据帧
lappy
,但到目前为止,我的尝试还不太成功

诀窍是创建一个适用于单个data.frame的函数,然后使用
lappy
在列表中迭代。由于
lappy
返回一个列表,因此我们将使用
do.call
将结果对象合并到一起:

foo <- function(data, meanCols = LETTERS[1:2], weightCol = "Weight", otherCols = "Site") {
  means <- t(sapply(data[, meanCols], weighted.mean, w = data[, weightCol]))
  sumWeight <- sum(data[, weightCol])
  others <- data[1, otherCols, drop = FALSE] #You said all the other data was constant, so we can just grab first row
  out <- data.frame(others, means, sumWeight)
  return(out)
}
既然您说这是一个最小的示例,那么这里有一种方法可以将其扩展到其他列。我们将使用
grepl()
并使用正则表达式来标识正确的列。或者,您可以将它们全部写在一个向量中。大概是这样的:

do.call(rbind, lapply(dfs, foo, 
                      meanCols = grepl("A|B", names(dfs[[1]])),
                      otherCols = grepl("Site", names(dfs[[1]]))
                      ))

使用
dplyr

 library(dplyr)
 library('devtools')
 install_github('hadley/tidyr')
 library(tidyr)

 unnest(dfs) %>%
           group_by(Site) %>% 
           filter(Weight) %>% 
           mutate(Sum=n()) %>%
           select(-Weight) %>% 
           summarise_each(funs(mean=mean(., na.rm=TRUE)))
给出了结果

 #  Site   A B Sum
 #1    X 4.5 6   2
 #2    Y 8.0 4   1
或使用
data.table

 library(data.table)
 DT <- rbindlist(dfs)
 DT[(Weight)][, c(lapply(.SD, mean, na.rm = TRUE), 
                Sum=.N), by = Site, .SDcols = c("A", "B")]
 #   Site   A B Sum
 #1:    X 4.5 6   2
 #2:    Y 8.0 4   1

我有
每个人的总结(funs(weighted.mean(,Weight)),list(quote(-Weight))
,但我不能用这种方式处理
权重。是否可以对每个摘要中的特定列应用不同的FUN?例如,我们是否可以在
summary\u each\u q
中为A和B应用
weighted.mean(,Weight)
,为
Weight
应用
summary\u each\u q
dplyr\u 0.3
中不推荐使用
sum()。对于特定的列,我无法使用
summary\u each\u
获得成功。啊,是这样吗?知道这件事很好。谢谢你的更新。@jazzurro没问题。很高兴它帮助了你。谢谢阿克伦,我真的很感谢你的帮助!谢谢Chase,我现在理解得更好了,并且能够在我更大的数据集中实现这一点。再次感谢!
 #  Site   A B Sum
 #1    X 4.5 6   2
 #2    Y 8.0 4   1
 library(data.table)
 DT <- rbindlist(dfs)
 DT[(Weight)][, c(lapply(.SD, mean, na.rm = TRUE), 
                Sum=.N), by = Site, .SDcols = c("A", "B")]
 #   Site   A B Sum
 #1:    X 4.5 6   2
 #2:    Y 8.0 4   1
   unnest(dfs) %>% 
             group_by(Site) %>% 
             summarise_each(funs(weighted.mean=stats::weighted.mean(., Weight),
                    Sum.Weight=sum(Weight)), -starts_with("Weight")) %>%
             select(Site:B_weighted.mean, Sum.Weight=A_Sum.Weight) 

  #    Site A_weighted.mean B_weighted.mean Sum.Weight
  #1    X             4.5               6          2
  #2    Y             8.0               4          1