es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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)))
Tags:  , ,

Answer

  1. Avatar for 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 primero convierte el data.frame a un data.table usando la función `setDT`. Luego realiza los mismos pasos de expansión y agregación que el código original utilizando la sintaxis de data.table, incluyendo el uso de la función `dcast` para pivotar los datos. El argumento `fun.aggregate = sum` en `dcast` se utiliza para sumar el número de pólizas en cada mes. Otro enfoque posible es usar la función `data.table::melt` en lugar de `tidyr::pivot_wider`. Aquí hay un código de ejemplo usando `melt`: ```{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)][, melt(.SD, id.vars=c("id", "deb", "fin"), measure.vars=patterns("^20")), by=.(id, variable)][, dcast(.SD, variable ~ paste0("m", substring(variable, 6)), fun.aggregate=sum, value.var="value")] })

    Este código es similar al anterior, pero en lugar de pivotar los datos usando dcast, primero utiliza data.table::melt para transponer los datos de un formato amplio a un formato largo, y luego utiliza dcast para pivotar los datos nuevamente. El argumento patterns("^20") en melt se utiliza para seleccionar solo las columnas que comienzan con “20” (es decir, las columnas de mes-año), y la función substring 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.

Comments are closed.