我有一个data.table,它需要在前n天的数据中计算移动平均值(为了简单起见,我们使用n = 2,而不是包括当前日)用于指定的分组(ID1,ID2)。移动平均线应尝试包括每个ID1-ID2对的最后2天值。我想计算移动平均值以两种不同的方式处理NA:1。仅计算何时有2个非NA观测值,否则avg应为NA(例如ID1-ID2中的前2天将始终具有NA)。 2.根据过去2天内的任何非NA观测值计算移动平均值(na.rm = TRUE?)。
我试过使用zoo包和其中的各种函数。我已经确定了以下内容(使用shift()来排除平均值中考虑的一周,以相反顺序放置日期以突出显示日期并不总是最初排序):
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")]
我似乎无法按多列分组。 VALUE以NA值开头/结尾的分组似乎也会引起问题。我对在data.table框架中有意义的任何解决方案持开放态度,尤其是frollmean(需要更新我的R + data.table版本)。我不知道是否需要以指定的对齐方式(例如“右”)对日期进行不同的排序。
我希望我的输出看起来像下面这样,除了按照ID1-ID2分组的最早日期排序:
DATE ID1 ID2 VALUE VALUE_AVG
1: 2018-01-04 A 1 1 2.5
2: 2018-01-03 A 1 2 3.5
3: 2018-01-02 A 1 3 NA
4: 2018-01-01 A 1 4 NA
5: 2018-01-04 A 2 5 6.5
6: 2018-01-03 A 2 6 7.5
7: 2018-01-02 A 2 7 NA
8: 2018-01-01 A 2 8 NA
9: 2018-01-04 B 1 9 10.5
10: 2018-01-03 B 1 10 11.5
11: 2018-01-02 B 1 11 NA
12: 2018-01-01 B 1 12 NA
13: 2018-01-04 B 2 13 14.5
14: 2018-01-03 B 2 14 15.0
15: 2018-01-02 B 2 15 NA
16: 2018-01-01 B 2 NA NA
我的代码似乎大致实现了样本数据的预期结果。然而,当尝试在大数据集上运行相同的代码4周平均值,其中ID1和ID2都是整数时,我得到以下错误:
Error in seq.default(start.at, NROW(data), by = by) :
wrong sign in 'by' argument
我的结果似乎适用于大多数ID1-ID2组合,但有ID1的特定情况,其中VALUE具有前导和尾随NA。我猜这是导致这个问题,虽然它没有上面的例子。
使用shift
不必要地使这复杂化。 rollapply
已经可以处理它。在rollapplyr
中指定:
list(-seq(2))
的宽度,指定它应该作用于偏移-1和-2。partial = TRUE
表示如果前面的行少于2,它将使用那里的任何东西。fill = NA
用NA填充空单元格仅考虑有2个先前的非NA给出NA的情况,否则删除partial = TRUE
和na.rm = TRUE
参数。
如果较少的先前行,则取前两行或更少行中的非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
赠送:
DATE ID1 ID2 VALUE VALUE_AVG
1: 2018-01-01 A 1 4 NA
2: 2018-01-02 A 1 3 4.0
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 8.0
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 12.0
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 NaN
15: 2018-01-03 B 2 14 15.0
16: 2018-01-04 B 2 13 14.5
如果先前2行中的任何一行是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),
by = c("ID1", "ID2")]
testdata
赠送:
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
也许是这样的:
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")]