Optimiza expand/pivot_wider en R para etiquetar todos los meses de un período de tiempo.
Estoy trabajando con un conjunto de datos de 1,3 millones de filas y 4 columnas, 1 fila por póliza y para cada una una fecha de inicio y una fecha de finalización.
Mi objetivo es determinar cuántas pólizas activas obtengo por mes, es decir, dentro de cada intervalo de tiempo [deb;fin], cuántas observaciones hay para cada mes del intervalo.
Utilizando tidyverse, logré crear el siguiente código, que es eficiente en conjuntos de datos pequeños, pero tarda casi 50 minutos en ejecutarse en los conjuntos de datos de entrada descritos anteriormente.
¿Algún consejo para optimizar el proceso de expand > pivot_wider? ¿O tal vez no lo estoy haciendo correctamente?
¡Muchas gracias por sus ideas!
library(tidyverse)
library(lubridate)
n <- 200
df <- data.frame(id = (1:n),
deb = sample(seq(as.Date('2020/01/01'), as.Date('2020/04/01'), by="day"), n, replace = T),
fin = sample(seq(as.Date('2020/05/01'), as.Date('2020/07/01'), by="day"), n, replace = T)
)
system.time((df2 <- df %>%
select(id, deb, fin) %>%
group_by(id, deb, fin) %>%
expand(dtmonth = format(seq.Date(floor_date(deb, "month"),
ceiling_date(fin, "month")-1,
by = "month"), "%Y-%m")) %>%
mutate(nb = 1) %>%
pivot_wider(names_from = dtmonth, values_from = nb)))
davy.ai
Hay algunas formas posibles de optimizar los pasos de expansión y pivoteo en este código. Un enfoque posible es usar data.table en lugar de tidyverse, ya que se sabe que data.table es eficiente para manejar conjuntos de datos grandes. Aquí hay un código de ejemplo usando data.table:
“`{r}
library(data.table)
library(lubridate)
setDT(df)
system.time({
df2 <- df[, .(dtmonth = format(seq(floor_date(deb, “month”), ceiling_date(fin, “month”)-1, by=”month”), “%Y-%m”),
nb = 1), by=.(id, deb, fin)][, dcast(.SD, id + deb + fin ~ dtmonth, fun.aggregate = sum, value.var = “nb”)]
})
Este código es similar al anterior, pero en lugar de pivotar los datos usando
dcast
, primero utilizadata.table::melt
para transponer los datos de un formato amplio a un formato largo, y luego utilizadcast
para pivotar los datos nuevamente. El argumentopatterns("^20")
enmelt
se utiliza para seleccionar solo las columnas que comienzan con “20” (es decir, las columnas de mes-año), y la funciónsubstring
se utiliza para extraer la parte del mes de los nombres de columna.Ambos enfoques deberían ser más eficientes que el código original que utiliza tidyverse. Sin embargo, la ganancia de rendimiento real depende de las características específicas del conjunto de datos y la configuración del hardware. Por lo tanto, se recomienda probarlos en el conjunto de datos real para ver cuál funciona mejor.