[R-es] Optimizar bucle for
Griera
gr|er@ @end|ng |rom y@ndex@com
Lun Oct 7 16:28:21 CEST 2024
Muchas gracias, Carlos!!
Pura màgia tu código que funciona a la perfección!
No se si conseguiré entenderlo nunca, pero lo intento.
Puedo preguntarte como funciona esto de :
delta = c(1000, diff(dates)))
¿Como es que en el primer registro coge 1000 i en los otros diff(dates)?
Muchas gracias y saludos: me has ahorrado muchas horas!
On Mon, 7 Oct 2024 16:02:17 +0200
"Carlos J. Gil Bellosta" <gilbellosta using gmail.com> wrote:
> Prueba así:
>
> ---
>
> dif_days <- 180 # Cambiado 6 meses
> df <- data.frame(
> id = c(1, 1, 1, 2, 2, 2, 1, 3),
> dates = as.Date(c("2023-01-01", "2023-05-15", "2023-12-01", "2023-01-01",
> "2023-04-01", "2023-12-01", "2023-03-15", "2023-01-01"))
> )
>
>
> # important!
> df <- df[order(df$id, df$dates),]
>
> n_borrar <- 1
>
> while (n_borrar > 0) {
> df <- ddply(df, .(id), transform, delta = c(1000, diff(dates)))
> # find the first register by id in less than dif_days
> df <- ddply(df, .(id), transform, borrar = cumsum(delta < dif_days))
> df <- ddply(df, .(id), transform, borrar = cumsum(borrar))
> n_borrar <- sum(df$borrar == 1)
> print(n_borrar)
> df <- df[df$borrar != 1,]
> }
> ---
>
> El programa no hacía lo que documentaba sino otra cosa distinta. Ahora solo
> borra una línea por id en cada pasada, la de la primera fila que está a
> menos de 6 meses de la anterior (por id). Antes podía haber borrado más de
> una fila.
>
> Un saludo,
>
> Carlos J. Gil Bellosta
> http://www.datanalytics.com
>
>
> On Mon, 7 Oct 2024 at 14:50, Griera <griera using yandex.com> wrote:
>
> > Muchas gracias, Carlos, por esta ayuda!
> >
> > Desconocia la existencia de ddply y me cuesta interpretar el código. Estoy
> > en ello.
> >
> > Realmente es mucho, pero mucho, más rápido.
> >
> > El problema es que si lo aplico a la tabla dde pruebas:
> > id dates
> > 1 1 2023-01-01
> > 2 1 2023-05-15
> > 3 1 2023-12-01
> > 4 2 2023-01-01
> > 5 2 2023-04-01
> > 6 2 2023-12-01
> > 7 1 2023-03-15
> > 8 3 2023-01-01
> >
> > dif_days <- 180 # Cambiado 6 meses
> > df <- data.frame(
> > id = c(1, 1, 1, 2, 2, 2, 1, 3),
> > dates = as.Date(c("2023-01-01", "2023-05-15", "2023-12-01",
> > "2023-01-01", "2023-04-01", "2023-12-01", "2023-03-15", "2023-01-01"))
> > )
> >
> > Borra incluso los registros de más de meses y solo queda:
> > > df
> > id dates delta borrar
> > 1 1 2023-01-01 1000 0
> > 2 2 2023-01-01 1000 0
> > 3 3 2023-01-01 1000 0
> >
> > ¿Sabes que puede estar pasando?
> >
> > Muchas gracias por la ayuda y saludos!
> >
> > On Mon, 7 Oct 2024 13:24:56 +0200
> > "Carlos J. Gil Bellosta" <gilbellosta using gmail.com> wrote:
> >
> > > Hola, ¿qué tal?
> > >
> > > Modifica esto:
> > >
> > > ----
> > >
> > > library(plyr)
> > >
> > > n_reg <- 332505
> > > n_ids <- 63738
> > >
> > > dif_days <- 90
> > >
> > > df <- data.frame(
> > > id = sample(n_ids, n_reg, replace = T),
> > > dates = sample(1000, n_reg, replace = T)
> > > )
> > >
> > > # important!
> > > df <- df[order(df$id, df$date),]
> > >
> > > n_borrar <- 1
> > >
> > > while (n_borrar > 0) {
> > > df <- ddply(df, .(id), transform, delta = c(1000, diff(dates)))
> > > # find the first register by id in less than dif_days
> > > df <- ddply(df, .(id), transform, borrar = cumsum(delta < dif_days))
> > > n_borrar <- sum(df$borrar == 1)
> > > print(n_borrar)
> > > df <- df[df$borrar != 1,]
> > > }
> > >
> > > ----
> > >
> > > Se puede hacer un poco mejor (sacando los ids que ya están limpios de la
> > > iteración), pero no vale la pena: tarda un par de minutos.
> > >
> > > Un saludo,
> > >
> > > Carlos J. Gil Bellosta
> > > http://www.datanalytics.com
> > >
> > >
> > > On Mon, 7 Oct 2024 at 12:01, Griera <griera using yandex.com> wrote:
> > >
> > > > Hola a todos:
> > > >
> > > > Tengo un bucle que tarda horas y me gustaría optimizarlo. Me explico.
> > > > Simplificando, tengo una tabla con 332.505 registros de 63.738
> > individuos.
> > > > Cada registro es una medida realiza de unos
> > > > días a unos meses o años después de la anterior. Lo que quiero es
> > borrar
> > > > aquellos registros que entre él y el anterior hayan transcurrido menos
> > > > de 6 meses, de manera que me quede una tabla con sólo aquellas medidas
> > > > realizadas al menos 6 meses después de la anterior.
> > > >
> > > > La tabla simplificada (no diferencio entre medida y ID y con una nueva
> > > > columna “BORRAR”) seria:
> > > >
> > > > ## Código
> > > > df <- data.frame(
> > > > ID = c(1, 1, 1, 2, 2, 2, 1, 3),
> > > > date = as.Date(c("2023-01-01", "2023-05-15", "2023-12-01",
> > "2023-01-01",
> > > > "2023-04-01", "2023-12-01", "2023-03-15", "2023-01-01")),
> > > > BORRAR = 0)
> > > >
> > > > ## El código con el bucle (doble bucle) es:
> > > >
> > > > # Definir umbral : 6 meses: si registro posterior menor 6 meses: borrar
> > > > umbral <- 30.5 * 6
> > > >
> > > > # Ordenar por ID i fecha
> > > > df <- df[order(df$ID, df$date), ]
> > > >
> > > > # Bucle per cada ID
> > > > for (id in unique(df$ID)) {
> > > > # Filtrar per ID actual
> > > > subset_df <- df[df$ID == id, ]
> > > >
> > > > # Si hay más de un registro borrar aquellos de más de 6 meses
> > > > if (nrow(subset_df) > 1) {
> > > > # Inicializar la referencia del primer registro no borrado
> > > > reference_date <- subset_df$date[1]
> > > >
> > > > for (i in 2:nrow(subset_df)) {
> > > > # Calcular la diferencia en días respecto a la referencia
> > > > diff_days <- as.numeric(difftime(subset_df$date[i],
> > reference_date,
> > > > units = "days"))
> > > >
> > > > # Si la diferencia es menor que el umbral, marcado para borrar
> > > > if (diff_days < umbral) {
> > > > df$BORRAR[df$ID == id & df$date == subset_df$date[i]] <- 1
> > > > } else {
> > > > # Actualizar la fecha referencia al nuevo registro no borrado
> > > > reference_date <- subset_df$date[i]
> > > > } ## Fin de if (diff_days < umbral)
> > > > } ## Fin del for (I in
> > > > 2:nrow(subset_df))
> > > > } ## Fin de (nrow(subset_df) > 1)
> > > > }
> > > >
> > > > # Resultado sin borrar registros
> > > > df
> > > >
> > > > ## fin Código
> > > >
> > > > El problema es que tarda muchas horas en ejecutarse. He intentado
> > > > optimizarlo (antes tardaba más), pero ya no se más R. ¿Algunas
> > > > sugerencias pera que vaya más rápido?
> > > >
> > > > Muchas gracias de antemano por su ayuda.
> > > >
> > > > _______________________________________________
> > > > R-help-es mailing list
> > > > R-help-es using r-project.org
> > > > https://stat.ethz.ch/mailman/listinfo/r-help-es
> > > >
> >
Más información sobre la lista de distribución R-help-es