R-在多列上执行Zoo rollapply / rollmean

时间:2019-06-12 14:05:16

标签: r dataframe zoo rollapply

我想计算每个15天的滚动平均值(前后)。这是一个测试框架:

date_list = seq(ymd('2000-01-15'),ymd('2010-09-18'),by='day')
testframe = data.frame(Date = date_list)
testframe$Day = substr(testframe$Date, start = 6, stop = 10)
testframe$V1 = runif(3900, 2.0, 35.0)
testframe$V2 = runif(3900, 5.0, 40.0)
testframe$V3 = runif(3900, -10.0, 10.0)
testframe$V4 = seq(from = 5, to = 45, length.out = 3900)

我知道如何为每列计算:

library(zoo)
rollmean(testframe$V4, 31)
rollapply(testframe$V4, 31, mean)

但是如何一次为每一列执行此操作?我认为我必须为此排除“日期和日期”列,但是如何在命令中执行此操作?在前15天和最后15天如何在带有NA的旧测试框架中获得结果?

我尝试过:

testframe[paste0("new_col",1:4)] <- lapply(testframe[,3:6], rollapply, FUN = mean, width = 31)

但这不起作用!

2 个答案:

答案 0 :(得分:2)

rollmean和rollapply的默认操作是对每一列进行操作。请查看?rollapply

library(zoo)
rollmeanr(BOD, 2, fill = NA)

给出以下内容,其中rollmean应用于内置BOD的每一列:

     Time demand
[1,]   NA     NA
[2,]  1.5   9.30
[3,]  2.5  14.65
[4,]  3.5  17.50
[5,]  4.5  15.80
[6,]  6.0  17.70

如果您只想将均值应用于某些列,请指定:

if (exists("BOD", .GlobalEnv)) rm(BOD)
BOD[1:2] <- rollmeanr(BOD[1:2], 2, fill = NA)

请注意,如果您拥有除索引列以外的所有数字列,那么仅使用Zoo对象而不是尝试将所有内容强制放入data.frame会更容易,因为在时间序列上效果不佳。

if (exists("BOD", .GlobalEnv)) rm(BOD)
z <- read.zoo(BOD)
rollmeanr(z, 2)

答案 1 :(得分:1)

虽然@ G.Grothendieck的回答在许多方面都比较好,但以下情况可能会导致您的情况出问题:

testframe[paste0("new_col",1:4)] <- lapply(testframe[,3:6], rollapply, FUN = mean, width = 31)
# Error in mean.default(X[[i]], ...) : 'trim' must be numeric of length one

这部分是因为您要传递FUN=,但这也是lapply的参数名称,因此在此有效地使用了它:

testframe[paste0("new_col",1:4)] <- lapply(testframe[,3:6], function(a) mean(a, trim=rollapply, width = 31))

mean的第二个参数是trim=,在这种情况下正在传递函数rollapply,显然是不正确的。

下一步将是

testframe[paste0("new_col",1:4)] <- lapply(testframe[,3:6], function(a) rollapply(a, FUN = mean, width = 31))
# Error in `[<-.data.frame`(`*tmp*`, paste0("new_col", 1:4), value = list( : 
#   replacement element 1 has 3870 rows, need 3900

这是因为单个rollapply不会返回前15个值(最后30个观察值)。您可以使用fill=NA来解决此问题:

testframe[paste0("new_col",1:4)] <- lapply(testframe[,3:6], function(a) rollapply(a, FUN = mean, width = 31, fill = NA))
# (no warnings/errors)