2011-12-18 19 views
5

Tengo un conjunto de datos relativamente grande (16,000+ x ~ 31). En otras palabras, es lo suficientemente grande como para no manipularlo línea por línea en Excel. Los datos están en esta forma:Cómo agregar una columna de conteo basada en valores en otras columnas en R

block site  day X1 X2 
1  1  1 0.4 5.1 
1  1  2 0.8 1.1 
1  1  3 1.1 4.2 
1  2  1 ... ... 
1  2  2 
1  2  3 
2  3  1 
2  3  2 
2  3  3 
2  4  1 
2  4  2 
2  4  3 

Como se puede ver, el recuento sitio es continua, pero me gustaría una columna en la que el número de sitio restablece con cada bloque. Por ejemplo, me gustaría algo como esto a continuación:

block site  day X1 X2 site2 
1  1  1 0.4 5.1 1 
1  1  2 0.8 1.1 1 
1  1  3 1.1 4.2 1 
1  2  1 ... ... 2 
1  2  2    2 
1  2  3    2 
2  3  1    1 
2  3  2    1 
2  3  3    1 
2  4  1    2 
2  4  2    2 
2  4  3    2 

Estaba pensando acerca del uso de la función R rle pero no estoy seguro si va a trabajar debido a complicaciones con día. De lo contrario, me gustaría probar algo como:

Data$site2 <- sequence(rle(Data$block)$lengths) 

¿Alguien tiene alguna sugerencia para añadir un conteo de la columna (secuencia) el número de sitios dentro de cada bloque? Si ayuda, hay la misma cantidad de días (263) registrados para cada sitio, pero hay una cantidad diferente de sitios por bloque.

Respuesta

6

Aquí es una solución ligeramente torpe usando plyr y ddply:

ddply(df,.(block),transform, 
        site1 = rep(1:length(unique(site)), 
          times = rle(site)$lengths)) 

O una versión ligeramente más pulido:

ddply(df,.(block),transform,site1 = as.integer(as.factor(site))) 

Puede haber una forma inteligente de hacer esto directamente, sin embargo, el uso de las diversas funciones seq, sequence y rle, pero mi cerebro es un poco confuso en este momento. Si deja esto abierto por un tiempo, es probable que alguien venga con una solución no-plyr.

+0

Gracias, esto funcionó perfectamente. He visto plyr antes pero nunca lo he usado. ddply es perfecto, en realidad tuve que dividir la matriz, usar la forma (= amplia) en días, aplicar el rle (sitio) y luego intentar remodelar (= largo). No sé si funcionaría, pero pensé que había alrededor de 1000 maneras más fáciles de hacerlo. Me gusta la solución dpdply. gracias de nuevo. – djhocking

+0

Bueno, acabo de probar la opción ddply en un problema similar y funcionó perfectamente la primera vez – Ell

1

Usando tapply podría funcionar

# Make some fake data 
dat <- data.frame(block = rep(1:3, each = 4), site = rep(1:6, each = 2), val = rnorm(12)) 
# For each block reset the count 
dat$site2 <- unlist(tapply(dat$site, dat$block, function(x){x - min(x) + 1})) 
+0

Esto no parece funcionar para mis datos confusos. Olvidé que el sitio no es completamente continuo porque los registradores de datos en algunos sitios fallaron o desaparecieron. De modo que, de vez en cuando, a lo largo del conjunto de datos se omiten los números de los sitios, pero lo que necesito es una variable que solo cuente, así puedo pasar por la indexación en las funciones de ciclo como parte de mi análisis. Tal vez si intento lo que sugieres pero con alguna función inteligente que agregue al valor anterior en el sitio2 en lugar de basarlo en el número del sitio original. – djhocking

0

Via Ave:

df1 <- structure(list(block = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2), 
    site = c(1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4), day = c(1, 
    2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3)), .Names = c("block", "site", 
"day"), row.names = c("2", "3", "4", "5", "6", "7", "8", "9", 
"10", "11", "12", "13"), class = "data.frame") 

df1$site2 <- ave(df1$site,df1$block,FUN=function(x) match(x,sort(unique(x)))) 
Cuestiones relacionadas