2012-08-05 21 views
18

Me he encontrado en la necesidad de actualizar uno o dos objetos de datos en un archivo Rdata creado previamente usando save. Si no tengo cuidado de cargar el archivo, puedo olvidar volver a guardar algunos objetos en el archivo. Como ejemplo, estoy trabajando en un paquete con algunos objetos almacenados en sysdata.rda (tablas de búsqueda para uso interno que no deseo exportar) y solo quiero preocuparme por actualizar objetos individuales.Actualización de un archivo Rdata existente

No he podido averiguar si hay una forma estándar de hacerlo, así que creé mi propia función.

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) 
} 

Parece exagerado. ¿Hay una forma mejor/más fácil de hacer esto?

Como un aparte, ¿estoy en lo cierto al suponer que un nuevo entorno creado en el ámbito de una función se destruye después de la llamada a la función?

+0

Hace uno (o al menos yo :-)) se pregunta por qué 'save' no tiene una opción de" agregar ". Preguntaré a r-help y volveré aquí si hay una respuesta útil. –

+1

Ok, miré: https://stat.ethz.ch/pipermail/r-help/2006-March/101259.html da básicamente la misma sugerencia que la respuesta @flodel proporcionada. Personalmente, me gustaría ver esto doblado a la función base 'save' como una opción de" append = T ", pero no es un gran problema. –

+0

He usado 'as.character (sustituto (list (...))) [- 1L]' (copiando desde 'save'). Al mirar la respuesta de la lista de correo, se usa 'deparse' en lugar de' as.character'. ¿Cuáles son los pros/contras de los dos enfoques? – seancarmody

Respuesta

21

Aquí es una versión ligeramente más corto:

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) 
} 

Aproveché el hecho de la función load devuelve el nombre de las variables cargadas, así que podía usar el entorno de la función en lugar de crear uno. Y al usar get, tuve cuidado de mirar solo en el entorno desde el que se llama a la función, es decir, parent.frame().

Aquí es una simulación:

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

¡Gracias! Una pregunta: ¿por qué los argumentos 'list' y' file' no están en el entorno de la función? – seancarmody

+1

Están en el entorno de la función, pero tengo cuidado de no guardarlos: ver que solo guardo 'unique (c (previous, var.names))'. – flodel

+0

Por supuesto. ¡Gracias! Gran respuesta. – seancarmody

0

He añadido una versión refactorizado de respuesta de @ flodel en el paquete stackoverflow. Utiliza entornos explícitamente para ser un poco más defensivo.

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) 
} 
Cuestiones relacionadas