2012-08-05 61 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) 
}