2012-03-30 18 views
5

Me encontré con una tabla de frecuencia. cuenta hoy que tuve que expandirme a un marco de datos de valores brutos. Pude hacerlo, pero me preguntaba si hay una forma más rápida de usar el paquete de remodelación o data.table?reforma de datos (una forma más rápida)

La tabla original era la siguiente:

i1 i2 i3 i4 m f 
1 0 0 0 0 22 29 
2 1 0 0 0 30 50 
3 0 1 0 0 13 15 
4 0 0 1 0 1 6 
5 1 1 0 0 24 67 
6 1 0 1 0 5 12 
7 0 1 1 0 1 2 
8 1 1 1 0 10 22 
9 0 0 0 1 10 7 
10 1 0 0 1 27 30 
11 0 1 0 1 14 4 
12 0 0 1 1 1 0 
13 1 1 0 1 54 63 
14 1 0 1 1 8 10 
15 0 1 1 1 8 6 
16 1 1 1 1 57 51 

He aquí un agarre fácil de los datos utilizando dput:

dat <- structure(list(i1 = c(0L, 1L, 0L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 
0L, 0L, 1L, 1L, 0L, 1L), i2 = c(0L, 0L, 1L, 0L, 1L, 0L, 1L, 1L, 
0L, 0L, 1L, 0L, 1L, 0L, 1L, 1L), i3 = c(0L, 0L, 0L, 1L, 0L, 1L, 
1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 1L, 1L), i4 = c(0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), m = c(22L, 30L, 
13L, 1L, 24L, 5L, 1L, 10L, 10L, 27L, 14L, 1L, 54L, 8L, 8L, 57L 
), f = c(29L, 50L, 15L, 6L, 67L, 12L, 2L, 22L, 7L, 30L, 4L, 0L, 
63L, 10L, 6L, 51L)), .Names = c("i1", "i2", "i3", "i4", "m", 
"f"), class = "data.frame", row.names = c(NA, -16L)) 

Mi enfoque (s) para formar de nuevo los datos (¿hay una manera más rápida?):

#step 1: method 1 (in this case binding and stacking uses less code than reshape) 
dat2 <- data.frame(rbind(dat[,1:4], dat[, 1:4]), 
    sex = rep(c('m', 'f'), each=16), 
    n = c(dat$m, dat$f)) 
dat2 

#step 1: method 2  
dat3 <- reshape(dat, direction = "long", idvar = 1:4, 
    varying = list(c("m", "f")), 
    v.names = c("n"), 
    timevar = "sex", 
    times = c("m", "f")) 
    rownames(dat3) <- 1:nrow(dat3) 
    dat3 <- data.frame(dat3) 
    dat3$sex <- as.factor(dat3$sex) 

all.equal(dat3, dat2) #just to show both method 1 and 2 give the same data frame 

#step 2 
dat4 <- dat2[rep(seq_len(nrow(dat2)), dat2$n), 1:5] 
rownames(dat4) <- 1:nrow(dat4) 
dat4 

Supongo que este es un problema común, ya que cuando desea tomar una tabla de un artículo y reproducirla, requiere un poco de desembalaje. Me estoy haciendo cada vez más y quiero asegurarme de ser eficiente.

Respuesta

7

Aquí hay un trazador de líneas.

dat2 <- ddply(dat, 1:4, summarize, sex = c(rep('m', m), rep('f', f))) 
2

Yo usaría melt para el primer paso y ddply para el segundo.

library(reshape2) 
library(plyr) 
d <- ddply( 
    melt(dat, id.vars=c("i1","i2","i3","i4"), variable.name="sex"), 
    c("i1","i2","i3","i4","sex"), 
    summarize, 
    id=rep(1,value) 
) 
d$id <- cumsum(d$id) 
+0

I li ke es mejor que mi enfoque de lejos. Si a nadie se le ocurre algo más eficiente (menos escritura de código que no sea velocidad), marcaré esta como la respuesta correcta. +1 –

+0

Estoy marcando esto como correcto. No creo que nadie pueda vencer esta cantidad de código. –

+0

verifique de nuevo :-) – Ramnath

5

Y aquí hay una base R de una sola línea.

dat2 <- cbind(dat[c(rep(1:nrow(dat), dat$m), rep(1:nrow(dat), dat$f)),1:4], 
       sex=c(rep("m",sum(dat$m)), rep("f", sum(dat$f)))) 

O bien, un poco más general:

d1 <- dat[,1:4] 
d2 <- as.matrix(dat[,5:6]) 
dat2 <- cbind(d1[rep(rep(1:nrow(dat), ncol(d2)), d2),], 
       sex=rep(colnames(d2), colSums(d2))) 
+0

Buen trabajo en la base +1 –

3

Dado que nadie ha publicado una solución data.table (como se sugiere en la pregunta original)

library(data.table) 
DT <- as.data.table(dat) 
DT[,list(sex = rep(c('m','f'),c(m,f))), by= list(i1,i2,i3,i4)] 

O, aún más sucintamente

DT[,list(sex = rep(c('m','f'),c(m,f))), by= 'i1,i2,i3,i4'] 
+0

¿Puede 'c (m, f)' (y 'list (i1, i2, i3, i4)' modificarse para hacer referencia a una variable que contenga los nombres de las columnas? Por ejemplo, en lugar de las columnas m y f, ¿qué pasa si tengo 100 columnas (digamos Var0 a Var99) y no quiero escribir el nombre de cada columna? – dnlbrky

Cuestiones relacionadas