我正在尝试编写R代码,它充当一个“移动窗口”,只是使用内存(状态)。我已经知道(多亏了this question)如何将函数应用到元素的后续元组中。例如,如果我希望编写一个(简单的)移动平均线,并具有典型的周期4,我将执行以下操作:
mapply(myfunc, x[1:(length(x)-4)], x[2:(length(x)-3)], x[3:(length(x)-2)], x[4:(length(x)-1)])其中myfunc是一个带有4个参数的函数,它计算它们的平均值(我不能使用mean,因为它只需要一个参数,而且我不知道如何使这4个参数成为一个向量)。但是,这是相当麻烦的,如果典型的周期是100,比如说,我不知道怎么做。
这是我的第一个问题:我如何概括这一点?
但这里还有另一个问题:假设我希望应用的函数能够保存状态。一个简单的例子是记录到目前为止它应用于多少个值。另一个例子是指数移动平均(EMA),它实际上不是一个窗口函数,而是一个作用于单个值但保持状态的函数(最后一个结果是平均值)。
我如何编写一个函数,当它应用于一个向量时,一个地处理它的值,返回一个长度相同的向量,它每次都能保留它的最后一个输出,或者在计算过程中保存任何其他的“状态”?例如,在Python中,我会为此使用类,但在R中这是相当困难的。
重要注意事项:,我对辅助R包(如zoo或TTR )不感兴趣,为我做这项工作。我正在努力学习R,无论如何,我想编写的函数虽然与MA或EMA有相似之处,但它们都是自定义的,并且在这些包中都不存在。
发布于 2014-04-28 20:34:36
关于你的第一个问题,
n <- length(x)
k <- 4
r <- embed(x, n-k)[1:k, seq(n-k, 1)]
do.call("mapply", c("myfunc", split(r, 1:k)))关于第二个问题,可以使用Reduce迭代向量保存状态。
发布于 2014-04-28 21:16:44
对于这种情况,您应该考虑使用普通的for循环:
x <- runif(10000)
k <- 100
n <- length(x)
res <- numeric(n - k)
library(microbenchmark)
microbenchmark(times=5,
for(i in k:n) res[i - k + 1] <- sum(vec[i:(i + k)]),
{
r <- embed(x, n-k)[1:k, seq(n-k, 1)]
gg <- do.call("mapply", c("sum", split(r, 1:k)))
},
flt <- filter(x, rep(1, k))
)生产:
Unit: milliseconds
min lq median uq max neval
for 163.5403 164.4929 165.2543 166.6315 167.0608 5
embed/mapply 1255.2833 1307.3708 1338.2748 1341.5719 1405.1210 5
filter 6.7101 6.7971 6.8073 6.8161 6.8991 5现在,结果是不一样的,我并不假装完全理解GGrothendieck对embed所做的事情,但是一般来说,只要先初始化结果向量,for循环就和*pply函数一样快。加窗口的计算不能很好地用于向量化,所以最好使用for循环。
编辑:正如一些人在评论中指出的那样,似乎有一个内部实现的函数要做(filter) --这要快得多,所以这似乎是最好的选择(尽管您应该再次确认它实际上做了您想做的事情,但是结果并不完全相同,而且我个人不太熟悉这个函数;在它的默认配置中,它似乎做了一个滚动加权和,或者如果权重是1,则使用居中窗口)。
https://stackoverflow.com/questions/23350408
复制相似问题