Domanda

Ho un elenco di frame dati per i quali sono certo che tutti contengono almeno una riga (in effetti, alcuni contengono solo una riga e altri contengono un determinato numero di righe) e che tutti abbiano le stesse colonne (nomi e tipi). Nel caso in cui sia importante, sono anche certo che non ci siano Na da nessuna parte nelle file.

La situazione può essere simulata in questo modo:

#create one row
onerowdfr<-do.call(data.frame, c(list(), rnorm(100) , lapply(sample(letters[1:2], 100, replace=TRUE), function(x){factor(x, levels=letters[1:2])})))
colnames(onerowdfr)<-c(paste("cnt", 1:100, sep=""), paste("cat", 1:100, sep=""))
#reuse it in a list
someParts<-lapply(rbinom(200, 1, 14/200)*6+1, function(reps){onerowdfr[rep(1, reps),]})

Ho impostato i parametri (della randomizzazione) in modo che approssimino la mia vera situazione.

Ora, voglio unire tutti questi gesti di dati in un solo tema. Ho pensato che usare Rbind avrebbe fatto il trucco, in questo modo:

system.time(
result<-do.call(rbind, someParts)
)

Ora, sul mio sistema (che non è particolarmente lento), e con le impostazioni sopra, questo prende l'uscita del sistema.

   user  system elapsed 
   5.61    0.00    5.62

Quasi 6 secondi per Rbind-ing 254 (nel mio caso) file di 200 variabili? Sicuramente ci deve essere un modo per migliorare le prestazioni qui? Nel mio codice, devo fare cose simili molto spesso (è una delle imputazioni multiple), quindi ho bisogno che questo sia il più veloce possibile.

È stato utile?

Soluzione

Puoi costruire le tue matrici solo con variabili numeriche e convertire in un fattore alla fine? rbind è molto più veloce sulle matrici numeriche.

Sul mio sistema, utilizzando i frame di dati:

> system.time(result<-do.call(rbind, someParts))
   user  system elapsed 
  2.628   0.000   2.636 

Costruire invece l'elenco con tutte le matrici numeriche:

onerowdfr2 <- matrix(as.numeric(onerowdfr), nrow=1)
someParts2<-lapply(rbinom(200, 1, 14/200)*6+1, 
                   function(reps){onerowdfr2[rep(1, reps),]})

si traduce in molto più velocemente rbind.

> system.time(result2<-do.call(rbind, someParts2))
   user  system elapsed 
  0.001   0.000   0.001

EDIT: ecco un'altra possibilità; Combina solo ogni colonna a sua volta.

> system.time({
+   n <- 1:ncol(someParts[[1]])
+   names(n) <- names(someParts[[1]])
+   result <- as.data.frame(lapply(n, function(i) 
+                           unlist(lapply(someParts, `[[`, i))))
+ })
   user  system elapsed 
  0.810   0.000   0.813  

Tuttavia, non è ancora così veloce come l'uso di matrici però.

EDIT 2:

Se hai solo numerici e fattori, non è così difficile convertire tutto in numerico, rbind loro e converti le colonne necessarie a fattori. Ciò presuppone che tutti i fattori abbiano esattamente gli stessi livelli. La conversione in un fattore da un numero intero è anche più veloce che da un numerico, quindi faccio prima forza a interi.

someParts2 <- lapply(someParts, function(x)
                     matrix(unlist(x), ncol=ncol(x)))
result<-as.data.frame(do.call(rbind, someParts2))
a <- someParts[[1]]
f <- which(sapply(a, class)=="factor")
for(i in f) {
  lev <- levels(a[[i]])
  result[[i]] <- factor(as.integer(result[[i]]), levels=seq_along(lev), labels=lev)
}

I tempi sul mio sistema sono:

   user  system elapsed 
   0.090    0.00    0.091 

Altri suggerimenti

Non è un enorme impulso, ma scambiarsi rbind per rbind.fill dal plyr Il pacchetto elimina circa il 10% di sconto sul tempo di esecuzione (con il set di dati di esempio, sulla mia macchina).

Se vuoi davvero manipolare il tuo data.frames più veloce, suggerirei di usare il pacchetto data.table e la funzione rbindlist(). Non ho eseguito test approfonditi ma per il mio set di dati (3000 dati di dati, 1000 righe x 40 colonne ciascuna) rbindlist() richiede solo 20 secondi.

Questo è ~ 25% più veloce, ma deve esserci un modo migliore ...

system.time({
  N <- do.call(sum, lapply(someParts, nrow))
  SP <- as.data.frame(lapply(someParts[[1]], function(x) rep(x,N)))
  k <- 0
  for(i in 1:length(someParts)) {
    j <- k+1
    k <- k + nrow(someParts[[i]])
    SP[j:k,] <- someParts[[i]]
  }
})

Assicurati di vincere DataFrame a DataFrame. Si è imbattuto in un enorme degrado perf quando è stato vincolato al telaio dati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top