2012-08-05 29 views
18

我发现自己需要更新以前使用save创建的Rdata文件中的一个或两个数据对象。如果我不小心加载文件,我可以忘记重新保存文件中的一些对象。作为一个例子,我正在处理一些包含sysdata.rda(我不想导出的内部查询表)的对象,只想更新单个对象。更新现有的Rdata文件

我还没有设法解决,如果有一个标准的方式来做到这一点,所以创建了我自己的功能。

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

虽然看起来好像过度。有没有更好/更简单的方法来做到这一点?

另一方面,我是否正确地认为函数范围内创建的新环境在函数调用后被销毁?

+0

是否让一个(或至少我:-))奇怪为什么'save'没有“append”选项。如果有一个有用的答案,我会问r-help并回到这里。 – 2012-08-05 21:33:09

+1

好吧,我看了:https://stat.ethz.ch/pipermail/r-help/2006-March/101259.html给出了与@ flodel提供的答案基本相同的建议。就我个人而言,我希望看到它作为“append = T”选项折叠到基本'save'函数中,但这不是什么大问题。 – 2012-08-05 21:39:09

+0

我用'as.character(替代(list(...)))[ - 1L]'(从'save'复制)。查看邮件列表响应,使用'deparse'而不是'as.character'。这两种方法的优点/缺点是什么? – seancarmody 2012-08-05 21:43:14

回答

21

这里有一个稍微较短的版本:

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

我把事实的load函数返回加载数据的变量名的优势,所以我可以使用,而不是创建一个函数的环境。当使用get时,我很小心只查看调用函数的环境,即parent.frame()

这里是一个仿真:

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

谢谢!一个问题:为什么'list'和'file'参数不在函数的环境中? – seancarmody 2012-08-05 02:20:59

+1

它们在函数的环境中,但我小心不要保存它们:请参阅我只保存'unique(c(previous,var.names))'。 – flodel 2012-08-05 02:28:48

+0

当然。谢谢!很好的答案。 – seancarmody 2012-08-05 02:58:43

0

我已经在计算器包添加@ flodel的答案的重构的版本。它明确使用环境更具防御性。

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