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]]

