R 如何按指定分组计算移动平均值并处理NAs

R 如何按指定分组计算移动平均值并处理NAs,r,data.table,zoo,moving-average,rollapply,R,Data.table,Zoo,Moving Average,Rollapply,我有一个data.table,它需要在前n天的数据上计算移动平均值。为了简单起见,我们使用n=2,不包括指定分组ID1、ID2的当天。移动平均线应尝试包括每个ID1-ID2对的最后2天值。我想用两种不同的方法计算移动平均值来处理NAs: 1.仅当有2个非NA观测值时计算,否则平均值应为NA,例如,ID1-ID2中的前2天将始终有NAs。 2.根据最近2天内的任何非NA观测值计算移动平均值NA。rm=真 我尝试过使用zoo软件包和其中的各种功能。我已经确定了以下使用的班次,以排除平均值中考虑的一周

我有一个data.table,它需要在前n天的数据上计算移动平均值。为了简单起见,我们使用n=2,不包括指定分组ID1、ID2的当天。移动平均线应尝试包括每个ID1-ID2对的最后2天值。我想用两种不同的方法计算移动平均值来处理NAs: 1.仅当有2个非NA观测值时计算,否则平均值应为NA,例如,ID1-ID2中的前2天将始终有NAs。 2.根据最近2天内的任何非NA观测值计算移动平均值NA。rm=真

我尝试过使用zoo软件包和其中的各种功能。我已经确定了以下使用的班次,以排除平均值中考虑的一周,将日期按相反顺序排列,以突出显示最初并不总是按顺序排列的日期:

library(zoo)
library(data.table)
DATE = rev(rep(seq(as.Date("2018-01-01"),as.Date("2018-01-04"),"day"),4))
VALUE =seq(1,16,1)
VALUE[16] <- NA
ID1 = rep(c("A","B"),each=8)
ID2 = rep(1:2,2,each=4)
testdata = data.frame (DATE, ID1, ID2, VALUE)
setDT(testdata)[order(DATE), VALUE_AVG := shift(rollapplyr(VALUE, 2, mean, 
na.rm=TRUE,fill = NA)), by = c("ID1", "ID2")]
我的代码似乎大致达到了示例数据的预期结果。然而,当尝试在大数据集上运行相同的代码,平均运行4周,其中ID1和ID2都是整数时,我得到以下错误:

Error in seq.default(start.at, NROW(data), by = by) : 
  wrong sign in 'by' argument
我的结果似乎适用于大多数ID1-ID2组合,但在ID1的某些特定情况下,值具有前导和尾随NAs。我猜这是导致问题的原因,尽管上面的例子中没有这样做。

可能类似于:

setorder(setDT(testdata), ID1, ID2, DATE)
testdata[order(DATE), VALUE_AVG := shift(
        rollapplyr(VALUE, 2L, function(x) if(sum(!is.na(x)) > 0L) mean(x, na.rm=TRUE), fill = NA_real_)
    ), by = c("ID1", "ID2")]
使用shift会不必要地使这变得复杂。rollapply已经可以自己处理了。在rollapplyr中指定:

list-seq2的宽度,用于指定它应作用于偏移量-1和-2

partial=TRUE表示如果前面的行少于2行,它将使用其中的任何行

fill=NA用NA填充空单元格

na.rm=TRUE以删除任何NAs并仅对剩余单元格执行平均值。如果前面的单元格均为NA,则平均值为NaN

仅考虑有2个先验NNA给出NA的情况,否则删除部分=真和NA rm=真参数。

第一例 取前2行中非NAs的平均值,如果前2行较少,则取较少的行

testdata <- data.table(DATE, ID1, ID2, VALUE, key = c("ID1", "ID2", "DATE"))
testdata[, VALUE_AVG := 
  rollapplyr(VALUE, list(-seq(2)), mean, fill = NA, partial = TRUE, na.rm = TRUE),
  by = c("ID1", "ID2")]
testdata
testdata <- data.table(DATE, ID1, ID2, VALUE, key = c("ID1", "ID2", "DATE"))
testdata[, VALUE_AVG := 
  rollapplyr(VALUE, list(-seq(2)), mean, fill = NA),
  by = c("ID1", "ID2")]
testdata
第二种情况 如果前两行中的任何一行为NA,或者前两行少于2行,则为NA

testdata <- data.table(DATE, ID1, ID2, VALUE, key = c("ID1", "ID2", "DATE"))
testdata[, VALUE_AVG := 
  rollapplyr(VALUE, list(-seq(2)), mean, fill = NA, partial = TRUE, na.rm = TRUE),
  by = c("ID1", "ID2")]
testdata
testdata <- data.table(DATE, ID1, ID2, VALUE, key = c("ID1", "ID2", "DATE"))
testdata[, VALUE_AVG := 
  rollapplyr(VALUE, list(-seq(2)), mean, fill = NA),
  by = c("ID1", "ID2")]
testdata

谢谢@chinsoon12;您的回答似乎对我产生了相同的结果,对大多数情况都是正确的,但对于特定的ID1-ID2对,包括开始时的拉伸,其值为NA。FWIW我在运行您的建议时收到以下错误:RHS“logical”的类型必须与LHS“double”匹配。对于最快的情况,检查和强制将对性能产生太大的影响。更改目标列的类型,或强制使用“=yourself”的RHS,例如,通过使用1L而不是1,我尝试将ID1和ID2调整为数字,但没有帮助。请尝试使用NA_real_而不是NA。请看编辑。最好只使用Gabor解决方案。谢谢@G.Grothendieck。我感谢你的解释。我尝试将您的解决方案纳入每周数据,平均前4周。我改为-seq4,但保留了所有其他内容。ID1和ID2已从整数转换为数字。在这些小的调整之后,我从实施第二种情况中收到了以下错误:seq.defaultstart.at,NROWdata,by=by中的错误:错误的登录“by”参数我发现有问题的ID1-ID2对涉及前导/尾随NAs。该解决方案确实适用于行为正常的配对。有什么想法吗?在为同一扩展应用程序运行解决方案的4周MA的第一个案例时,我收到了以下错误:我在实现第一个案例后收到了以下错误:RHS“logical”的类型必须与LHS“double”匹配。对于最快的情况,检查和强制将对性能产生太大的影响。更改目标列的类型,或强制RHS为:=您自己,例如,通过使用1L而不是1,您将需要提供可复制的代码和输入,因为它适用于问题中显示的输入。您可以查看imputeTS包。它有一个插补功能缺失数据替换称为na.ma移动平均插补。
          DATE ID1 ID2 VALUE VALUE_AVG
 1: 2018-01-01   A   1     4        NA
 2: 2018-01-02   A   1     3        NA
 3: 2018-01-03   A   1     2       3.5
 4: 2018-01-04   A   1     1       2.5
 5: 2018-01-01   A   2     8        NA
 6: 2018-01-02   A   2     7        NA
 7: 2018-01-03   A   2     6       7.5
 8: 2018-01-04   A   2     5       6.5
 9: 2018-01-01   B   1    12        NA
10: 2018-01-02   B   1    11        NA
11: 2018-01-03   B   1    10      11.5
12: 2018-01-04   B   1     9      10.5
13: 2018-01-01   B   2    NA        NA
14: 2018-01-02   B   2    15        NA
15: 2018-01-03   B   2    14        NA
16: 2018-01-04   B   2    13      14.5