weighted means by group and column

*爱你&永不变心* 提交于 2019-11-28 10:31:04

I suggest to use package data.table:

library(data.table)
dt <- as.data.table(df)
dt2 <- dt[,lapply(.SD,weighted.mean,w=weights),by=list(region,state,county)]
print(dt2)

   region state county   weights     y1980    y1990    y2000
1:      1     1      1  10.00000  100.0000 200.0000  50.0000
2:      1     1      2   5.00000   50.0000 100.0000 200.0000
3:      1     1      3 120.00000 1000.0000 500.0000 250.0000
4:      1     1      4  13.47059  113.2353 144.1176 223.5294
5:      2     2      1   1.00000   10.0000  50.0000 150.0000
6:      2     2      2  34.00000   34.0000  82.0000  64.0000
7:      2     2      3  20.00000  100.0000 100.0000  10.0000

If you want you can merge with the original data.table afterwards:

merge(dt,dt2,by=c("region","state","county"))

   region state county weights.x y1980.x y1990.x y2000.x weights.y   y1980.y  y1990.y  y2000.y
1:      1     1      1        10     100     200      50  10.00000  100.0000 200.0000  50.0000
2:      1     1      2         5      50     100     200   5.00000   50.0000 100.0000 200.0000
3:      1     1      3       120    1000     500     250 120.00000 1000.0000 500.0000 250.0000
4:      1     1      4         2      25     100     400  13.47059  113.2353 144.1176 223.5294
5:      1     1      4        15     125     150     200  13.47059  113.2353 144.1176 223.5294
6:      2     2      1         1      10      50     150   1.00000   10.0000  50.0000 150.0000
7:      2     2      2        10      10      10     200  34.00000   34.0000  82.0000  64.0000
8:      2     2      2        40      40     100      30  34.00000   34.0000  82.0000  64.0000
9:      2     2      3        20     100     100      10  20.00000  100.0000 100.0000  10.0000

I figured out how to nest sapply inside apply to obtain weighted averages by group and column without using an explicit for-loop. Below I provide the data set, the apply statement and an explanation of how the apply statement works.

Here is the data set from the original post:

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)

# add a group variable to the data set

group <- paste(df$region, '_', df$state, '_', df$county, sep = "")
df    <- data.frame(group, df)

Here is the apply / sapply code to obtain the desired weighted means.

apply(df[,6:ncol(df)], 2, function(x) {sapply(split(data.frame(df[,1:5], x), df$group), function(y) weighted.mean(y[,6], w = y$weights))})

Here is an explanation of the above apply / sapply statement:

  1. Note that the apply statement selects columns 6 through 8 of df one at a time.

  2. For each of those three columns I create a new data frame combining that individual column with the first five columns of df.

  3. Then I split each of those new 6-column data frames into chunks by the grouping variable df$group.

  4. Once a data frame of six columns has been split into its individual chunks I calculate the weighted mean for the last column (the 6th column) of each chunk.

Here is the result:

          y1980    y1990    y2000
1_1_1  100.0000 200.0000  50.0000
1_1_2   50.0000 100.0000 200.0000
1_1_3 1000.0000 500.0000 250.0000
1_1_4  113.2353 144.1176 223.5294
2_2_1   10.0000  50.0000 150.0000
2_2_2   34.0000  82.0000  64.0000
2_2_3  100.0000 100.0000  10.0000

Using package data.table is nice, but until I become more familiar with its syntax and how that syntax differs from the syntax of data.frame I thought it would be good to know how to use apply and sapply to do the same thing. Now I can use both approaches, plus the approaches in the original post, to check one against the others and learn more about all of them.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!