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