2012-03-30 7 views
5

Ich stieß auf eine Tabelle von Freq. Heute muss ich in einen Datenrahmen von Rohwerten expandieren. Ich war in der Lage, es zu tun, aber fragte mich, ob es eine schnellere Möglichkeit gibt, das Umformpaket oder data.table zu verwenden?Daten umformen (ein schneller Weg)

Die ursprüngliche Tabelle sah wie folgt aus:

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 

Hier ist ein einfaches Zupacken der Daten mit 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)) 

Mein Ansatz (n) die Daten neu zu gestalten (Gibt es einen schnelleren Weg?):

#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 

Ich nehme an, das ist ein häufiges Problem, wenn Sie eine Tabelle aus einem Artikel nehmen und reproduzieren möchten, erfordert es ein paar Entpackungen. Ich merke, dass ich das immer mehr mache und möchte sicherstellen, dass ich effizient bin.

Antwort

7

Hier ist ein Einzeiler.

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

Ich würde melt für den ersten Schritt und ddply für den zweiten verwenden.

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 Es ist besser als mein Ansatz bei weitem. Wenn niemand mit etwas effizienterem kommt (weniger Code-Schreiben, das ist keine Geschwindigkeit), werde ich dieses als die richtige Antwort markieren. +1 –

+0

Ich markiere das als richtig. Ich glaube nicht, dass irgendjemand diese Menge Code übertreffen kann. –

+0

nochmal überprüfen :-) – Ramnath

5

Und hier ist eine Basis R Einzeiler.

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

Oder etwas allgemeiner:

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

Schöne Arbeit in der Basis +1 –

3

Da niemand eine data.table Lösung geschrieben hat (wie in der ursprünglichen Frage vorgeschlagen)

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

Oder, noch kurz und bündig

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

Kann 'c (m, f)' (und 'liste (i1, i2, i3, i4)') geändert werden, um auf eine Variable zu verweisen, die die Spaltennamen enthält? Zum Beispiel, anstatt die m und f Spalten, was passiert, wenn ich 100 Spalten habe (zB Var0 bis Var99) und nicht den Namen jeder Spalte eingeben wollte. – dnlbrky