【问题标题】:Efficient solution to (recursively) replace NAs with the mean of lags, by group按组(递归)用滞后的平均值替换 NA 的有效解决方案
【发布时间】:2018-11-22 15:56:13
【问题描述】:

我需要按组将 NA 替换为前三个值的平均值。 一旦一个 NA 被替换,它将作为计算下一个 NA 对应的平均值的输入(如果下一个 NA 在接下来的三个月内)。

这是一个例子:

id   date   value
1 2017-04-01 40
1 2017-05-01 40
1 2017-06-01 10
1 2017-07-01 NA
1 2017-08-01 NA
2 2014-01-01 27
2 2014-02-01 13

数据:

dt <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 2L, 2L), date = structure(c(17257, 17287, 17318, 17348, 17379, 16071, 16102), class = "Date"), value = c(40, 40, 10, NA, NA, 27, 13)), row.names = c(1L, 2L, 3L, 4L, 5L, 8L, 9L), class = "data.frame")

输出应如下所示:

id   date   value
1 2017-04-01 40.00
1 2017-05-01 40.00
1 2017-06-01 10.00
1 2017-07-01 30.00
1 2017-08-01 26.66
2 2014-01-01 27.00
2 2014-02-01 13.00

其中 26.66 = (30 + 10 + 40)/3

什么是执行此操作的有效方法(即避免 for 循环)?

【问题讨论】:

标签: r dplyr apply


【解决方案1】:

定义一个roll 函数,该函数将 3 个或更少的先前值作为列表和当前值,如果当前值不是 NA,则将前 2 个值与当前值作为列表返回,而前 2 个值与表示当前值是否为 NA。将其与Reduce 一起使用,并在结果中选择每个列表的最后一个值。然后使用ave 将所有这些应用于每个组。

roll <- function(prev, cur) {
  prev <- unlist(prev)
  list(tail(prev, 2), if (is.na(cur)) mean(prev) else cur)
}

reduce_roll <- function(x) {
  sapply(Reduce(roll, init = x[1], x[-1], acc = TRUE), tail, 1)
}

transform(dt, value = ave(value, id, FUN = reduce_roll))

给予:

  id       date    value
1  1 2017-04-01       40
2  1 2017-05-01       40
3  1 2017-06-01       10
4  1 2017-07-01       30
5  1 2017-08-01 26.66667
8  2 2014-01-01       27
9  2 2014-02-01       13

【讨论】:

  • 简洁的答案,谢谢。另外,我更正了截断的数据(这是我没有注意到的复制粘贴错误)。
【解决方案2】:

以下仅使用基础 R 并满足您的需要。

sp <- split(dt, dt$id)
sp <- lapply(sp, function(DF){
  for(i in which(is.na(DF$value))){
    tmp <- DF[seq_len(i - 1), ]
    DF$value[i] <- mean(tail(tmp$value, 3))
  }
  DF
})

result <- do.call(rbind, sp)
row.names(result) <- NULL

result
#  id       date    value
#1  1 2017-01-04 40.00000
#2  1 2017-01-05 40.00000
#3  1 2017-01-06 10.00000
#4  1 2017-01-07 30.00000
#5  1 2017-01-08 26.66667
#6  2 2014-01-01 27.00000
#7  2 2014-01-02 13.00000

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    • 2012-03-08
    • 2016-10-03
    • 2021-03-17
    相关资源
    最近更新 更多