2012-01-02 26 views
40

Ho un file Rdata contenente vari oggetti:Chiedi oggetto specifico da RDATA presentare

New.Rdata 
    |_ Object 1 (e.g. data.frame) 
    |_ Object 2 (e.g. matrix) 
    |_... 
    |_ Object n 

Naturalmente posso caricare il frame di dati con load('New.Rdata'), tuttavia, c'è un modo intelligente per caricare un solo oggetto specifico fuori di questo file e scartare gli altri?

+1

Nei commenti, @DWin dice no. http://stackoverflow.com/questions/6550510/examining-contents-of-rdata-file-by-attaching-into-a-new-environment-possible –

+1

Ma in tutte le questioni-R rimando a Simon. –

risposta

61

. I file di dati non hanno un indice (i contenuti sono serializzati come un grande pairlist). Puoi hackerare un modo per passare attraverso il pairlist e assegnare solo le voci che ti piacciono, ma non è facile dato che non puoi farlo al livello R.

Tuttavia, è possibile convertire semplicemente il file .RData in un database a caricamento lento che serializza ciascuna voce separatamente e crea un indice. La cosa bella è che il carico sarà on-demand:

# convert .RData -> .rdb/.rdx 
e = local({load("New.RData"); environment()}) 
tools:::makeLazyLoadDB(e, "New") 

Caricamento del DB quindi carica solo l'indice, ma non il contenuto. I contenuti vengono caricati in cui sono utilizzati:

lazyLoad("New") 
ls() 
x # if you had x in the New.RData it will be fetched now from New.rdb 

Proprio come con load() è possibile specificare un ambiente di caricare in modo che non c'è bisogno di inquinare lo spazio di lavoro globale ecc

+1

Ma la ricerca richiederà ancora un accesso seriale tramite "New.RData" per ottenere "x", giusto? Quindi, se "x" si trova alla fine di "New.RData", potrebbero non esserci risparmi di tempo? Domanda 2: non ci sarà memoria occupata con gli altri oggetti incontrati mentre il processo di unserializzazione si fa strada attraverso "New.RData"? –

+1

No, la ricerca cerca solo in 'New.rdb' all'inizio di' x' e carica solo 'x'. –

+8

Quali sono le possibilità che queste funzioni diventino meno interne? – hadley

10

È possibile utilizzare attach piuttosto di load che collegherà l'oggetto dati al percorso di ricerca, quindi è possibile copiare l'oggetto a cui si è interessati e staccare l'oggetto .Rdata.

Questo carica ancora tutto, ma è più semplice lavorare con il caricamento di tutto nello spazio di lavoro globale (probabilmente sovrascrivendo le cose che non si desidera sovrascrivere) eliminando tutto ciò che non si desidera.

+3

Questa risposta è buona, ma sarebbe più completa con un esempio, perché il distacco dell'oggetto .RData dal percorso di ricerca non è intuitivo. Esempio per recuperare 'someObj' da' someFile.RData': 'attach ('someFile.RData'); someObj <- someObj; detach ('file: someFile.RData') ' – C8H10N4O2

+0

@ C8H10N4O2, il tuo esempio è buono (e molto esplicito). Ma se si collega nella posizione predefinita (2) e non si aggiunge altro prima di chiamare detach, i valori di default funzionano e si può semplicemente chiamare 'detach()' senza argomenti e scollegherà il file. Questo è più veloce e più semplice; il tuo approccio è più sicuro. –

4

La risposta di Simon Urbanek è molto, molto bella. Un inconveniente è che non sembra funzionare se un oggetto da salvare è troppo grande:

tools:::makeLazyLoadDB(
    local({ 
    x <- 1:1e+09 
    cat("size:", object.size(x) ,"\n") 
    environment() 
    }), "lazytest") 
size: 4e+09 
Error: serialization is too large to store in a raw vector 

Sto indovinando che questo è dovuto ad una limitazione della corrente implementazione di R (ho 2.15. 2) piuttosto che esaurire la memoria fisica e lo scambio. Il pacchetto saves potrebbe tuttavia essere un'alternativa per alcuni usi.

+1

Questo è più un commento esteso piuttosto che una risposta. – C8H10N4O2