R 按组和列加权平均数

R 按组和列加权平均数,r,for-loop,apply,sapply,R,For Loop,Apply,Sapply,我希望获得几列(实际上大约60列)的加权平均数。这个问题非常类似于:刚问过 到目前为止,我提出了两种获得加权平均数的方法: 对每列使用单独的sapply语句 将sapply语句放入for循环中 但是,我觉得必须有一种方法可以在sapply语句中插入apply语句,反之亦然,从而消除for循环。我尝试了许多排列,但都没有成功。我还研究了sweep函数 这是我到目前为止的代码 df <- read.table(text= " region state county

我希望获得几列(实际上大约60列)的加权平均数。这个问题非常类似于:刚问过

到目前为止,我提出了两种获得加权平均数的方法:

  • 对每列使用单独的
    sapply
    语句
  • sapply
    语句放入
    for循环中
  • 但是,我觉得必须有一种方法可以在
    sapply
    语句中插入
    apply
    语句,反之亦然,从而消除
    for循环
    。我尝试了许多排列,但都没有成功。我还研究了
    sweep
    函数

    这是我到目前为止的代码

    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)
    
    # obtain weighted averages for y1980, y1990 and y2000 
    # one column at a time using one sapply per column
    
    sapply(split(df, df$group), function(x) weighted.mean(x$y1980, w = x$weights))
    sapply(split(df, df$group), function(x) weighted.mean(x$y1990, w = x$weights))
    sapply(split(df, df$group), function(x) weighted.mean(x$y2000, w = x$weights))
    
    # obtain weighted average for y1980, y1990 and y2000
    # one column at a time using a for-loop
    
    y <- matrix(NA, nrow=7, ncol=3)
    group.b <- df[!duplicated(df$group), 1]
    
    for(i in 6:8) { 
    
        y[,(i-5)] <- sapply(split(df[,c(1:5,i)], df$group), function(x) weighted.mean(x[,6], w = x$weights))
    
    }
    
    # add weighted averages to the original data set
    
    y2 <- data.frame(group.b, y)
    colnames(y2) <- c('group','ave1980','ave1990','ave2000')
    y2
    
    y3 <- merge(df, y2, by=c('group'), all = TRUE)
    y3
    

    我建议使用包数据。表:

    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
    

    我想出了如何在
    中嵌套
    sapply
    以获得分组和列的加权平均值,而无需使用显式的
    for循环
    。下面我提供了数据集、
    apply
    语句以及
    apply
    语句的工作原理说明

    以下是原始帖子中的数据集:

    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)
    
    下面是对上述
    apply
    /
    sapply
    语句的解释:

  • 请注意,
    apply
    语句一次选择
    df
    的第6列到第8列

  • 对于这三列中的每一列,我创建了一个新的数据框,将单个列与
    df
    的前五列组合在一起

  • 然后,我通过分组变量
    df$group
    将每个新的6列数据帧分割成块

  • 一旦一个由六列组成的数据帧被分割成单独的数据块,我计算每个数据块最后一列(第六列)的加权平均值

  • 结果如下:

              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
    

    使用package
    data.table
    很好,但是在我更加熟悉它的语法以及该语法与
    data.frame
    的语法有何不同之前,我想知道如何使用
    apply
    sapply
    来做同样的事情会很好。现在,我可以使用这两种方法,再加上原始帖子中的方法,检查其中一种方法与其他方法的优劣,并进一步了解所有方法。

    继续提问,但如果您提供一些虚拟数据并演示预期结果,我(我们?)将不胜感激。对不起。我已将数据集“y3”的内容添加到我的帖子中。虚拟数据在数据集“df”中,代码似乎在我的计算机上运行。此解决方案有点复杂,其性能可能不是很好(但我还没有进行基准测试)。你基本上是在试图重新发明轮子。如果您想要好的语法,您应该查看package
    plyr
    。我演示了
    data.table
    解决方案,因为它在处理大数据集时速度更快。所有split-apply-combine函数都允许您指定多个分组变量。你的速度快了2.5倍。谢谢您的建议。如何限制仅在此处的一部分列上执行weighted.mean,例如
    list(y1980,y1990)
    仅限?@FooBar Use
    .SDcols
    。请参阅
    帮助(“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)
    
    # add a group variable to the data set
    
    group <- paste(df$region, '_', df$state, '_', df$county, sep = "")
    df    <- data.frame(group, df)
    
    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))})
    
              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