Как я могу вызвать функцию, используя определенное временное окно? - PullRequest
1 голос
/ 20 ноября 2019

Предположим, у меня есть объект зоопарка (или это может быть 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
...

Iхотел бы вызывать пользовательскую функцию (вызывать ее custom.func(vals)) с 12:01 - 12:03 (то есть что-то похожее на zoo :: rollapply) каждый раз, когда происходит такой интервал, в этом примере ежедневно. Как бы я это сделал?


ПРИМЕЧАНИЯ (для надежности также было бы здорово учесть следующие крайние случаи, но не обязательно):

  1. Непредположим, что у меня есть значения для 12:01 - 12:03 каждый день
  2. Не думайте, что весь диапазон 12:01 - 12:03 присутствует каждый день. В некоторые дни у меня могут быть только 12:01 и 12:02, но могут отсутствовать 12: 03
  3. Что если бы я хотел, чтобы мой custom.func(vals) вызывался на границах дня, например, используя val с 23:58 -00:12?

Ответы [ 2 ]

1 голос
/ 21 ноября 2019

Предположим, что нашим вводом является объект POSIXct zoo z, указанный в примечании в конце.

Создайте вектор символов times, который имеет один элемент на элемент z и имеет видHH: MM. Затем создайте логический ok, который указывает, какое время находится между указанными граничными значениями. z[ok] тогда z уменьшается до этих значений. Наконец, для каждого дня примените sum (при желании можете использовать какую-то другую функцию), используя aggregate.zoo:

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 

Изменение

Блок предыдущего кода работает, если функцияявляется симметричным по компонентам своего аргумента (что имеет место для многих функций, таких как mean и sum), но если бы функция не была симметричной, нам потребовался бы немного другой подход. Мы определяем to.sec, который переводит строку ЧЧ: ММ в числовые секунды и вычитает to.sec("23:58") из каждой даты-времени POSIXct. Тогда в качестве компонентов z сохраняются те, чье преобразованное время преобразуется в строки символов ЧЧ: ММ, которые меньше «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")

РЕДАКТИРОВАТЬ

Пересмотрел несимметричный код и упростил все фрагменты кода.

1 голос
/ 20 ноября 2019

Я рекомендую 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-я минута часа. Это означает, что мы всегда сохраняем {чч}: 56 - {чч + 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")

enter image description here

Есть и другие примеры в виньетка как это сделать с runner

...