计算除当前组外所有组的平均数

4

我有一个包含两个分组变量'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(所有与当前组 'a' 不同的 'mdl' )的 'pt' 的平均值。

期望结果:

#   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
5个回答

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

1
使用 data.table,按 'mkt' 计算总和和长度。然后,在每个 mkt-mdl 组内,计算平均值为 (mkt 总和 - 组总和) / (mkt 长度 - 组长度)
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

1
考虑使用基本的 R 语言,通过使用分解后的平均值计算方法 sum / count,对不同层次进行多个 ave 调用。
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

0
为了完整起见,这里提供另一种使用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
在编程中,mktmdlmdt中允许通过每个进行分组by = .EACHI)。

0
这里有一种方法,通过对不属于实际值mdlpr值进行子集划分,直接计算avgother的值,然后再计算平均值。
这与迄今为止发布的其他答案非常不同,我认为这是一个独立的答案。
# 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. 计算每个mktpr的总和和计数
  2. 计算每个mktmdlpr的总和和计数
  3. 从市场总和和计数中减去市场/型号总和和计数
  4. 计算avgother

这种方法

  • mkt分组
  • 在每个mkt内循环遍历mdl,
  • pr子集化以删除不属于实际mdl值的值
  • 然后直接计算mean()

性能注意事项:虽然代码本质上是一个一行代码,但并不意味着它是最快的。


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