【问题标题】:Calculate mean of all groups except the current group计算除当前组之外的所有组的平均值
【发布时间】:2021-06-24 12:16:34
【问题描述】:

我有一个包含两个分组变量“mkt”和“mdl”以及一些值“pr”的数据框:

df <- data.frame(mkt = c(1,1,1,1,2,2,2,2,2),
                 mdl = c('a','a','b','b','b','a','b','a','b'),
                 pr = c(120,120,110,110,145,130,145,130, 145))

df

  mkt mdl  pr
1   1   a 120
2   1   a 120
3   1   b 110
4   1   b 110
5   2   b 145
6   2   a 130
7   2   b 145
8   2   a 130
9   2   b 145

在每个 'mkt' 中,每个 'mdl' 的平均 'pr' 应该计算为同一 'mkt' 中所有其他 'mdl' 的 'pr' 的平均值,除了当前的“mdl”。

例如,对于由mkt == 1mdl == a 定义的组,'avgother' 计算为mkt == 1(相同'mkt')和mdl == b(所有其他' mdl' 比当前组a)。

想要的结果:

#   mkt mdl  pr avgother
# 1   1   a 120      110
# 2   1   a 120      110
# 3   1   b 110      120
# 4   1   b 110      120
# 5   2   b 145      130
# 6   2   a 130      145
# 7   2   b 145      130
# 8   2   a 130      145
# 9   2   b 145      130

【问题讨论】:

    标签: r group-by average mean


    【解决方案1】:

    首先获取每个mktmdl 值的平均值,然后为每个mkt 排除当前值并获取剩余值的平均值。

    library(dplyr)
    library(purrr)
    
    df %>%
      group_by(mkt, mdl) %>%
      summarise(avgother = mean(pr)) %>%
      mutate(avgother = map_dbl(row_number(), ~mean(avgother[-.x]))) %>%
      ungroup %>%
      inner_join(df, by = c('mkt', 'mdl'))
    
    #    mkt mdl   avgother    pr
    #  <dbl> <chr>    <dbl> <dbl>
    #1     1 a          110   120
    #2     1 a          110   120
    #3     1 b          120   110
    #4     1 b          120   110
    #5     2 a          145   130
    #6     2 a          145   130
    #7     2 b          130   145
    #8     2 b          130   145
    #9     2 b          130   145
    

    【讨论】:

      【解决方案2】:

      使用data.table,通过“mkt”计算总和和长度。然后,在每个 mkt-mdl 组内,计算平均值为(mkt sum - group sum) / (mkt length - group length)

      library(data.table)
      setDT(df)[ , `:=`(s = sum(pr), n = .N), by = mkt]
      df[ , avgother := (s - sum(pr)) / (n - .N), by = .(mkt, mdl)]
      df[ , `:=`(s = NULL, n = NULL)]
      #    mkt mdl  pr avgother
      # 1:   1   a 120      110
      # 2:   1   a 120      110
      # 3:   1   b 110      120
      # 4:   1   b 110      120
      # 5:   2   b 145      130
      # 6:   2   a 130      145
      # 7:   2   b 145      130
      # 8:   2   a 130      145
      # 9:   2   b 145      130
      

      【讨论】:

        【解决方案3】:

        考虑具有多个ave 的基R 调用,使用sum / count 的均值分解版本进行不同级别的分组计算:

        df <- within(df, {
              avgoth <- (ave(pr, mkt, FUN=sum) - ave(pr, mkt, mdl, FUN=sum)) /
                          (ave(pr, mkt, FUN=length) - ave(pr, mkt, mdl, FUN=length))
        })
        
        df
        #   mkt mdl  pr avgoth
        # 1   1   a 120    110
        # 2   1   a 120    110
        # 3   1   b 110    120
        # 4   1   b 110    120
        # 5   2   b 145    130
        # 6   2   a 130    145
        # 7   2   b 145    130
        # 8   2   a 130    145
        # 9   2   b 145    130
        

        【讨论】:

          【解决方案4】:

          为了完整起见,这里是另一个data.table 方法,它使用按每个 i 分组,即同时加入和聚合。

          为了演示,我们使用了一个增强的样本数据集,该数据集具有包含 3 种产品的第三市场:

          df <- data.frame(mkt = c(1,1,1,1,2,2,2,2,2,3,3,3),
                           mdl = c('a','a','b','b','b','a','b','a','b', letters[1:3]),
                           pr = c(120,120,110,110,145,130,145,130, 145, 1:3))
          
          library(data.table)
          mdt <- setDT(df)[, .(mdl, s = sum(pr), .N), by = .(mkt)]
          df[mdt, on = .(mkt, mdl), avgother := (sum(pr) - s) / (.N - N), by = .EACHI][]
          
              mkt mdl  pr avgother
           1:   1   a 120    110.0
           2:   1   a 120    110.0
           3:   1   b 110    120.0
           4:   1   b 110    120.0
           5:   2   b 145    130.0
           6:   2   a 130    145.0
           7:   2   b 145    130.0
           8:   2   a 130    145.0
           9:   2   b 145    130.0
          10:   3   a   1      2.5
          11:   3   b   2      2.0
          12:   3   c   3      1.5
          

          临时表mdt 包含每个mkt 内的价格总和和计数,但在市场内为每个产品mdl 复制:

          mdt
          
              mkt mdl   s N
           1:   1   a 460 4
           2:   1   a 460 4
           3:   1   b 460 4
           4:   1   b 460 4
           5:   2   b 695 5
           6:   2   a 695 5
           7:   2   b 695 5
           8:   2   a 695 5
           9:   2   b 695 5
          10:   3   a   6 3
          11:   3   b   6 3
          12:   3   c   6 3
          

          mdt 中有mkt mdl 允许按每个 i 分组 (by = .EACHI)

          【讨论】:

            【解决方案5】:

            这是一种在计算平均值之前通过子集pr 值直接计算avgother 的方法,这些值不属于mdl 的实际值。

            这与迄今为止发布的其他答案完全不同,这有理由将其作为单独的答案发布,恕我直言。

            # enhanced sample dataset covering more corner cases
            df <- data.frame(mkt = c(1,1,1,1,2,2,2,2,2,3,3,3,4),
                             mdl = c('a','a','b','b','b','a','b','a','b', letters[1:3],'d'),
                             pr = c(120,120,110,110,145,130,145,130, 145, 1:3, 9))
            
            library(data.table)
            setDT(df)[, avgother := sapply(mdl, function(m) mean(pr[m != mdl])), by = mkt][]
            
                mkt mdl  pr avgother
             1:   1   a 120    110.0
             2:   1   a 120    110.0
             3:   1   b 110    120.0
             4:   1   b 110    120.0
             5:   2   b 145    130.0
             6:   2   a 130    145.0
             7:   2   b 145    130.0
             8:   2   a 130    145.0
             9:   2   b 145    130.0
            10:   3   a   1      2.5
            11:   3   b   2      2.0
            12:   3   c   3      1.5
            13:   4   d   9      NaN
            

            方法之间的区别

            其他答案或多或少共享相同的方法(尽管以不同的方式实现)

            1. 为每个mkt 计算pr 的总和和计数
            2. 为每个mktmdl 计算pr 的总和和计数
            3. 从 mkt 总和和计数中减去 mkt/mdl 总和和计数
            4. 计算avgother

            这种方法

            • mkt分组
            • 在每个mkt 内循环通过mdl
            • 子集pr 删除属于mdl 实际值的值
            • 在直接计算mean()之前。

            关于性能的警告:虽然代码本质上是单行,但这并不意味着它是最快的。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-01-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-04-18
              • 2019-09-01
              • 2016-06-21
              • 1970-01-01
              相关资源
              最近更新 更多