【问题标题】:Replace value with the mean based on two classes用基于两个类别的平均值替换值
【发布时间】:2020-05-07 20:20:16
【问题描述】:

我有一个 dataset 有 2 个日历变量(Week & Hour)和 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

我希望将Amount 的每个值替换为具有相同周/小时对的每个观察值的平均值。例如,这里有 2 个 obs。对于 (Week=35, Hour=1),Amount 的值为 367182。因此,对于此示例,带有 (Week=35, Hour=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])]
}

【问题讨论】:

    标签: r pivot mean


    【解决方案1】:

    dplyr 的可能解决方案:

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

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

    编辑

    为了保持原来的结构(行数)改变代码

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

    【讨论】:

    • 但这并不是 OP 真正想要的。
    • 已编辑,现在应该是 OP 要求的。
    【解决方案2】:

    如果这个想法只是通过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
    

    解释:

    这个pastes 将平均值数据帧xdataset 中的前两列的行组合成字符串,使用函数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])]
    

    【讨论】:

    • 我又添加了两个解决方案。
    【解决方案3】:

    基础 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))
    

    【讨论】:

      猜你喜欢
      • 2018-12-13
      • 2023-03-08
      • 2020-08-25
      • 2020-08-15
      • 2021-10-10
      • 2022-11-16
      • 2013-04-01
      • 2019-03-21
      • 2018-02-05
      相关资源
      最近更新 更多