在一个data.table中,按组计算多个列的加权平均数

9
这个问题是在组加权平均值的基础上提出的:我想使用data.table创建加权组内平均值。与最初的问题不同的是,要平均的变量名称在字符串向量中指定。
数据如下:
df <- read.table(text= "
          region    state  county  weights y1980  y1990  y2000
             1        1       1       10     100    200     50
             1        1       2        5      50    100    200
             1        1       3      120    1000    500    250
             1        1       4        2      25    100    400
             1        1       4       15     125    150    200
             2        2       1        1      10     50    150
             2        2       2       10      10     10    200
             2        2       2       40      40    100     30
             2        2       3       20     100    100     10
", header=TRUE, na.strings=NA)

使用Roland在上述问题中提供的答案:
library(data.table)
dt <- as.data.table(df)
dt2 <- dt[,lapply(.SD,weighted.mean,w=weights),by=list(region,state,county)]

我有一个包含字符串的向量,用于动态确定我想要组内加权平均值的列。

colsToKeep = c("y1980","y1990")

但我不知道如何将它作为参数传递给data.table函数。

我尝试过:

 dt[,lapply(
      as.list(colsToKeep),weighted.mean,w=weights),
      by=list(region,state,county)]` 

但是我接下来会得到:
Error in x * w : non-numeric argument to binary operator

我不确定如何实现我想要的。

额外问题:我希望保留原始列名,而不是得到V1和V2。

NB:我使用data.table包的1.9.3版本。

2个回答

11

通常情况下,您应该能够执行以下操作:

dt2 <- dt[,lapply(.SD,weighted.mean,w=weights), 
          by = list(region,state,county), .SDcols = colsToKeep]

即仅通过将那些列提供给.SDcols即可。但目前,由于存在一个错误,即weights列未在.SDcols中指定,因此这种方法无法运行due to a bug

在问题得到修复之前,我们可以按照以下方式完成:

dt2 <- dt[, lapply(mget(colsToKeep), weighted.mean, w = weights), 
            by = list(region, state, county)]
#    region state county     y1980    y1990
# 1:      1     1      1  100.0000 200.0000
# 2:      1     1      2   50.0000 100.0000
# 3:      1     1      3 1000.0000 500.0000
# 4:      1     1      4  113.2353 144.1176
# 5:      2     2      1   10.0000  50.0000
# 6:      2     2      2   34.0000  82.0000
# 7:      2     2      3  100.0000 100.0000

该漏洞仍然存在,或者第一种方法不再推荐?在2015年12月16日,我遇到了这个问题:Error in as.double(w) : cannot coerce type 'closure' to vector of type 'double' - PatrickT
1
抱歉,错误还没有修复 :-(。您可以尝试使用以下代码:dt[, lapply(mget(colsToKeep), weighted.mean, w=weights), by=.(region,state,country)]。您的错误似乎表明您正在使用函数作为输入使用 as.double`(这与错误无关)。 - Arun
所以您的建议是使用“mget()”而不是“as.list(.SD)[]”,对吗?(我知道您在“by=”后面使用的点是“list”的速记,因此代码的那一部分与您上面的解决方法相同)(关于错误消息,我认为我只是复制粘贴了OP的数据,但没有通过data.frame。) - PatrickT
1
是的,没错。我会编辑它以替换 as.list()。我当时一定是写错了,因为 mget() 当时不起作用(这是另一个 bug,但我们已经修复了)。 - Arun

1

我不了解 data.table,但你考虑过使用 dplyr 吗?我认为它几乎和 data.table 一样快。

library(dplyr)
df %>% 
  group_by(region, state, county) %>% 
  summarise(mean_80 = weighted.mean(y1980, weights), 
            mean_90 = weighted.mean(y1990, weights))
Source: local data frame [7 x 5]
Groups: region, state

  region state county   mean_80  mean_90
1      1     1      1  100.0000 200.0000
2      1     1      2   50.0000 100.0000
3      1     1      3 1000.0000 500.0000
4      1     1      4  113.2353 144.1176
5      2     2      1   10.0000  50.0000
6      2     2      2   34.0000  82.0000
7      2     2      3  100.0000 100.0000

谢谢你的帮助,但我需要使用data.table,并且你的答案没有解决我的新问题限制,即必须通过矢量动态指定列。 - Peutch
我的错,我应该更仔细地阅读你的帖子。如果你决定切换到dplyr,这里有一个可能会有帮助的例子。 - kferris10

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