【问题标题】:How do I call a function using a specific time window?如何使用特定时间窗口调用函数?
【发布时间】:2019-11-20 17:51:30
【问题描述】:

假设我有一个动物园对象(或者它可能是一个 data.frame),它在“一天中的时间”上有一个索引并且有一些值(参见下面的示例数据):

                    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,该怎么办?

【问题讨论】:

  • 您想在 3 分钟窗口跨度上创建滚动函数吗?
  • 每天跨越特定时间范围的窗口(在示例案例中)

标签: r dataframe zoo rollapply


【解决方案1】:

假设我们的输入是末尾注释中给出的 POSIXct zoo 对象z

创建一个字符向量timesz 的每个元素都有一个元素,格式为 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要保留的组件是那些转换时间转换为小于“00:14”的HH:MM字符串的组件。

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")

编辑

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

【讨论】:

    【解决方案2】:

    我推荐runner 包,它允许计算不规则时间序列上的任何滚动函数。函数runner 等价于rollApply,区别在于它可以依赖于日期。 runner 允许将任何 R 函数应用于由 k 定义的窗口长度,日期为 idx(或任何整数)。下面的示例计算 5 分钟(5*60 秒)窗口跨度的回归。算法不关心是否有天变,每次只计算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)
    

    滑动窗口调用的自定义函数:

    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 分钟预测的数据集,那么我们就可以只过滤特定的窗口 - 在这里,只有一小时的第 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 进行此操作

    【讨论】:

    • 但我想仅在特定时间之间计算 3 分钟
    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多