Assigning and Removing Objects in a Loop: Eval(Parse(Paste(

Assigning and removing objects in a loop: eval(parse(paste(

That's a pretty disgusting and frustrating way to go about it. Use assign to assign and rm's list argument to remove objects.

> for (i in 1:length(x[1,1,])) {
+ assign(letters[i],mean(x[,,i]))
+ }
> ls()
[1] "a" "b" "c" "i" "x"
> a
[1] 3.5
> b
[1] 9.5
> c
[1] 15.5
> for (i in 1:length(x[1,1,])) {
+ rm(list=letters[i])
+ }
> ls()
[1] "i" "x"
>

Whenever you feel the need to use parse, remember fortune(106):

If the answer is parse() you should
usually rethink the question.

-- Thomas Lumley, R-help (February 2005)

Loading and removing datasets using paste in R

The list argument of rm should do what you want. It takes character of variable names which are removed. So, something like this should work:

for (i in 1:n) {
loaded <- load(paste0("C", i, ".R"))
# do stuff to dataset
rm(list = loaded)
}

Note, that the load function returns a character with the names of the loaded object(s). So we can use that when removing the loaded object(s) again. The loaded object(s) with load does not nessesarily correspond to the filename.

How can I assign a function to a variable that its name should be made by paste function?

This is FAQ 7.21. The most important part of that FAQ is the last part that says not to do it that way, but to put everything into a list and operate on the list.

You can put your objects into a list using code like:

mylists <- lapply( 1:10, function(i) get( paste0('list',i) ) )

Then you can do the replacement with code like:

mylists <- lapply( mylists, function(x) { x[[1]] <- FUN()
x} )

Now if you want to save all the lists, or delete all the lists, you just have a single object that you need to work with instead of looping through the names again. If you want to do something else to each list then you just use lapply or sapply on the overall list in a single easy step without worrying about the loop. You can name the elements of the list to match the original names if you want and access them that way as well. Keeping everything of interest in a single list will also make your code safer, much less likely to accidentilly overwrite or delete another object.

How to modify a certain row of a matrix, which has to be called by paste()

Consider saving all objects into a list using lapply especially since they are the same structure. With this approach, you avoid millions of matrices flooding your global environment becoming a management headache! Plus, you can easily run the same operations like the rth row across all matrix elements. Additionally, you avoid nested for loops or using assign and get and eval(parse(paste...))). And then you still can get those million objects from list, using list2env:

# LIST OF A MILLION MATRICES (SAME DIMS) 
matlist <- lapply(seq(1000000), function(i) matrix(ncol=10, nrow=4))

# NAMING LIST ITEMS
itemnames <- paste0("XY", c(outer(seq(1000), seq(1000), paste0)))
matlist <- setNames(matlist, itemnames)

# UPDATING MATRIX
matlist <- setNames(lapply(seq(length(matlist)), function(i){
mat <- matlist[[i]]
for (r in seq(4)) {
mat[r,] <- some_function(i,r)
}
return(mat)
}), itemnames)

# OUTPUT INDIVIDUAL ELEMENTS TO SEPARATE GLOBAL OBJECTS
list2env(matlist, envir=.GlobalEnv)

At a basic level, what does eval-parse do in R?

eval(parse(text = "Larry")) is the same as typing Larry directly into your R terminal.

> "Text"
[1] "Text"
> eval(parse(text = "Text"))
Error in eval(expr, envir, enclos) : object 'Text' not found
> Text = 1:10
> eval(parse(text = "Text"))
[1] 1 2 3 4 5 6 7 8 9 10

It essentially allows you to call objects by their name in a character string. It's useful inside functions where you don't know which object you'll need yet, although most experienced R users find that storing data in a list eliminates most needs for eval(parse(...))

Save object to RData using eval(parse(text=...)))

I think the easiest way to do this is to use

save(list = varName, file = paste0(varName, ".RData"))

It saves having to get (or mget) the variable(s), as save effectively does it for you.

Using eval within a loop

A more R-like way to do this avoiding the assign/eval would be

DF <- data.frame(
x = c(1,2,3,4,5),
y = c(5,4,3,2,1),
y2 = c(1,2,3,4,5))

plotlist <- list(
Plot1 = ggplot(DF, aes(x=x, y=y)) +
geom_point(),
Plot2 = ggplot(DF, aes(x=x, y=y2)) +
geom_point()
)

pdf(paste0("Plot", "_Test.pdf"), height =8, width=16)
lapply(plotlist, print)
dev.off()

All your plots here are easily stored in a list that we can just lapply() over when needed.

The main problem is that ggplot objects won't render until they are print()ed. When you work in the console, by default the result of the last expression is print()ed. But when you run a loop, that default print()ing doesn't happen. That's described in this previous question: R: ggplot does not work if it is inside a for loop although it works outside of it

creating variables in for loops and assigning values

Although @Parfait is totally right and you should prefer using list, here is a possibility to answer your question, using eval and parse. But you need to put your index i at the end of your object name, not in the beginning, to avoid problems:

x = 2
for (i in 1:6){
x <- x + 1
assign(paste0("file_",i), read.xlsx(file.path(path,"Template.xlsx"), sheetIndex = x, colIndex = 1:5, startRow = 6, stringsAsFactors=FALSE)
)

#remove rows where the entire row is NA (do not remove rows that have some values and/or NA, has to be completely NA)
assign(paste0("file_",i),
eval(parse(text = paste0("file_",i))) %>%
filter_all(any_vars(!is.na(.)))

}

You can change filter_at by filter_all, as you are selecting all columns. But you could actually do:

for (i in 1:6){
x <- x + 1
assign(paste0("file_",i),
read.xlsx(file.path(path,"Template.xlsx"), sheetIndex = x, colIndex = 1:5, startRow = 6, stringsAsFactors=FALSE) %>%
filter_all(any_vars(!is.na(.)))
)
}


Related Topics



Leave a reply



Submit