Ein Array in data.frame verschmelzen, aber eine Dimension in Spalten umwandeln

StackOverflow https://stackoverflow.com//questions/22003121

  •  20-12-2019
  •  | 
  •  

Frage

Ich möchte ein Array mit mehreren Dimensionen konvertieren (z. B.x, y, z;siehe „arr“ unten) in einen data.frame, aber behalten Sie eine Dimension in den Spalten bei (z. B.z, siehe 'df2' unten).

Derzeit verwende ich die Funktionen Melt und Dcast im Paket reshape2.

set.seed(1111)
num <- 1000
dim_names <- list(x = seq(num), y = seq(num), 
    z = paste0('Z', 1:5))
dim_arr <- as.numeric(lapply(dim_names, length))
arr <- array(runif(prod(dim_arr)), dim = dim_arr)
dimnames(arr) <- dim_names

library(reshape2)
df <- melt(arr)
head(df)
system.time(df2 <- dcast(df, x + y ~ z, value.var = 'value'))
head(df2)

  x y        Z1        Z2        Z3        Z4         Z5
1 1 1 0.4655026 0.8027921 0.1950717 0.0403759 0.04669389
2 1 2 0.5156263 0.5427343 0.5799924 0.1911539 0.26069063
3 1 3 0.2788747 0.9394142 0.9081274 0.7712205 0.68748300
4 1 4 0.2827058 0.8001632 0.6995503 0.9913805 0.25421346
5 1 5 0.7054767 0.8013255 0.2511769 0.6556174 0.07780849
6 1 6 0.5576141 0.6452644 0.3362980 0.7353494 0.93147223

Die Konvertierung von 5 M-Werten dauerte jedoch etwa 10 s

  user  system elapsed 
  8.13    1.11    9.39 

Gibt es effizientere Methoden?Vielen Dank für alle Vorschläge.

War es hilfreich?

Lösung

Hier ist ein leicht allgemeinere Lösung für ein 4-dimensionales Array unter Verwendung einer Kombination von aperm(...) Und matrix(...).Ich bin kein Zauberer genug, um das weiter zu verallgemeinern.

nx <- 2 ; ny <- 3 ; nz <- 4 ; nw <- 5
original <- array(rnorm(nx*ny*nz*nw), dim=c(nx,ny,nz,nw), 
              dimnames=list(x=sprintf('x%s', 1:nx), y=sprintf('y%s', 1:ny), 
                            z=sprintf('z%s', 1:nz), w=sprintf('w%s', 1:nw)))

Dies ist Ihre vorhandene Methode, die verwendet wird melt(...) Und dcast(...) So entfernen Sie alle bis auf die letzte Dimension:

f.dcast <- function(a) dcast(melt(a), x + y + z ~ w)

Das Folgende macht dasselbe, indem es verwendet wird aperm(...) um die Daten dann als Vektor in einer bestimmten Reihenfolge auszuschreiben, damit sie als richtig formatierte Matrix enden cbinds mit den Variablennamen:

f.aperm <- function(a) {
  d <- dim(a)

  data <- matrix(as.vector(aperm(a, c(4,3,2,1))), ncol=d[4], byrow=T)
  colnames(data) <- dimnames(a)[[4]]

  # specify levels in the same order as the input so they don't wind up alphabetical  
  varnames <- data.frame(
    factor(rep(dimnames(a)[[1]], times=1,         each=d[2]*d[3]), levels=dimnames(a)[[1]]),
    factor(rep(dimnames(a)[[2]], times=d[1],      each=d[3]     ), levels=dimnames(a)[[2]]),
    factor(rep(dimnames(a)[[3]], times=d[1]*d[2], each=1        ), levels=dimnames(a)[[3]])
  )

  names(varnames) <- names(dimnames(a))[1:3]

  cbind(varnames, data)
}

Beide geben mir das gleiche Ergebnis:

> desired <- f.dcast(original)
> test <- f.aperm(original)
> all.equal(desired, test)
[1] TRUE

Die zweite Methode ist für ein Array dieser Größe sechsmal schneller:

> microbenchmark::microbenchmark(f.dcast(original), f.aperm(original))
Unit: milliseconds
              expr      min       lq     mean   median       uq       max neval
 f.dcast(original) 7.270208 7.343227 7.703360 7.481984 7.698812 10.392141   100
 f.aperm(original) 1.218162 1.244595 1.327204 1.259987 1.291986  4.182391   100

Wenn ich die Größe des ursprünglichen Arrays vergrößere:

nx <- 10 ; ny <- 20 ; nz <- 30 ; nw <- 40

Dann ist die zweite Methode über zehnmal schneller:

> microbenchmark::microbenchmark(f.dcast(original), f.aperm(original))
Unit: milliseconds
              expr       min        lq      mean    median        uq       max neval
 f.dcast(original) 303.21812 385.44857 381.29150 392.11693 394.81721 472.80343   100
 f.aperm(original)  18.62788  22.25814  28.85363  23.90133  24.54939  97.96776   100

Andere Tipps

generasacodicetagpre.

verstrichene Zeit dafür war rund ein Zehntelsekunde.Dies war das Ergebnis von str ()

generasacodicetagpre.

Ich nehme an, Sie könnten in Row.names eingeben, obwohl er über eine Sekunde bis ein bisschen verstrichene Zeit erhöht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top