multivariadas - series de tiempo diarias en r
fusionar dos series de tiempo diarias después de resumir en horas desplazadas (3)
Puede hacerlo usando cut
, por ejemplo:
library(lubridate)
library(dplyr)
brk = seq(ymd_hm(paste(as.Date(min(hourly$datetime) - days(1)), "08:00"), tz= "UTC"), ymd_hm(paste(as.Date(max(hourly$datetime)+ days(1)), "08:00"), tz= "UTC"), by = "24 hours")
hourly$cut <- ymd_hms(cut.POSIXt(hourly$datetime, breaks = brk))
hourly2 <- hourly %>% group_by(cut) %>% summarize(value = sum(value))
hourly2$cut <- as.Date(hourly2$cut)
names(hourly2) <- names(daily)
comb <- rbind(hourly2, daily) %>% group_by(datetime) %>% summarize(value = sum(value))
datetime value
<date> <dbl>
1 2016-12-31 52.0000000
2 2017-01-01 241.5612137
3 2017-01-02 244.3689032
4 2017-01-03 271.3156334
5 2017-01-04 253.8221333
6 2017-01-05 238.5790170
7 2017-01-06 220.7118064
8 2017-01-07 167.5018586
9 2017-01-08 -0.2962494
10 2017-01-09 0.4126310
... with 22 more rows
Tengo una medición (por ejemplo, radiación solar) indexada con una variable de fecha y hora, en una marca de tiempo por hora. Lo que quiero hacer es sumar el valor de medición para cada día del año y unirlo a otra fuente de datos también a escala diaria (digamos temperatura media al aire libre).
Aunque, la segunda fuente de datos ya está agregada desde las 8:00 a.m. hasta las 8:00 a.m. del día siguiente . Sé cómo resumir mi primera variable por día estándar, pero necesito hacerlo de 8 a 8 para hacer coincidir ambas mediciones.
Un ejemplo de mis datos
set.seed(1L) # to create reproducible data
hourly = data.frame(datetime = seq(from = lubridate::ymd_hm("2017-01-01 01:00"),
length.out = 168, by = "hour"),
value = rpois(168, 10))
daily = data.frame(datetime = seq(from=as.Date("2017-01-01"), length.out = 31, by="day"),
value=rnorm(31))
usando dplyr
y simplemente traduciendo el día restando 8 horas:
hourly %>% mutate(datetime = as_date(datetime - 8 * hours())) %>%
rbind(daily) %>%
group_by(datetime) %>%
summarize_all(sum) %>%
ungroup%>%
arrange(datetime)
resultado
A tibble: 32 x 2
datetime value
<date> <dbl>
1 2016-12-31 70.0000000
2 2017-01-01 218.6726454
3 2017-01-02 244.3821258
4 2017-01-03 257.7136326
5 2017-01-04 220.4788443
6 2017-01-05 230.3729744
7 2017-01-06 248.5082639
8 2017-01-07 176.5511818
9 2017-01-08 -0.8307824
10 2017-01-09 -0.6343781
# ... with 22 more rows
Ampliando mi comentario a una respuesta, vale la pena señalar que el OP ha enfatizado las palabras agregadas de 8:00 a.m. a 8:00 a.m. del día siguiente .
Asignación de los períodos de 24 horas no alineados a las fechas
Si un período de 24 horas no está alineado con la medianoche, es decir, no se extiende desde las 00:00 hasta las 24:00, sino que comienza y termina en algún momento durante el día, es ambiguo qué fecha se asocia con ese período.
Podemos tomar cualquiera
- la fecha del día en que comienza el período,
- la fecha del día en que finaliza el período, o
- la fecha del día que contiene la mayoría de las horas del período.
Solo para ilustrar la diferencia:
# timestamps: 9 am, 10pm, 7 am next day
x <- lubridate::ymd_hm(c("2017-09-12 09:00", "2017-09-12 22:00", "2017-09-13 07:00"))
x
[1] "2017-09-12 09:00:00 UTC" "2017-09-12 22:00:00 UTC" "2017-09-13 07:00:00 UTC"
# map timestamps to date on which period starts by shifting back by 8 hours
x + lubridate::hours(-8L)
[1] "2017-09-12 01:00:00 UTC" "2017-09-12 14:00:00 UTC" "2017-09-12 23:00:00 UTC"
# map timestamps to date on which period ends by advancing by 16 hours
x + lubridate::hours(16L)
[1] "2017-09-13 01:00:00 UTC" "2017-09-13 14:00:00 UTC" "2017-09-13 23:00:00 UTC"
Como no hay más información, supongamos que los datos daily
se asignaron al día en que comienza el período.
Agregación y fusión
Para agrupar, agregar y fusionar data.table
se usa:
library(data.table)
# aggregate data by shifted timestamp
setDT(hourly)[, .(sum.value = sum(value)),
by = .(date = as.Date(datetime + lubridate::hours(-8L)))]
date sum.value 1: 2016-12-31 68 2: 2017-01-01 232 3: 2017-01-02 222 4: 2017-01-03 227 5: 2017-01-04 228 6: 2017-01-05 231 7: 2017-01-06 260 8: 2017-01-07 144
Tenga en cuenta que la nueva columna de date
que se utiliza para agrupar y agregar se crea sobre la marcha en el parámetro by
(una de las razones por las que prefiero data.table
)
Ahora, los datos daily
deben unirse. Al encadenar esto se puede combinar en una declaración:
setDT(hourly)[, .(sum.value = sum(value)),
by = .(date = as.Date(datetime + lubridate::hours(-8L)))][
setDT(daily), on = .(date = datetime), nomatch = 0L]
date sum.value value 1: 2017-01-01 232 -0.5080862 2: 2017-01-02 222 0.5236206 3: 2017-01-03 227 1.0177542 4: 2017-01-04 228 -0.2511646 5: 2017-01-05 231 -1.4299934 6: 2017-01-06 260 1.7091210 7: 2017-01-07 144 1.4350696
El parámetro nomatch = 0L
indica que queremos una unión interna aquí.