How to Neatly Clean My R Workspace While Preserving Certain Objects

How can I neatly clean my R workspace while preserving certain objects?

I would approach this by making a separate environment in which to store all the junk variables, making your data frame using with(), then copying the ones you want to keep into the main environment. This has the advantage of being tidy, but also keeping all your objects around in case you want to look at them again.

temp <- new.env()
with(temp, {
x <- rnorm(25, mean = 65, sd = 10)
y <- rnorm(25, mean = 75, sd = 7)
z <- 1:25
dd <- data.frame(mscore = x, vscore = y, caseid = z)
}
)

dd <- with(temp,dd)

This gives you:

> ls()
[1] "dd" "temp"
> with(temp,ls())
[1] "dd" "x" "y" "z"

and of course you can get rid of the junk environment if you really want to.

Clearing all user-defined objects in R workspace

it is a bit dangerous but:

rm(list=ls())

really, don't do this.

Cleaning up the global environment after sourcing: How to remove objects of a certain type in R

As an alternative approach (similar to @Ken's suggestion from the comments), the following code allows you to delete all objects created after a certain point, except one (or more) that you specify:

freeze <- ls() # all objects created after here will be deleted
var <- letters
for (i in var) {
assign(i, runif(1))
}
df <- data.frame(x1 = a, x2 = b, x3 = c)
rm(list = setdiff(ls(), c(freeze, "df"))) #delete old objects except df

The workhorse here is setdiff(), which will return a list a list of the items that appear in the first list but not the second. In this case, all items created after freeze except df. As an added bonus, freeze is deleted here as well.

What ways are there for cleaning an R environment from objects?

You may want to check out the RGtk2 package.
You can very easily create an interface with Glade Interface Designer and then attach whatever R commands you want to it.

If you want a good starting point where to "steal" ideas on how to use RGtk2, install the rattle package and run rattle();. Then look at the source code and start making your own interface :)

I may have a go at it and see if I can come out with something simple.

EDIT: this is a quick and dirty piece of code that you can play with. The big problem with it is that for whatever reason the rm instruction does not get executed, but I'm not sure why... I know that it is the central instruction, but at least the interface works! :D

TODO:

  • Make rm work
  • I put all the variables in the remObjEnv environment. It should not be listed in the current variable and it should be removed when the window is closed
  • The list will only show objects in the global environment, anything inside other environment won't be shown, but that's easy enough to implement
  • probably there's some other bug I haven't thought of :D

Enjoy

# 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()

Cleaning up the workspace hiding objects

Try this to leave out the "f-dots":

fless <- function() { ls(env=.GlobalEnv)[!grepl("^f\\.", ls(env=.GlobalEnv) )]}

The ls() function looks at objects in an environment. If you only used (as I initially did) :

fless <- function() ls()[!grepl("^f\\.", ls())]

You get ... nothing. Adding .GlobalEnv moves the focus for ls() out to the usual workspace. The indexing is pretty straightforward. You are just removing (with the ! operator) anything that starts with "f." and since the "." is a special character in regex expressions, you need to escape it, ... and since the "\" is also a special character, the escape needs to be doubled.

How do I clear only a few specific objects from the workspace?

You'll find the answer by typing ?rm

rm(data_1, data_2, data_3)

How can I update .RData?

It gets modified if and when you

  1. use save.image()
  2. use q() and answer yes

Otherwise it does not get changed.

My personal preference is to explicitly load and save data I want to cache across sessions or for further analysis.

Is there an R function to specifically remove objects created within one script?

I actually just found a solution that finds all the objects created within one script. The code below relies on getParseData() to screen the script, then find() to find which objects are in the environment.

I wrote the following function, get.objects():

get.objects <- function(path2file = NULL, exception = NULL, source = FALSE, message = TRUE) {
library("utils")
library("tools")

# Step 0-1: Possibility to leave path2file = NULL if using RStudio.
# We are using rstudioapi to get the path to the current file
if(is.null(path2file)) path2file <- rstudioapi::getSourceEditorContext()$path

# Check that file exists
if (!file.exists(path2file)) {
stop("couldn't find file ", path2file)
}

# Step 0-2: If .Rmd file, need to extract the code in R chunks first
# Use code in https://felixfan.github.io/extract-r-code/
if(file_ext(path2file)=="Rmd") {
require("knitr")
tmp <- purl(path2file)
path2file <- paste(getwd(),tmp,sep="/")
source = TRUE # Must be changed to TRUE here
}

# Step 0-3: Start by running the script if you are calling an external script.
if(source) source(path2file)

# Step 1: screen the script
summ_script <- getParseData(parse(path2file, keep.source = TRUE))

# Step 2: extract the objects
list_objects <- summ_script$text[which(summ_script$token == "SYMBOL")]
# List unique
list_objects <- unique(list_objects)

# Step 3: find where the objects are.
src <- paste(as.vector(sapply(list_objects, find)))
src <- tapply(list_objects, factor(src), c)

# List of the objects in the Global Environment
# They can be in both the Global Environment and some packages.
src_names <- names(src)

list_objects = NULL
for (i in grep("GlobalEnv", src_names)) {
list_objects <- c(list_objects, src[[i]])
}

# Step 3bis: if any exception, remove from the list
if(!is.null(exception)) {
list_objects <- list_objects[!list_objects %in% exception]
}

# Step 4: done!
# If message, print message:
if(message) {
cat(paste0(" ",length(list_objects)," objects were created in the script \n ", path2file,"\n"))
}

return(list_objects)
}

To run it, you need a saved script. Here is an example of a script:

# This must be saved as a script, e.g, "test.R".
# Create a bunch of objects
temp <- LETTERS[1:3]
data <- data.frame(x = 1:10, y = 10:1)
p1 <- ggplot(data, aes(x, y)) + geom_point()

# List the objects, and remove them if you wish. Here, I listed as exception p1.
get.objects()
rm(list = get.objects(exception = "p1", message = FALSE))

Note that the function also works for external script and R markdown.
If you run an external script, you will have to run the script before. To do so, change the argument source to TRUE.

I will validate this answer, but will keep an eye on this post in case the community has another solution to suggest!

[As Dr. @AllanCameron pointed it out, it is better to have good practices, which I agree with! But in my case, the good practices present a greater drawback than being messy: saving/loading .Rdata takes too much time (I tried, having less objects does not solves this) + my environment is not that messy, it is just that I do not want to remove all objects.]

Remove all objects of a given type in R

A variation on @Jilber's answer:

rm(list=names(Filter(is.function, mget(ls(all=T)))))


Related Topics



Leave a reply



Submit