有哪些方法可以清除R环境中的对象?

10

我知道可以使用ls()和rm()查看并删除存在于我的环境中的对象。

但是,当处理“旧”的.RData文件时,有时需要将环境分开以找到要保留和留出的内容。

我想做的是,拥有一个类似GUI的界面,让我能够查看这些对象、排序它们(例如按大小排序),并删除我不需要的对象(例如通过复选框界面)。由于我想象中这样的系统目前尚未在R中实现,那么存在什么方法?您用什么清理旧的.RData文件?

谢谢,

Tal


2
请查看这个相关的问题:https://dev59.com/HnE85IYBdhLWcg3wViE4 - gd047
8个回答

17

我从不创建.RData文件。如果你正在进行可重现研究(而你应该这样做!),你应该能够使用R文件从输入数据文件到所有输出中进行源控制。

当您有需要较长时间才能完成的操作时,缓存它们是有意义的。我通常会使用类似以下结构:

 if (file.exists("cache.rdata")) { 
    load("cache.rdata")
 } else {
    # do stuff ...
    save(..., file = "cache.rdata")
 }

这样可以让你从缓存文件中快速工作,当你需要重新计算时,只需删除工作目录中的所有rdata文件。


我不同意。每次加载所有文件,合并它们,准备?我选择一次性数据准备,保存到.RData,并从“load”中进行分析。 - Marek
2
嗨,哈德利 - 理论上我会采取你的立场,但实际上并不总是奏效。例如,我有一些项目需要几分钟的R处理才能获取相关的数据框。在这种情况下,我更愿意按照Marek所写的去做。 - Tal Galili
2
缓存与这种工作实践完全无关。我已经添加了一条注释以使其更清晰。 - hadley

5

基本解决方法是加载您的数据,删除您不需要的内容并保存为新的、干净的数据。


处理这种情况的另一种方式是通过将加载的RData加载到自己的环境中来控制它。

sandbox <- new.env()
load("some_old.RData", sandbox)

现在您可以看到里面的内容。
ls(sandbox)
sapply(ls(sandbox), function(x) object.size(get(x,sandbox)))

然后你有几种选择:

  • 将要保存的内容写入新的RData文件中:save(A, B, file="clean.RData", envir=sandbox)
  • 从环境中删除不需要的内容:rm(x, z, u, envir=sandbox)
  • 将你想要的变量复制到全局工作区并删除sandbox

我通常会选择类似第三个选项,加载我的数据,进行一些检查和转换,将最终数据复制到全局工作区并删除环境。


你总是可以实现自己想要的。所以

  1. 加载数据
    vars <- load("some_old.RData")
  2. 获取大小
    vars_size <- sapply(vars, function(x) object.size(get(x)))
  3. 排序
    vars <- vars[order(vars_size, decreasing=TRUE)]
    vars_size <- vars_size [order(vars_size, decreasing=TRUE)]
  4. 创建对话框(取决于操作系统,在Windows中)
    vars_with_size <- paste(vars,vars_size)
    vars_to_save <- select.list(vars_with_size, multiple=TRUE)
  5. 删除不需要的内容
    rm(vars[!vars_with_size%in%vars_to_save])

为了得到对象大小的美观形式,我使用了基于getAnywhere(print.object_size)的解决方案。

pretty_size <- function(x) {
    ifelse(x >= 1024^3, paste(round(x/1024^3, 1L), "Gb"),
    ifelse(x >= 1024^2, paste(round(x/1024^2, 1L), "Mb"),
    ifelse(x >= 1024  , paste(round(x/1024, 1L), "Kb"),
                        paste(x, "bytes")
    )))
}

然后在第4步中,可以使用paste(vars, pretty_size(vars_size))

感谢Marek。你的代码提供了一些有趣的函数和策略,对我很有帮助。但我仍然希望能够像Nico建议的那样开发出类似的功能-这似乎更容易处理。再次感谢,Tal。 - Tal Galili

3
你可能想查看RGtk2包。你可以使用Glade Interface Designer非常容易地创建一个界面,然后附加任何你想要的R命令。
如果你想要一个好的起点来“窃取”如何使用RGtk2的想法,安装rattle包并运行rattle();。然后查看源代码并开始制作自己的界面:)
我可能会尝试一下,看看能否做出一些简单的东西。
编辑:这是一段快速而肮脏的代码,你可以试着玩一下。它的一个大问题是rm指令由于某种原因没有被执行,但我不确定为什么...我知道它是中心指令,但至少界面是可以工作的!:D
待办事项:
  • rm正常工作
  • 我把所有变量都放在remObjEnv环境中。它不应该列在当前变量中,并且在关闭窗口时应该被删除
  • 列表只显示全局环境中的对象,其他环境中的任何东西都不会显示,但这很容易实现
  • 可能还有一些我没有想到的其他bug:D
享受吧!
# Our environment
remObjEnv <<- new.env()

# Various required libraries
require("RGtk2")

remObjEnv$createModel <- function()
    {
    # create the array of data and fill it in
    remObjEnv$objList <- NULL
    objs <- objects(globalenv())

    for (o in objs)
        remObjEnv$objList[[length(remObjEnv$objList)+1]] <- list(object = o, 
            type = typeof(get(o)),
            size = object.size(get(o)))

    # create list store
    model <- gtkListStoreNew("gchararray", "gchararray", "gint")

    # add items 
    for (i in 1:length(remObjEnv$objList))
        {
        iter <- model$append()$iter

        model$set(iter,
              0, remObjEnv$objList[[i]]$object,
              1, remObjEnv$objList[[i]]$type,
              2, remObjEnv$objList[[i]]$size)
        }

    return(model)
    }

remObjEnv$addColumns <- function(treeview)
    {
    colNames <- c("Name", "Type", "Size (bytes)")

    model <- treeview$getModel()

    for (n in 1:length(colNames))
        {
        renderer <- gtkCellRendererTextNew()
        renderer$setData("column", n-1)
        treeview$insertColumnWithAttributes(-1, colNames[n], renderer, text=n-1)
        }
    }

# Builds the list. 
# I seem to have some problems in correctly build treeviews from glade files
# so we'll just do it by hand :)
remObjEnv$buildTreeView <- function()
    {   
    # create model
    model <- remObjEnv$createModel()
    # create tree view
    remObjEnv$treeview <- gtkTreeViewNewWithModel(model)

    remObjEnv$treeview$setRulesHint(TRUE)
    remObjEnv$treeview$getSelection()$setMode("single")

    remObjEnv$addColumns(remObjEnv$treeview)
    remObjEnv$vbox$packStart(remObjEnv$treeview, TRUE, TRUE, 0)
    }

remObjEnv$delObj <- function(widget, treeview)
    {
    model <- treeview$getModel()
    selection <- treeview$getSelection()
    selected <- selection$getSelected()
    if (selected[[1]])
        {
        iter <- selected$iter
        path <- model$getPath(iter)
            i <- path$getIndices()[[1]]
            model$remove(iter)
        }

    obj <- as.character(remObjEnv$objList[[i+1]]$object)
    rm(obj)
    }

# The list of the current objects
remObjEnv$objList <- NULL

# Create the GUI.
remObjEnv$window <- gtkWindowNew("toplevel", show = FALSE)
gtkWindowSetTitle(remObjEnv$window, "R Object Remover")
gtkWindowSetDefaultSize(remObjEnv$window, 500, 300)
remObjEnv$vbox <- gtkVBoxNew(FALSE, 5)
remObjEnv$window$add(remObjEnv$vbox)

# Build the treeview
remObjEnv$buildTreeView()

remObjEnv$button <- gtkButtonNewWithLabel("Delete selected object")
gSignalConnect(remObjEnv$button, "clicked", remObjEnv$delObj, remObjEnv$treeview)
remObjEnv$vbox$packStart(remObjEnv$button, TRUE, TRUE, 0)

remObjEnv$window$showAll()

谢谢你,Nico。如果你成功了并准备好了什么,请告诉我(tal.galili@gmail.com)。谢谢! - Tal Galili
@Tal Galili:我更新了我的答案,并附上了一段代码。这是供您自由使用的! :) - nico
嗨Nico - 太好了,谢谢!我目前还不能运行它,因为我有一个Gtk2的问题,但是修复后我会运行你的代码。最好的祝福,Tal - Tal Galili
Nico,你认为线程中关于使用gwidgets而不是RGtk2的用户___想法怎么样? - Tal Galili
@Tal Galili:我从未使用过gwidgets,我猜那是一个选项,我通常使用RGtk2,因为它可以很好地集成到Gnome环境中,但这绝对是个人偏好。如果你愿意,你也可以使用Tcl/Tk。 - nico

2

一旦您确定了要保留哪些内容,您可以使用gdata包中的-keep-函数实现其名称所示的功能。

a <- 1
b <- 2
library(gdata)
keep(a, all = TRUE, sure = TRUE)

请参阅help(keep)以获取有关-all-和-sure-选项的详细信息。
all: whether hidden objects (beginning with a .) should be removed, unless explicitly kept.
sure: whether to perform the removal, otherwise return names of objects that would have been removed.

这个函数非常有用,我很惊讶它不是R本身的一部分。

1
这句话的英译中文为:“可怜的家伙的答案可能是:”。其中保留了HTML标签。
ls()
# spot the rank of the variables you want to remove, for example 10 to 25 
rm(list= ls()[[10:25]])
# repeat until satisfied

1

它没有复选框来删除,而是您选择文件,然后单击删除。但是,下面的解决方案非常容易实现:

library(gWidgets)
options(guiToolkit="RGtk2")

## make data frame with files
out <- lapply((x <- list.files()), file.info)
out <- do.call("rbind", out)
out <- data.frame(name=x, size=as.integer(out$size), ## more attributes?
                  stringsAsFactors=FALSE)
## set up GUI
w <- gwindow("Browse directory")
g <- ggroup(cont=w, horizontal=FALSE)
tbl <- gtable(out, cont=g, multiple=TRUE)
size(tbl) <- c(400,400)
deleteThem <- gbutton("delete", cont=g)
enabled(deleteThem) <- FALSE
## add handlers
addHandlerClicked(tbl, handler=function(h,...) {
  enabled(deleteThem) <- (length(svalue(h$obj, index=TRUE)) > 0)
})

addHandlerClicked(deleteThem, handler=function(h,...) {
  inds <- svalue(tbl, index=TRUE)
  files <- tbl[inds,1]
  print(files)                          # replace with rm?
})

谢谢用户___,在我的 RGtk2 再次工作后,我也会尝试这个。最好的祝福,Tal。 - Tal Galili
嗨,我又来了。我试了你给我的代码加上选项(guiToolkit="tcltk"),有一部分是有效的。我可以看到文件列表(虽然我原本想要的是ls()对象,但这也行) - 但我看不到删除按钮(它没有足够的空间)。有什么建议吗? - Tal Galili
是的,那是我还没有解决的表格小问题。一些快速的hack方法是:您可以手动调整窗口大小;将删除按钮移到gtable实例上方,或者使用水平布局(跳过ggroup中的horizontal=FALSE)--John - jverzani

1

OS X的GUI确实有这样一个东西,它被称为Workspace Browser。非常方便。

我也希望有一个界面能够显示对象之间的会话依赖关系,即如果我从plot()开始向后工作,找到创建它所使用的所有对象。这需要解析历史记录。


谢谢 Ken - 听起来是个好主意。你有什么想法吗? - Tal Galili
1
您可以使用 ?browseEnv 在任何平台下浏览工作区。ls.str 提供了控制台的替代方案。 - Richie Cotton
Richie - 谢谢,这非常酷(我知道ls.str,但不知道browseEnv)! - Tal Galili

0

要清理完整的环境,您可以尝试:

rm(list(ls())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接