2012-08-05 13 views
18

Mi sono trovato nella posizione di dover aggiornare uno o due oggetti dati in un file Rdata precedentemente creato utilizzando save. Se non sto attento a caricare il file, posso dimenticare di ri-salvare alcuni oggetti nel file. Ad esempio, sto lavorando su un pacchetto con alcuni oggetti memorizzati in sysdata.rda (tabelle di ricerca per uso interno che non voglio esportare) e voglio solo preoccuparmi di aggiornare singoli oggetti.Aggiornamento di un file Rdata esistente

Non sono riuscito a capire se esiste un modo standard per farlo, quindi ho creato la mia funzione.

resave <- function (..., list = character(), file = stop("'file' must be specified")) { 
    # create a staging environment to load the existing R objects 
    stage <- new.env() 
    load(file, envir=stage) 
    # get the list of objects to be "resaved" 
    names <- as.character(substitute(list(...)))[-1L] 
    list <- c(list, names) 
    # copy the objects to the staging environment 
    lapply(list, function(obj) assign(obj, get(obj), stage)) 
    # save everything in the staging environment 
    save(list=ls(stage, all.names=TRUE), file=file) 
} 

Tuttavia, sembra eccessivo. C'è un modo migliore/più semplice per farlo?

Per inciso, ho ragione nel presumere che un nuovo ambiente creato nell'ambito di una funzione venga distrutto dopo la chiamata di funzione?

+0

Fa sì che uno (o almeno io :-)) si chieda perché 'save' non ha l'opzione" aggiungi ". Chiederò r-help e tornerò qui se c'è una risposta utile. –

+1

Ok, ho guardato: https://stat.ethz.ch/pipermail/r-help/2006-March/101259.html fornisce sostanzialmente lo stesso suggerimento della risposta fornita da @flodel. Personalmente mi piacerebbe vedere questo inserito nella funzione di base 'save' come opzione" append = T ", ma non è un grosso problema. –

+0

Ho usato 'as.character (sostituto (lista (...))) [- 1L]' (copia da 'save'). Guardando la risposta alla mailing list, viene usato 'deparse' piuttosto che' as.character'. Quali sono i pro/contro dei due approcci? – seancarmody

risposta

21

Ecco una versione leggermente più corta:

resave <- function(..., list = character(), file) { 
    previous <- load(file) 
    var.names <- c(list, as.character(substitute(list(...)))[-1L]) 
    for (var in var.names) assign(var, get(var, envir = parent.frame())) 
    save(list = unique(c(previous, var.names)), file = file) 
} 

ho approfittato del fatto la funzione load restituisce il nome delle variabili caricate, così ho potuto usare l'ambiente di funzione invece di crearne uno. E quando si utilizza get, sono stato attento a cercare solo nell'ambiente da cui viene chiamata la funzione, ad esempio parent.frame().

Ecco una simulazione:

x1 <- 1 
x2 <- 2 
x3 <- 3 
save(x1, x2, x3, file = "abc.RData") 

x1 <- 10 
x2 <- 20 
x3 <- 30 
resave(x1, x3, file = "abc.RData") 

load("abc.RData") 
x1 
# [1] 10 
x2 
# [1] 2 
x3 
# [1] 30 
+0

Grazie! Una domanda: perché gli argomenti 'list' e' file' non si trovano nell'ambiente della funzione? – seancarmody

+1

Sono nell'ambiente della funzione, ma sto attento a non salvarli: si noti che salvi solo 'unique (c (precedente, var.names))'. – flodel

+0

Naturalmente. Grazie! Bella risposta. – seancarmody

0

Ho aggiunto una versione refactoring di @ di flodel risposta nel pacchetto StackOverflow. Usa gli ambienti esplicitamente per essere un po 'più difensivi.

resave <- function(..., list = character(), file) { 
    e <- new.env() 
    load(file, e) 
    list <- union(list, as.character(substitute((...)))[-1L]) 
    copyEnv(parent.frame(), e, list) 
    save(list = ls(e, all.names=TRUE), envir = e, file = file) 
} 
Problemi correlati