如何使用特定时间 window 调用函数?

How do I call a function using a specific time window?

假设我有一个动物园对象(或者它可能是一个 data.frame),它在 "time of day" 上有一个索引并且有一些值(见下面的示例数据):

                    val
...
2006-08-01 12:00    23
2006-08-01 12:01    24
2006-08-01 12:02    25
2006-08-01 12:03    26
2006-08-01 12:04    27
2006-08-01 12:05    28
2006-08-01 12:06    29
...
2006-08-02 12:00    123
2006-08-02 12:01    124
2006-08-02 12:02    125
2006-08-02 12:03    126
2006-08-02 12:04    127
...

我想在每次出现该间隔​​时从 12:01 - 12:03(即类似于 zoo::rollapply)调用一个自定义函数(称之为 custom.func(vals))所以在这个例子中,每天。我该怎么做?


注意事项(为了稳健性,考虑以下边缘情况也很好,但不是必需的):

  1. 不要假设我每天都有 12:01 - 12:03 的值
  2. 不要假设整个范围 12:01 - 12:03 每天都存在。有些日子我可能只有 12:01 和 12:02 但可能会丢失 12:03
  3. 如果我希望我的 custom.func(vals) 在日期边界被调用怎么办,比如使用 23:58 - 00:12 中的 val

我建议 runner package which allows to compute any rolling function on irregular time series. Function runner 等同于 rollApply,区别在于它可以依赖于日期。 runner 允许在 window 长度上应用任何 R 函数,长度由 k 定义,日期为 idx(或任何整数)。下面的示例计算 5 分钟(5*60 秒)window 跨度的回归。算法不关心是否会有日变化,每次只计算 5 分钟(例如 23:56-00:01)。

创建数据:

set.seed(1)
x <- cumsum(rnorm(1000))
y <- 3 * x + rnorm(1000)
time <- as.POSIXct(cumsum(sample(60:120, 1000, replace = TRUE)), 
                   origin = Sys.Date()) # unequaly spaced time series
data <- data.frame(time, y, x)

滑动时调用的自定义函数windows:

library(runner)

running_regression <- function(idx) {
  predict(lm(y ~ x, data = data))[max(idx)]
}

data$pred <- runner(seq_along(x), 
                    k = 60 * 5,
                    idx = time,
                    f = running_regression)



一旦我们创建了具有滚动 5 分钟预测的数据集,那么我们就可以仅过滤特定的 windows - 此处,仅过滤一小时的第 1 分钟。这意味着我们总是保持 {hh}:56 - {hh+1}:01


library(dplyr)
library(lubridate)
filtered <-
  data %>% 
  filter(minute(time) == 1)


plot(data$time, data$y, type = "l", col = "red")
points(filtered$time, filtered$pred, col = "blue")

vignette 中还有一些其他示例如何使用 runner

假设我们的输入是最后注释中给出的POSIXct动物园对象z

创建一个字符向量 times,其中每个 z 的元素一个元素,形式为 HH:MM。然后创建一个逻辑 ok 指示哪些时间在指示的边界值之间。 z[ok] 然后 z 减少到这些值。最后,每天使用 aggregate.zoo 应用 sum(如果需要可以使用其他功能):

times <- format(time(z), "%H:%M")
ok <- times >= "12:01" & times <= "12:03"
aggregate(z[ok], as.Date, sum)
## 2006-08-01 2006-08-02 
##         75        375 

次跨越午夜

该版本适用于时间跨越午夜的情况。请注意,发送到函数的值的顺序不是原始顺序,但如果函数是对称的,则无关紧要。

times <- format(time(z), "%H:%M")
ok <- times >= "23:58" | times <= "00:12"
aggregate(z[ok], (as.Date(format(time(z))) + (times >= "23:58"))[ok], sum)
## 2006-08-02 
##         41 

变化

如果函数在其参数的组件中是对称的(许多函数都是这种情况,例如 meansum)但如果函数不对称,则先前的代码块有效我们需要一种稍微不同的方法。我们定义 to.sec 将 HH:MM 字符串转换为数字秒,并从每个 POSIXct 日期时间中减去 to.sec("23:58")。那么z的分量就是那些变换时间转换成HH:MM个小于"00:14"的字符串的分量。

to.sec <- function(x) with(read.table(text = x, sep = ":"), 3600 * V1 + 60 * V2)
times <- format(time(z) - to.sec("23:58"), "%H:%M")
ok <- times <= "00:14"
aggregate(z[ok], as.Date(time(z)[ok] - to.sec("23:58")), sum)
## 2006-08-01 
##         41 

备注

Lines <- "datetime val
2006-08-01T12:00    23
2006-08-01T12:01    24
2006-08-01T12:02    25
2006-08-01T12:03    26
2006-08-01T12:04    27
2006-08-01T12:05    28
2006-08-01T12:06    29
2006-08-01T23:58    20
2006-08-02T00:01    21
2006-08-02T12:00    123
2006-08-02T12:01    124
2006-08-02T12:02    125
2006-08-02T12:03    126
2006-08-02T12:04    127"

library(zoo)
z <- read.zoo(text = Lines, tz = "", header = TRUE, format = "%Y-%m-%dT%H:%M")

编辑

修改了非对称代码并简化了所有代码块。