Carlos Ortega
2014-Mar-10 23:49 UTC
[R-es] Frecuencia absoluta acumulada por individuo y por año
Hola, Vaya, en el código que he enviado, cusum no se incrementaba.. Y has indicado que se introduce un año más, con el mismo ID que el anterior y con la misma cantidad acumulada. Pero si el siguiente año es del mismo ID, acumula el valor de la cantidad que hemos introducido en esa fila... Con el siguiente código se resuelve este error y además ya está preparado para contemplar cualquier tipo de salto en años. He modificado un para de años sobre el resultado inicial del sqldf para mostrarlo. El problema de este código es que son dos bucles seguidos...pero resuelve la situación... #---------------------------------------------------------------------- Lines <- "ROW ID FECHA YEAR CANTIDAD 1 100 2005-08-02 2005 1 2 100 2005-10-19 2005 2 3 100 2007-02-09 2007 1 4 100 2007-10-25 2007 1 5 100 2007-10-29 2007 1 6 120 2006-05-11 2006 1 7 120 2006-08-17 2006 5 8 120 2006-10-15 2006 1 9 120 2007-04-16 2007 3 " DF <- read.table(textConnection(Lines), header=T, as.is = TRUE) library(sqldf) df.tmp <- sqldf("select ID,YEAR, sum(CANTIDAD) as cusum from DF group by ID,YEAR order by ID,YEAR") #----------------------- quitar estas filas # Pruebo que el salto en años sea mayor que dos.. # En vez de "100 2007" lo cambio a "100 2008".. df.tmp[2,2] <- c(2008) # Y que la última fila "120 2007" pasa a ser "120 2014" df.tmp[4,2] <- c(2014) #----------------------- quitar filas anteriores #------- Primer bucle para detectar los saltos en los años for(i in 1:nrow(df.tmp)) { if(i==1 ) { df.tmp$difID[i] <- 0 df.tmp$difYE[i] <- 0 } else{ if(df.tmp$ID[i]!=df.tmp$ID[i-1] & (df.tmp$YEAR[i]-df.tmp$YEAR[i-1] < 0)) { df.tmp$difID[i] <- 0 df.tmp$difYE[i] <- 0 } else { df.tmp$difID[i] <- df.tmp$ID[i] - df.tmp$ID[i-1] df.tmp$difYE[i] <- df.tmp$YEAR[i] - df.tmp$YEAR[i-1] } } } df.tmp #------- Segundo bucle para introducir filas en los saltos de años # Introduzco filas cuando el salto de años sea mayor que 2... df.new <- 0 for(i in 1:nrow(df.tmp)) { #Copio la fila tal cual cuando la diferencia en años es 0 o menor que dos. if(df.tmp$difYE[i] < 2) { df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] ,df.tmp$cusum[i])) } else { # Si la diferencia en años es mayor que dos, ciclo en años y teniendo en cuenta que cusum se acumula... cusum.cont <- df.tmp$cusum[i-1] for(j in 1:(df.tmp$difYE[i]-1) ) { df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i-1]+j ,df.tmp$cusum[i-1])) cusum.cont <- cusum.cont + df.tmp$cusum[i-1] } # Y tras ciclar copio la fila en la que estaba df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] ,df.tmp$cusum[i]+cusum.cont)) } } df.tmp df.new <- df.new[2:nrow(df.new),] row.names(df.new) <- NULL df.new <- as.data.frame(df.new) names(df.new) <- c('ID', 'YEAR','CUSUM') df.new #--------------------------------------------------------------------- En R el resultado es este: A) El data.frame resultado del sqldf pero *manipulado*.> df.tmp ID YEAR cusum difID difYE1 100 2005 3 0 0 2 100 2008 3 0 3 3 120 2006 7 0 0 4 120 2014 3 0 8 B) Resultado final con el procesado. Incluyendo años que faltan y arrastrando cusum incluso para esos años añadidos...> df.new ID YEAR CUSUM1 100 2005 3 2 100 2006 3 3 100 2007 3 4 100 2008 12 5 120 2006 7 6 120 2007 7 7 120 2008 7 8 120 2009 7 9 120 2010 7 10 120 2011 7 11 120 2012 7 12 120 2013 7 13 120 2014 59 Saludos, Carlos Ortega www.qualityexcellence.es El 10 de marzo de 2014, 23:47, Carlos Ortega <cof@qualityexcellence.es>escribió:> Hola, > > Crear la suma acumulada, puede hacerse de diferentes formas. > Pero rellenar el hueco del año cuando hay dos filas consecutivas con el > mismo ID pero diferente año, es donde aparece la complejidad. > > Esta es una forma de crear la suma acumulada (con sqldf) y de completar > ese hueco. > El hueco se completa, pero siempre que el salto del año sea de uno, como > en el ejemplo de los datos que has incluido. > > #------------------------------------------------------ > Lines <- "ROW ID FECHA YEAR CANTIDAD > > 1 100 2005-08-02 2005 1 > 2 100 2005-10-19 2005 2 > 3 100 2007-02-09 2007 1 > 4 100 2007-10-25 2007 1 > 5 100 2007-10-29 2007 1 > 6 120 2006-05-11 2006 1 > 7 120 2006-08-17 2006 5 > 8 120 2006-10-15 2006 1 > 9 120 2007-04-16 2007 3 > " > > DF <- read.table(textConnection(Lines), header=T, as.is = TRUE) > > # Consigo el valor acumulado de CANTIDAD agrupado por YEAR y ID > library(sqldf) > df.tmp <- sqldf("select ID,YEAR, sum(CANTIDAD) as cusum from DF group by > ID,YEAR order by ID,YEAR") > > # Ahora completo el hueco en el año > df.new <- 0 > for(i in 1:nrow(df.tmp)) { > > if(i>1) { > if(df.tmp$ID[i]==df.tmp$ID[i-1] & > (df.tmp$YEAR[i]!=df.tmp$YEAR[i-1]) & df.tmp$YEAR[i]-df.tmp$YEAR[i-1] > 1 ){ > > #Introduzco la fila anterior que falta > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i]-1 > ,df.tmp$cusum[i])) > > #Introduzco la fila tal cual > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] > ,df.tmp$cusum[i])) > > } else { > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] > ,df.tmp$cusum[i])) > } > } else { > # i=1 - Copio la fila > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] > ,df.tmp$cusum[i])) > } > > } > > df.tmp > # Arreglo df.new > df.new <- df.new[2:nrow(df.new),] > row.names(df.new) <- NULL > df.new <- as.data.frame(df.new) > names(df.new) <- names(df.tmp) > df.new > > > #----------------------------- FIN DE PROGRAMA ------------------------- > > > Saludos, > Carlos Ortega > www.qualityexcellence.es > > > El 10 de marzo de 2014, 19:19, Francisco Javier <iterador10@hotmail.com>escribió: > >> Hola, >> >> Hola a todos, >> Os escribo porque no consigo finalizar el script necesario para realizar >> lo que a continuación planteo. Partiendo de un data frame (2 millones de >> casos), tengo: >> >> > datos2 >> ID FECHA YEAR CANTIDAD >> 1 100 2005-08-02 2005 1 >> 2 100 2005-10-19 2005 2 >> 3 100 2007-02-09 2007 1 >> 4 100 2007-10-25 2007 1 >> 5 100 2007-10-29 2007 1 >> 6 120 2006-05-11 2006 1 >> 7 120 2006-08-17 2006 5 >> 8 120 2006-10-15 2006 1 >> 9 120 2007-04-16 2007 3 >> >> Y desearía las cantidades acumuladas por ID y año, a partir del primer >> año con registros de cada ID, obteniendo: >> ID YEAR CANTIDAD >> 1 100 2005 3 >> 2 100 2006 3 (como en el 2006 no hay datos de ID=100, el >> acumulado se mantiene) >> 3 100 2007 6 >> 4 120 2006 7 >> 5 120 2007 10 >> >> Hasta ahora sólo he conseguido llegar a esto mediante el paquete >> data.table: >> > library(data.table) >> > datos2 <- data.table(datos2) >> > datos2 <- datos2[, ACUM.CANTIDAD:=cumsum(CANTIDAD), by = list(ID, YEAR)] >> > datos2 >> ID FECHA YEAR CANTIDAD ACUM.CANTIDAD >> 1: 100 2005-08-02 2005 1 1 >> 2: 100 2005-10-19 2005 2 3 >> 3: 100 2007-02-09 2007 1 1 >> 4: 100 2007-10-25 2007 1 2 >> 5: 100 2007-10-29 2007 1 3 >> 6: 120 2006-05-11 2006 1 1 >> 7: 120 2006-08-17 2006 5 6 >> 8: 120 2006-10-15 2006 1 7 >> 9: 120 2007-04-16 2007 3 3 >> >> Cualquier ayuda será bienvenida. Muchísimas gracias. >> >> >> >> [[alternative HTML version deleted]] >> >> >> _______________________________________________ >> R-help-es mailing list >> R-help-es@r-project.org >> https://stat.ethz.ch/mailman/listinfo/r-help-es >> >> > > > -- > Saludos, > Carlos Ortega > www.qualityexcellence.es >-- Saludos, Carlos Ortega www.qualityexcellence.es [[alternative HTML version deleted]]
"Marcuzzi, Javier Rubén"
2014-Mar-11 04:29 UTC
[R-es] Frecuencia absoluta acumulada por individuo y por año
Hola Una forma que se me ocurre ahora, posiblemente ineficiente pero fácil (creo). El pseudocódigo es algo así: Crear un data frame nuevo usando rbind, agrega una fila, esto es porque en los datos hay ID pero estos no tienen registros todos los años. Por lo cual creo desde el primer año al último un if (bueno, if esle, if anidados, case ...). La pregunta para el condicional es ¿hay datos en el data frame original para el primer año?, si es si tomar esos valores, si es no colocar los el ID, año y 0 en cantidad (valor). La idea es tener un nuevo data.frame que pasa en el ID=1 de: 1 2005 5 1 2007 6 a: 1 2005 5 1 2006 0 *nuevo con un 0 1 2007 6 Luego cbind para colocar una función que sume, cumsum o alguna semejante escrita por el usuario. En un caso muy semejante yo use: lo_que_necesito <- with(Datos, tapply(Valor, ID, function(x){ if(...) ............................... en este if habría que escribir lo que corresponde. })) Datos$lo_que_necesito <- do.call(c, lo_que_necesito) No lo escribo porque me estoy durmiendo y seguro que cometo errores, pero yo pase por algo casi igual, la diferencia es que no utilice una función de suma, todo tendría que andar. Mirando el archivo donde trabaje antes y copio algo en este correo, tengo comentado que sqldf me daba errores al ordenar con fechas, como dice Carlos, sqldf fue mi primera opción por aquellos días, por lo que escribí bastante en R para poder lograr lo que necesitaba, le recomiendo que observe bien a sqldf (debería andar correctamente, ya no recuerdo el error que me daba, pero no era en todos los casos, era muy raro). Javier Marcuzzi El 10/03/14 20:49, Carlos Ortega escribió:> Hola, > > Vaya, en el código que he enviado, cusum no se incrementaba.. > Y has indicado que se introduce un año más, con el mismo ID que el anterior > y con la misma cantidad acumulada. Pero si el siguiente año es del mismo > ID, acumula el valor de la cantidad que hemos introducido en esa fila... > > Con el siguiente código se resuelve este error y además ya está preparado > para contemplar cualquier tipo de salto en años. > He modificado un para de años sobre el resultado inicial del sqldf para > mostrarlo. > El problema de este código es que son dos bucles seguidos...pero resuelve > la situación... > > #---------------------------------------------------------------------- > > Lines <- "ROW ID FECHA YEAR CANTIDAD > 1 100 2005-08-02 2005 1 > 2 100 2005-10-19 2005 2 > 3 100 2007-02-09 2007 1 > 4 100 2007-10-25 2007 1 > 5 100 2007-10-29 2007 1 > 6 120 2006-05-11 2006 1 > 7 120 2006-08-17 2006 5 > 8 120 2006-10-15 2006 1 > 9 120 2007-04-16 2007 3 > " > > DF <- read.table(textConnection(Lines), header=T, as.is = TRUE) > > library(sqldf) > df.tmp <- sqldf("select ID,YEAR, sum(CANTIDAD) as cusum from DF group by > ID,YEAR order by ID,YEAR") > > #----------------------- quitar estas filas > # Pruebo que el salto en años sea mayor que dos.. > # En vez de "100 2007" lo cambio a "100 2008".. > df.tmp[2,2] <- c(2008) > # Y que la última fila "120 2007" pasa a ser "120 2014" > df.tmp[4,2] <- c(2014) > #----------------------- quitar filas anteriores > > #------- Primer bucle para detectar los saltos en los años > for(i in 1:nrow(df.tmp)) { > if(i==1 ) { > df.tmp$difID[i] <- 0 > df.tmp$difYE[i] <- 0 > > } > else{ > > if(df.tmp$ID[i]!=df.tmp$ID[i-1] & (df.tmp$YEAR[i]-df.tmp$YEAR[i-1] < > 0)) { > df.tmp$difID[i] <- 0 > df.tmp$difYE[i] <- 0 > } else { > df.tmp$difID[i] <- df.tmp$ID[i] - df.tmp$ID[i-1] > df.tmp$difYE[i] <- df.tmp$YEAR[i] - df.tmp$YEAR[i-1] > } > } > } > df.tmp > > #------- Segundo bucle para introducir filas en los saltos de años > # Introduzco filas cuando el salto de años sea mayor que 2... > df.new <- 0 > for(i in 1:nrow(df.tmp)) { > > #Copio la fila tal cual cuando la diferencia en años es 0 o menor que dos. > if(df.tmp$difYE[i] < 2) { > > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] > ,df.tmp$cusum[i])) > > } else { > # Si la diferencia en años es mayor que dos, ciclo en años y teniendo > en cuenta que cusum se acumula... > cusum.cont <- df.tmp$cusum[i-1] > for(j in 1:(df.tmp$difYE[i]-1) ) { > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i-1]+j > ,df.tmp$cusum[i-1])) > cusum.cont <- cusum.cont + df.tmp$cusum[i-1] > } > # Y tras ciclar copio la fila en la que estaba > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] > ,df.tmp$cusum[i]+cusum.cont)) > } > > } > df.tmp > df.new <- df.new[2:nrow(df.new),] > row.names(df.new) <- NULL > df.new <- as.data.frame(df.new) > names(df.new) <- c('ID', 'YEAR','CUSUM') > df.new > > #--------------------------------------------------------------------- > > En R el resultado es este: > > A) El data.frame resultado del sqldf pero *manipulado*. > >> df.tmp ID YEAR cusum difID difYE > 1 100 2005 3 0 0 > 2 100 2008 3 0 3 > 3 120 2006 7 0 0 > 4 120 2014 3 0 8 > > > B) Resultado final con el procesado. Incluyendo años que faltan y > arrastrando cusum incluso para esos años añadidos... > >> df.new ID YEAR CUSUM > 1 100 2005 3 > 2 100 2006 3 > 3 100 2007 3 > 4 100 2008 12 > 5 120 2006 7 > 6 120 2007 7 > 7 120 2008 7 > 8 120 2009 7 > 9 120 2010 7 > 10 120 2011 7 > 11 120 2012 7 > 12 120 2013 7 > 13 120 2014 59 > > > > > Saludos, > Carlos Ortega > www.qualityexcellence.es > > > El 10 de marzo de 2014, 23:47, Carlos Ortega <cof@qualityexcellence.es>escribió: > >> Hola, >> >> Crear la suma acumulada, puede hacerse de diferentes formas. >> Pero rellenar el hueco del año cuando hay dos filas consecutivas con el >> mismo ID pero diferente año, es donde aparece la complejidad. >> >> Esta es una forma de crear la suma acumulada (con sqldf) y de completar >> ese hueco. >> El hueco se completa, pero siempre que el salto del año sea de uno, como >> en el ejemplo de los datos que has incluido. >> >> #------------------------------------------------------ >> Lines <- "ROW ID FECHA YEAR CANTIDAD >> >> 1 100 2005-08-02 2005 1 >> 2 100 2005-10-19 2005 2 >> 3 100 2007-02-09 2007 1 >> 4 100 2007-10-25 2007 1 >> 5 100 2007-10-29 2007 1 >> 6 120 2006-05-11 2006 1 >> 7 120 2006-08-17 2006 5 >> 8 120 2006-10-15 2006 1 >> 9 120 2007-04-16 2007 3 >> " >> >> DF <- read.table(textConnection(Lines), header=T, as.is = TRUE) >> >> # Consigo el valor acumulado de CANTIDAD agrupado por YEAR y ID >> library(sqldf) >> df.tmp <- sqldf("select ID,YEAR, sum(CANTIDAD) as cusum from DF group by >> ID,YEAR order by ID,YEAR") >> >> # Ahora completo el hueco en el año >> df.new <- 0 >> for(i in 1:nrow(df.tmp)) { >> >> if(i>1) { >> if(df.tmp$ID[i]==df.tmp$ID[i-1] & >> (df.tmp$YEAR[i]!=df.tmp$YEAR[i-1]) & df.tmp$YEAR[i]-df.tmp$YEAR[i-1] > 1 ){ >> >> #Introduzco la fila anterior que falta >> df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i]-1 >> ,df.tmp$cusum[i])) >> >> #Introduzco la fila tal cual >> df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] >> ,df.tmp$cusum[i])) >> >> } else { >> df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] >> ,df.tmp$cusum[i])) >> } >> } else { >> # i=1 - Copio la fila >> df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i] >> ,df.tmp$cusum[i])) >> } >> >> } >> >> df.tmp >> # Arreglo df.new >> df.new <- df.new[2:nrow(df.new),] >> row.names(df.new) <- NULL >> df.new <- as.data.frame(df.new) >> names(df.new) <- names(df.tmp) >> df.new >> >> >> #----------------------------- FIN DE PROGRAMA ------------------------- >> >> >> Saludos, >> Carlos Ortega >> www.qualityexcellence.es >> >> >> El 10 de marzo de 2014, 19:19, Francisco Javier <iterador10@hotmail.com>escribió: >> >>> Hola, >>> >>> Hola a todos, >>> Os escribo porque no consigo finalizar el script necesario para realizar >>> lo que a continuación planteo. Partiendo de un data frame (2 millones de >>> casos), tengo: >>> >>>> datos2 >>> ID FECHA YEAR CANTIDAD >>> 1 100 2005-08-02 2005 1 >>> 2 100 2005-10-19 2005 2 >>> 3 100 2007-02-09 2007 1 >>> 4 100 2007-10-25 2007 1 >>> 5 100 2007-10-29 2007 1 >>> 6 120 2006-05-11 2006 1 >>> 7 120 2006-08-17 2006 5 >>> 8 120 2006-10-15 2006 1 >>> 9 120 2007-04-16 2007 3 >>> >>> Y desearía las cantidades acumuladas por ID y año, a partir del primer >>> año con registros de cada ID, obteniendo: >>> ID YEAR CANTIDAD >>> 1 100 2005 3 >>> 2 100 2006 3 (como en el 2006 no hay datos de ID=100, el >>> acumulado se mantiene) >>> 3 100 2007 6 >>> 4 120 2006 7 >>> 5 120 2007 10 >>> >>> Hasta ahora sólo he conseguido llegar a esto mediante el paquete >>> data.table: >>>> library(data.table) >>>> datos2 <- data.table(datos2) >>>> datos2 <- datos2[, ACUM.CANTIDAD:=cumsum(CANTIDAD), by = list(ID, YEAR)] >>>> datos2 >>> ID FECHA YEAR CANTIDAD ACUM.CANTIDAD >>> 1: 100 2005-08-02 2005 1 1 >>> 2: 100 2005-10-19 2005 2 3 >>> 3: 100 2007-02-09 2007 1 1 >>> 4: 100 2007-10-25 2007 1 2 >>> 5: 100 2007-10-29 2007 1 3 >>> 6: 120 2006-05-11 2006 1 1 >>> 7: 120 2006-08-17 2006 5 6 >>> 8: 120 2006-10-15 2006 1 7 >>> 9: 120 2007-04-16 2007 3 3 >>> >>> Cualquier ayuda será bienvenida. Muchísimas gracias. >>> >>> >>> >>> [[alternative HTML version deleted]] >>> >>> >>> _______________________________________________ >>> R-help-es mailing list >>> R-help-es@r-project.org >>> https://stat.ethz.ch/mailman/listinfo/r-help-es >>> >>> >> >> -- >> Saludos, >> Carlos Ortega >> www.qualityexcellence.es >> > > > > > _______________________________________________ > R-help-es mailing list > R-help-es@r-project.org > https://stat.ethz.ch/mailman/listinfo/r-help-es[[alternative HTML version deleted]]
Francisco Javier
2014-Mar-11 17:44 UTC
[R-es] Frecuencia absoluta acumulada por individuo y por año
En primer lugar, muchas gracias Carlos, Javier Rubén y Daniel por vuestra ayuda. He aprendido mucho con cada una de vuestras sugerencias. En particular, gracias a Carlos Ortega por el código con el segundo bucle. Está curradísimo y me ha parecido muy buena la idea de separarlo en dos bucles. Lo he aplicado a mis datos y obtengo: ID YEAR CUSUM 1 100 2005 3 2 100 2006 3 3 100 2007 9 4 120 2006 7 5 120 2007 3 Que es casi lo que busco, pues lo que persigo obtener (diculpa Carlos porque me era difícil explicar con palabras y de forma resumida el objetivo) es lo siguiente: ID YEAR CUSUM 1 100 2005 3 2 100 2006 3 (se incorporan 0 datos nuevos: siguen habiendo 3 acumulados) 3 100 2007 6 (se incorporan 3 datos nuevos: hay 6 acumulados) 4 120 2006 7 5 120 2007 10 (se incorporan 3 datos nuevos: hay 10 acumulados) Carlos, he usado tú código sobre el data frame: # Mi data frame: datos2 datos2 <- data.frame(ID = c(rep(100,5),rep(120,4)), FECHA = c("02/08/2005", "19/10/2005", "09/02/2007", "25/10/2007","29/10/2007", "11/05/2006", "17/08/2006", "15/10/2006", "16/04/2007"), CANTIDAD = c(1, 2, 1, 1, 1, 1, 5, 1, 3)) class(datos2$FECHA) # Es un factor datos2$FECHA <- as.Date(datos2$FECHA,"%d/%m/%Y") class(datos2$FECHA) # Ahora ya es una fecha # Código library(sqldf) df.tmp <- sqldf("select ID,YEAR, sum(CANTIDAD) as cusum from datos2 group by ID,YEAR order by ID,YEAR") for(i in 1:nrow(df.tmp)) { if(i==1 ) { df.tmp$difID[i] <- 0 df.tmp$difYE[i] <- 0 } else{ if(df.tmp$ID[i]!=df.tmp$ID[i-1] & (df.tmp$YEAR[i]-df.tmp$YEAR[i-1] <0)) { df.tmp$difID[i] <- 0 df.tmp$difYE[i] <- 0 } else { df.tmp$difID[i] <- df.tmp$ID[i] - df.tmp$ID[i-1] df.tmp$difYE[i] <- df.tmp$YEAR[i] - df.tmp$YEAR[i-1] } } } #df.tmp (Lo comento porque no es el resultado finalmente buscado) #------- Segundo bucle para introducir filas en los saltos de años # Introduzco filas cuando el salto de años sea mayor que 2... df.new <- 0 for(i in 1:nrow(df.tmp)) { #Copio la fila tal cual cuando la diferencia en años es 0 o menor que dos. if(df.tmp$difYE[i] < 2) { df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i],df.tmp$cusum[i])) } else { # Si la diferencia en años es mayor que dos, ciclo en años y teniendo # en cuenta que cusum se acumula... cusum.cont <- df.tmp$cusum[i-1] for(j in 1:(df.tmp$difYE[i]-1) ) { df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i-1]+j ,df.tmp$cusum[i-1])) cusum.cont <- cusum.cont + df.tmp$cusum[i-1] } # Y tras ciclar copio la fila en la que estaba df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i],df.tmp$cusum[i]+cusum.cont)) } } # df.tmp (Lo comento al ser un data frame intermedio) # Data frame finalmente buscado: df.new df.new <- df.new[2:nrow(df.new),] row.names(df.new) <- NULL df.new <- as.data.frame(df.new) names(df.new) <- c('ID', 'YEAR','CUSUM') df.new [[alternative HTML version deleted]]
"Olivier Nuñez"
2014-Mar-12 09:07 UTC
[R-es] Frecuencia absoluta acumulada por individuo y por año
Llego tarde al hilo, pero creo que se llega rápidamente al resultado con la complicidad del paquete "reshape2". Si DT es el data.table que escojo Francisco como ejemplo:> DTID YEAR CANTIDAD 1: 100 2005 1 2: 100 2005 2 3: 100 2007 1 4: 100 2007 1 5: 100 2007 1 6: 120 2006 1 7: 120 2006 5 8: 120 2006 1 9: 120 2007 3> require(reshape2) > temp=dcast.data.table(DT,ID~YEAR,sum,value.var="CANTIDAD") > tempID 2005 2006 2007 1: 100 3 0 3 2: 120 0 7 3> res=melt(temp,id.var="ID") > setkey(res,ID,variable) > resID variable value 1: 100 2005 3 2: 100 2006 0 3: 100 2007 3 4: 120 2005 0 5: 120 2006 7 6: 120 2007 3> res[,cumsum:=cumsum(value),by=ID] > resID variable value cumsum 1: 100 2005 3 3 2: 100 2006 0 3 3: 100 2007 3 6 4: 120 2005 0 0 5: 120 2006 7 7 6: 120 2007 3 10> subset(res,cumsum>0)ID variable value cumsum 1: 100 2005 3 3 2: 100 2006 0 3 3: 100 2007 3 6 4: 120 2006 7 7 5: 120 2007 3 10 Un saludo. Olivier> En primer lugar, muchas gracias Carlos, Javier Rubén y Daniel por vuestra ayuda. He > aprendido mucho con cada una de vuestras sugerencias. > > > > En particular, gracias a Carlos Ortega por el código con el segundo bucle. Está > curradísimo y me ha parecido muy buena la idea de separarlo en dos bucles. Lo he > aplicado a mis datos y obtengo: > > > > ID YEAR CUSUM > 1 100 2005 3 > 2 100 2006 3 > 3 100 2007 9 > 4 120 2006 7 > 5 120 2007 3 > > > > Que es casi lo que busco, pues lo que persigo obtener (diculpa Carlos porque me era > difícil explicar con palabras y de forma resumida el objetivo) es lo siguiente: > > > > ID YEAR CUSUM > 1 100 2005 3 > 2 100 2006 3 (se incorporan 0 datos nuevos: siguen habiendo 3 acumulados) > 3 100 2007 6 (se incorporan 3 datos nuevos: hay 6 acumulados) > 4 120 2006 7 > 5 120 2007 10 (se incorporan 3 datos nuevos: hay 10 acumulados) > > > > Carlos, he usado tú código sobre el data frame: > > > > # Mi data frame: datos2 > > > datos2 <- data.frame(ID = c(rep(100,5),rep(120,4)), > FECHA = c("02/08/2005", "19/10/2005", "09/02/2007", "25/10/2007","29/10/2007", > "11/05/2006", "17/08/2006", "15/10/2006", "16/04/2007"), > CANTIDAD = c(1, 2, 1, 1, 1, 1, 5, 1, 3)) > > class(datos2$FECHA) # Es un factor > > datos2$FECHA <- as.Date(datos2$FECHA,"%d/%m/%Y") > class(datos2$FECHA) # Ahora ya es una fecha > > > > # Código > > library(sqldf) > > df.tmp <- sqldf("select ID,YEAR, sum(CANTIDAD) as cusum from datos2 group by ID,YEAR > order by ID,YEAR") > > > for(i in 1:nrow(df.tmp)) { > if(i==1 ) { > df.tmp$difID[i] <- 0 > df.tmp$difYE[i] <- 0 > > } > else{ > > if(df.tmp$ID[i]!=df.tmp$ID[i-1] & (df.tmp$YEAR[i]-df.tmp$YEAR[i-1] <0)) { > df.tmp$difID[i] <- 0 > df.tmp$difYE[i] <- 0 > } else { > df.tmp$difID[i] <- df.tmp$ID[i] - df.tmp$ID[i-1] > df.tmp$difYE[i] <- df.tmp$YEAR[i] - df.tmp$YEAR[i-1] > } > } > } > #df.tmp (Lo comento porque no es el resultado finalmente buscado) > > #------- Segundo bucle para introducir filas en los saltos de años > # Introduzco filas cuando el salto de años sea mayor que 2... > df.new <- 0 > for(i in 1:nrow(df.tmp)) { > > #Copio la fila tal cual cuando la diferencia en años es 0 o menor que dos. > if(df.tmp$difYE[i] < 2) { > > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i],df.tmp$cusum[i])) > > } else { > # Si la diferencia en años es mayor que dos, ciclo en años y teniendo > # en cuenta que cusum se acumula... > cusum.cont <- df.tmp$cusum[i-1] > for(j in 1:(df.tmp$difYE[i]-1) ) { > df.new <- rbind(df.new, c(df.tmp$ID[i] , df.tmp$YEAR[i-1]+j > ,df.tmp$cusum[i-1])) > cusum.cont <- cusum.cont + df.tmp$cusum[i-1] > } > # Y tras ciclar copio la fila en la que estaba > df.new <- rbind(df.new, c(df.tmp$ID[i] , > df.tmp$YEAR[i],df.tmp$cusum[i]+cusum.cont)) > } > > } > # df.tmp (Lo comento al ser un data frame intermedio) > > # Data frame finalmente buscado: df.new > df.new <- df.new[2:nrow(df.new),] > row.names(df.new) <- NULL > df.new <- as.data.frame(df.new) > names(df.new) <- c('ID', 'YEAR','CUSUM') > df.new > > > > > > > > > > > > [[alternative HTML version deleted]] > > _______________________________________________ > R-help-es mailing list > R-help-es en r-project.org > https://stat.ethz.ch/mailman/listinfo/r-help-es >-- ____________________________________ Olivier G. Nuñez Email: onunez en unex.es http://kolmogorov.unex.es/~onunez Tel : +34 663 03 69 09 Departamento de Matemáticas Universidad de Extremadura