Secondo Creating an R dataframe row-by-row, non è ideale per aggiungere uno data.frame
utilizzando rbind
, poiché ogni volta crea una copia dell'intero data.frame. Come faccio ad accumulare dati in R
risultante in un data.frame
senza incorrere in questa penalità? Il formato intermedio non deve essere un data.frame
.Crescere un data.frame in modo efficiente dalla memoria
risposta
primo approccio
Ho provato accedere a ciascun elemento di un data.frame preallocato:
res <- data.frame(x=rep(NA,1000), y=rep(NA,1000))
tracemem(res)
for(i in 1:1000) {
res[i,"x"] <- runif(1)
res[i,"y"] <- rnorm(1)
}
Ma tracemem impazzisce (ad esempio la data.frame viene copiato un nuovo indirizzo ogni volta).
approccio alternativo (non funziona nemmeno)
Un approccio (non sono sicuro che sia più veloce in quanto non ho ancora benchmark) è quello di creare un elenco di data.frames, poi stack
tutti insieme:
makeRow <- function() data.frame(x=runif(1),y=rnorm(1))
res <- replicate(1000, makeRow(), simplify=FALSE) # returns a list of data.frames
library(taRifx)
res.df <- stack(res)
Sfortunatamente nel creare l'elenco penso che sarà difficile pre-allocare. Ad esempio:
> tracemem(res)
[1] "<0x79b98b0>"
> res[[2]] <- data.frame()
tracemem[0x79b98b0 -> 0x71da500]:
In altre parole, la sostituzione di un elemento dell'elenco provoca la copia dell'elenco. Presumo l'intera lista, ma è possibile che sia solo quell'elemento della lista. Non ho familiarità con i dettagli della gestione della memoria di R.
Probabilmente il miglior approccio
Come molte velocità o processi di memoria limitata questi giorni, l'approccio migliore potrebbe essere quella di utilizzare data.table
invece di un data.frame
. Poiché data.table
ha la :=
assegnazione da operatore di riferimento, è possibile aggiornare senza ri-copia:
library(data.table)
dt <- data.table(x=rep(0,1000), y=rep(0,1000))
tracemem(dt)
for(i in 1:1000) {
dt[i,x := runif(1)]
dt[i,y := rnorm(1)]
}
# note no message from tracemem
Ma, come sottolinea @MatthewDowle, set()
è il modo appropriato per farlo all'interno di un ciclo. In questo modo lo rende ancora più veloce:
library(data.table)
n <- 10^6
dt <- data.table(x=rep(0,n), y=rep(0,n))
dt.colon <- function(dt) {
for(i in 1:n) {
dt[i,x := runif(1)]
dt[i,y := rnorm(1)]
}
}
dt.set <- function(dt) {
for(i in 1:n) {
set(dt,i,1L, runif(1))
set(dt,i,2L, rnorm(1))
}
}
library(microbenchmark)
m <- microbenchmark(dt.colon(dt), dt.set(dt),times=2)
(risultati riportati di seguito)
Benchmarking
Con la corsa ciclo 10.000 volte, tabella dei dati è quasi un ordine completo di grandezza più veloce:
Unit: seconds
expr min lq median uq max
1 test.df() 523.49057 523.49057 524.52408 525.55759 525.55759
2 test.dt() 62.06398 62.06398 62.98622 63.90845 63.90845
3 test.stack() 1196.30135 1196.30135 1258.79879 1321.29622 1321.29622
e il confronto di :=
con set()
:
> m
Unit: milliseconds
expr min lq median uq max
1 dt.colon(dt) 654.54996 654.54996 656.43429 658.3186 658.3186
2 dt.set(dt) 13.29612 13.29612 15.02891 16.7617 16.7617
Nota che n
qui è 10^6 non 10^5 come nei benchmark tracciati sopra.Quindi c'è un ordine di grandezza più lavoro, e il risultato è misurato in millisecondi, non secondi. Impressionante davvero.
Per quanto ne so, il tuo ultimo esempio non fa crescere data.table. Basta sovrascrivere la prima riga 1.000 volte. – Andrie
@Andrie. Ops. Risolto il problema. Grazie per segnalarlo. –
Questo è buono ma hai visto l'esempio di velocità nella parte inferiore di '?": = "' Confrontando ': =' all'interno di un ciclo su 'set()' all'interno di un ciclo. ': =' ha un overhead (ad es.controllando l'esistenza e il tipo di argomenti passati a '[.data.table'), che è il motivo per cui' set() 'è previsto per l'uso all'interno di loop. –
Mi piace RSQLite
per questo: dbWriteTable(...,append=TRUE)
dichiarazioni durante la raccolta e la dichiarazione dbReadTable
alla fine.
Se i dati sono abbastanza piccoli, è possibile utilizzare il file ": memory:", se è grande, il disco rigido.
Naturalmente, non può competere in termini di velocità:
makeRow <- function() data.frame(x=runif(1),y=rnorm(1))
library(RSQLite)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
collect1 <- function(n) {
for (i in 1:n) dbWriteTable(con, "test", makeRow(), append=TRUE)
dbReadTable(con, "test", row.names=NULL)
}
collect2 <- function(n) {
res <- data.frame(x=rep(NA, n), y=rep(NA, n))
for(i in 1:n) res[i,] <- makeRow()[1,]
res
}
> system.time(collect1(1000))
User System verstrichen
7.01 0.00 7.05
> system.time(collect2(1000))
User System verstrichen
0.80 0.01 0.81
Ma potrebbe essere meglio se le data.frame
s hanno più di una riga. E non è necessario conoscere il numero di righe in anticipo.
L'idea è interessante, ma non è molto efficiente (http://stackoverflow.com/questions/20689650/how-to-append-rows-to-an-r-data-frame/38052208#38052208). L'ho messo su un test su un altro thread. –
Si potrebbe anche avere un oggetto elenco vuoto in cui gli elementi sono riempiti con i dataframes; poi raccogli i risultati alla fine con un po 'o simili. Un esempio può essere trovato here. Questo non incorre in sanzioni per la crescita di un oggetto.
Beh, sono molto sorpreso che nessuno ha menzionato la conversione ad ancora una matrice ...
Paragonando al dt.colon e dt.set funzioni definite dal Ari B. Friedman, la conversione a una matrice ha il miglior tempo di esecuzione (leggermente più veloce di dt.colon). Tutte le influenze all'interno di una matrice vengono eseguite per riferimento, quindi non viene eseguita alcuna copia di memoria non necessaria in questo codice.
CODICE:
library(data.table)
n <- 10^4
dt <- data.table(x=rep(0,n), y=rep(0,n))
use.matrix <- function(dt) {
mat = as.matrix(dt) # converting to matrix
for(i in 1:n) {
mat[i,1] = runif(1)
mat[i,2] = rnorm(1)
}
return(as.data.frame(mat)) # converting back to a data.frame
}
dt.colon <- function(dt) { # same as Ari's function
for(i in 1:n) {
dt[i,x := runif(1)]
dt[i,y := rnorm(1)]
}
}
dt.set <- function(dt) { # same as Ari's function
for(i in 1:n) {
set(dt,i,1L, runif(1))
set(dt,i,2L, rnorm(1))
}
}
library(microbenchmark)
microbenchmark(dt.colon(dt), dt.set(dt), use.matrix(dt),times=10)
RISULTATO:
Unit: milliseconds
expr min lq median uq max neval
dt.colon(dt) 7107.68494 7193.54792 7262.76720 7277.24841 7472.41726 10
dt.set(dt) 93.25954 94.10291 95.07181 97.09725 99.18583 10
use.matrix(dt) 48.15595 51.71100 52.39375 54.59252 55.04192 10
A favore di utilizzando una matrice:
- questo è il metodo più veloce finora
- non si dispone di impara/usa gli oggetti data.table
Con di utilizzare una matrice:
- si può gestire un solo tipo di dati in una matrice (in particolare, se tu avessi tipi misti nelle colonne del vostro data.frame, allora saranno tutti convertiti a carattere dalla linea: mat = as.matrix (dt) # conversione in matrice)
- 1. La maggior parte della memoria efficiente per far crescere un array in Java?
- 2. Individuare in modo efficiente le colonne della costante di gruppo in un data.frame
- 3. Modo memoria efficiente per memorizzare le stringhe
- 4. Java: memoria efficiente ByteArrayOutputStream
- 5. Rimuovere più chiavi dalla mappa in modo efficiente?
- 6. trasformare in modo sicuro un data.table in un data.frame
- 7. Memoria insufficiente durante la modifica di un grande R data.frame
- 8. Un modo migliore per caricare i vettori dalla memoria. (clang)
- 9. Perché la memoria del mio programma Delphi continua a crescere?
- 10. R: come convertire i dati da data.table() a matrice in modo efficiente (velocità e memoria)
- 11. gestione efficiente della memoria in R
- 12. Erlang sezione di memoria "di sistema" continua a crescere
- 13. usando faretra di matplotlib in un ciclo in modo efficiente
- 14. Utilizzo della memoria continuano a crescere con multiprocessing.pool di Python
- 15. Perché l'utilizzo della memoria del mio tomcat continua a crescere?
- 16. modo efficiente per contenere ed elaborare un grande dict in memoria in python
- 17. È possibile modificare un data.frame sul posto (in modo distruttivo)?
- 18. Come gestisco in modo efficiente più inserti in un array?
- 19. Come archiviare e leggere in modo efficiente una gerarchia dalla cache
- 20. Come utilizzare in modo efficiente MySQLDB SScursor?
- 21. As3 - Come cancellare un array in modo efficiente?
- 22. Come ridimensionare un vettore std :: in modo efficiente per la memoria?
- 23. Common Lisp: Aggiunta di un plist nidificato in modo efficiente
- 24. F # in modo efficiente la rimozione di n elementi dalla fine di un set
- 25. Esecuzione eseguibile dalla memoria
- 26. Come annullare in modo efficiente un completamento automatico in vim
- 27. Ridimensionamento delle immagini con memoria efficiente in Android
- 28. Trovare efficienze uniche in modo efficiente
- 29. Come posso indicizzare in modo efficiente un file?
- 30. Un modo più veloce di trasformare il vettore di testo in matrice numerica/data.frame in R?
a cura di fare quello chiaro sono abbastanza sicuro che volevi dire. Si prega di annullare se ho incasinato. –
Se sei ancora interessato, [ecco un altro punto di riferimento di un altro insieme di modi diversi per far crescere data.frame] (http://stackoverflow.com/questions/20689650/how-to-append-rows-to-an-r -data-frame/38052208 # 38052208) quando non si conoscono le dimensioni in anticipo. –