lapply and the save function in R - r

I have created a list of objects in my work environment
data <- c("variable1", "variable2", "variable3")
i would like to save the files to different directories with the variable name as the directory... so i did this to give me a list of file names to pass to the save function via lapply..
paste0(data,"/",data,".rda")
lapply(data,FUN=save,file = paste0(data,"/",data,".rda"))
i get the error
Error in FUN(X[[i]], ...) : object ‘X[[i]]’ not found
i'm not sure what i'm doing wrong here..

Do you have a list of objects, or a list of names of objects? You say you have the former, but the code you give is for the latter.
Also, if you only have one object per file, then it's better to use the saveRDS function (and loadRDS to load it).
lapply(data, function(x) saveRDS(get(x), paste0(x, "/", x, ".rds")))
If you have to use save:
lapply(data, function(x) save(list=x, file=paste0(x, "/", x, ".rds")))

Several things going on here.
First, you need not use lapply when you don't care about the return value of the function called at each iteration. It offers nothing in this case.
Second, and more importantly, what you are doing is writing objects to files with names derived from their variable names in R. That's an anti-pattern.
Instead, create a list of the objects, and use for for the work. We need to use saveRDS for this (thanks Hong Ooi) as l[[n]] is also not the name of an object in the environment.
l <- list(variable1 = variable1, variable2 = variable2, variable3=variable3)
for (n in names(l)) {
fname = paste0(n, '/', n, '.rda')
saveRDS(file=fname, l[[n]])
}
It would be better to just save the entire list, but then all the data would be in one file in one directory.
As for what's actually wrong with your code:
You pass the same value for file to all invocations of save, and you don't intend to do so. This value is a vector, but what you want is that each iteration gets one element from this vector.
The way lapply computes the value to pass to the function confuses save. In particular, it does this:
names <- as.character(substitute(list(...)))[-1L]
That results in something like the following, which is not the name of an object in the environment.
c("variable1", "variable2", "variable3")[[1]]

Related

How to print pdf from a function

I have a series of tables and graphs that are produced from a list in R. I would like to create a pdf for each iteration of the list. I have tried simply using pdf() within the function but I get the error that too many graphic devices are open. How can I do this (and name the files according to the list element name?
So far I have tried:
ReportPDF<-function(x){
pdf(paste(name(x),"~\\Myfile.pdf")
tb<-table(x$acolumn)
print(fb)
}
lapply(mylist,ReportPDF)
I cant quite work out how to attach the name of the list element to the filename and I'm not even sure this is the best way to create a pdf from lapply
Can you clean some of this up?
Please give a more specific example of the object you're passing to ReportPDF(), I would expect a plot object, rather than what appears to be a data frame that you are selecting a column from.
The function example has some errors too, did you mean this?
ReportPDF<-function(x){
pdf(paste(names(x),"Myfile.pdf"))
tb<-table(x$acolumn)
print(tb)
dev.off()
}
lapply(mylist,ReportPDF)
I believe I've done something similar before and can update this answer when I get the other information.
Here's an update making some assumptions about your objects. It uses a for loop as lmo suggests, but I think a more elegant method must exist. I'm using the for loop because lapply passes the object within each element of the list, with no reference to name of the element in the list -- which is what you need to name the files individually. Note the difference between calling mylist[i] and mylist[[i]], which is part of what's breaking the code in your example. In your code, names(x) will get the names of the columns within x, rather than the name of x as it is inside of mylist, which is what you want.
x <- data.frame(acolumn = rnorm(10))
q<- data.frame(acolumn = rnorm(10))
mylist <- list(a = x,b = q)
for(i in seq_along(mylist) ){
filename <- paste(names(mylist[i]),'-myFile.pdf', sep = "")
pdf(filename)
plot(myList[[i]]$acolumn)
dev.off()
}

lapply skipping over the first function argument

Is it possible run lapply such that the X list argument is used as the second argument to FUN and the first argument to FUN is skipped?
One example is rjson::fromJSON(json_str, file, [other arguments]). I have a list containing several file paths of json files and would like to read each of them, collapsing the results into a list.
Normally, lapply would be ideal for this. However, in order to read from a file, the json_str argument cannot be given, even a null value. This is because fromJSON uses missing to check whether arguments are given. If both file and json_str are given, an error is thrown.
That means that lapply(files, fromJSON, json_str = NULL) will not work. I'm aware that I could work around this by manually making my own function as follows.
result <- lapply(files, function(file) {
fromJSON(file = file)
})
However, this seems cumbersome and unnecessary. Is there some cleaner way of doing this?

Lacking output strings when using function in R

I'm having a problem with the below function:
ab<-matrix(c(1:20),nrow=4)
rownames(ab)<-c("a","b","c","d")
cd<-c("a","c")
test<-function(x,y,ID_Tag){
for(i in y) {
M_scaled<-t(scale(t(x),center=T))
a<-quantile(M_scaled[match(i,rownames(x)),])
assign(paste0("Probes_",ID_Tag,"_quan_",i),a)
}
}
test(ab,cd,"C1")
x is the dataframe/matrix
y is the string I need to search for in rownames(x)
ID_Tag is is the number I use to distinguish my samples from each other.
The function is running, but no output is generated into strings afterwards.
Hope somebody can help me
When you use assign within a function it will make the assignment to a variable that is accessible within that function only (i.e. it's like using <-). To get around this, you need to specify the envir argument in assign to be either the global environment globalenv() or the parent frame of the function. So try changing your assign statement to
assign(..., envir = parent.frame())
or
assign(..., envir = globalenv())
depending on what you want exactly (in the example you provided they are equivalent). Have a look at ?parent.frame for more info on these. Another possibility is to specify the pos argument in assign, check ?assign.
As an aside, assigning global objects from within a function can lead to various problems in general. I find it better practice in your example to return a list of objects created in the for loop rather than use assign.

How to use result from function as variable name in R

I am new to R and trying to use file names as variable names in R.
Basically, I have a folder containing a list of files
and I want to load all files into R and use their names for variable names
for(i in list.files()) {
loaddata(i,i)
}
This does not work, I also tried as.name and paste, both don't work.
Can anyone please help?
Here's a one liner that'll get you most of the way:
sapply(list.files("~/r"), FUN = function(X) assign(X, rnorm(1)))
This assigns a random number to an object in the global environment, with each object taking its name from the files in my ~/r/ directory.
To give a concrete example, say we had a directory ~/r and we wished to read the files in and have them as seperate items in the environment -- then one would do the following:
list2env(sapply(list.files("~/r"), FUN = function(X) read.csv(X)), globalenv())
This is a combination of two commands that has the advantage of not cluttering the global environment with the list containing all the files.
In steps we would do:
inList <- sapply(list.files("~/r"), FUN = function(X) read.csv(X))
list2env(inList, globalenv())

How do you stop source from abbreviating function names?

I am trying to source multiple functions, that differ by a number in the name.
For example: func1, func2.
I tried using "func_1", and "func_2", as well as putting the number first, "1func" and "2func". No matter how I index the function names, the source function just reads in one function that it calls "func" - which is not what I want.
I have tried using for-loops and sapply:
for-loop:
func.list <- list.files(path="/some_path",pattern="some pattern",full.names=TRUE)
for(i in 1:length(func.list)){
source(func.list[i])
}
sapply:
sapply(func.list,FUN=source)
I am going to be writing multiple versions of a data correction function, and would really like to be able to index them - because giving a concise, but specific, name would be difficult, and not allow me to selectively source just the function files from their directory.
In my code, func.list gives the output (I have replaced the actual directory because of privacy/contractual issues):
[1] "mypath/1resp.correction.R"
[2] "mypath/2resp.correction.R"
Then when I source func.list with either the for-loop or sapply code (listed above), R only loads one function named resp.correction, with the code body from "2resp.correction.R".
The argument to source is a file name, not a function name. So you cannot be fancy here: you need to provide the exact filenames.
It sounds like your two files contain the definitions of a function with the same name (resp.correction) in both files, so yes, as you source one file after the other, the function is overwritten in your global environment.
You could, inside your loop, reassign the function to a different name:
func.list <- list.files(path="/some_path",pattern="some pattern",full.names=TRUE)
for(i in 1:length(func.list)) {
source(func.list[i], local = TRUE)
assign(paste0("resp.correction", i), resp.correction, envir = .GlobalEnv)
}

Resources