将值替换为基于两个 类 的平均值

Replace value with the mean based on two classes

我有一个 dataset,其中包含 2 个日历变量(WeekHour)和 1 个 Amount 变量:

 Week Hour Amount
   35    1    367
   35    2    912
   36    1    813
   36    2    482
   37    1    112
   37    2    155
   35    1    182
   35    2    912
   36    1    551
   36    2    928
   37    1    125
   37    2    676

我希望用相同 Week/Hour 对的每次观察的平均值替换 Amount 的每个值。例如,这里有 2 个 obs。对于 (Week=35, Hour=1),Amount 值为 367182。因此,对于此示例,具有 (Week=35Hour=1) 的 2 行应将 Amount 替换为 mean(c(367,182)。最终输出应该是:

Week Hour Amount
  35    1  274.5
  35    2  912.0
  36    1  682.0
  36    2  705.0
  37    1  118.5
  37    2  415.5
  35    1  274.5
  35    2  912.0
  36    1  682.0
  36    2  705.0
  37    1  118.5
  37    2  415.5

我有以下代码可以解决这个问题。但是,对于数千行的完整数据集,速度非常慢。有什么方法可以用这种配对方式自动重塑吗?

dataset = data.frame(Week=c(35,35,36,36,37,37,35,35,36,36,37,37),
                     Hour = c(1,2,1,2,1,2,1,2,1,2,1,2),
                     Amount = c(367,912,813,482,112,155,182,912,551,928,125,676))

means <- reshape2::dcast(dataset, Week~Hour, value.var="Value", mean)

for (i in 1:nrow(dataset)) {
  print(i)
  dataset$Amount[i] <- means[means$Week==dataset$Week[i],which(colnames(means)==dataset$Hour[i])]
}

可能的解决方案dplyr

dataset %>% 
  group_by(Week, Hour) %>% 
  summarise(mean_amount = mean(Amount))

您按周和小时分组,并根据此条件计算平均值。

编辑

为了保持原始结构(行数)将代码更改为

dataset %>% 
  group_by(Week, Hour) %>% 
  mutate(Amount = mean(Amount))

如果这个想法只是通过 WeekHour 获得平均值 Amount,这将可行:

aggregate(Amount ~ ., dataset, mean)
  Week Hour Amount
1   35    1  274.5
2   36    1  682.0
3   37    1  118.5
4   35    2  912.0
5   36    2  705.0
6   37    2  415.5

编辑:

但是,如果想法是将平均值放回 dataset,那么这应该可行:

x <- aggregate(Amount ~ ., dataset, mean)
dataset$Amount <- x$Amount[match(apply(dataset[,1:2], 1, paste0, collapse = " "), 
                                 apply(x[,1:2], 1, paste0, collapse = " "))]
dataset
   Week Hour Amount
1    35    1  274.5
2    35    2  912.0
3    36    1  682.0
4    36    2  705.0
5    37    1  118.5
6    37    2  415.5
7    35    1  274.5
8    35    2  912.0
9    36    1  682.0
10   36    2  705.0
11   37    1  118.5
12   37    2  415.5

解释:

paste 将平均值数据帧 x 中前两列的行组合成字符串 dataset 使用函数 apply 它使用 match 在这些字符串上将平均值分配给 dataset

中的相应行

编辑 2:

或者,您可以分别使用 interaction%in% 进行此转换:

dataset$Amount <- x$Amount[match(interaction(dataset[,1:2]), interaction(x[,1:2]))]
# or:
dataset$Amount <- x$Amount[interaction(x[,1:2]) %in% interaction(dataset[,1:2])]

基础 R 解决方案:

dataset$Amount <- with(dataset, ave(dataset$Amount, dataset$Week, dataset$Hour, FUN = mean))

数据:

dataset = data.frame(Week=c(35,35,36,36,37,37,35,35,36,36,37,37),
                     Hour = c(1,2,1,2,1,2,1,2,1,2,1,2),
                     Amount = c(367,912,813,482,112,155,182,912,551,928,125,676))