R function - Error argument is missing, with no default - r

I am testing a simple function in R that should transform a time series object into a data frame.
However the code works fine outside the function but within the function it gives me the error in the object.
>fx<-function(AMts) {
x<-as.data.frame(AMts)
return(x)
}
>fx()
I expeced to have the data.frame x in my environment, but I got
Error in as.data.frame(AMts) : argument "AMts" is missing, with no default

If it's inside a function, you need to have "<<-" as the assignment operator instead of the traditional "<-". <<- tells R to keep the object after the function is done running.
>fx<-function(AMts) {
x<<-as.data.frame(AMts) # "<<-" is what saves "x" in your environment
return(x) # remove this line; this prints data frame "x" to the console, but it doesn't save it
}
>fx(AMts)
EDIT: As the commenters have already pointed out, you aren't including any parameters in your function. Above I made it fx(AMts) to make it clear you need to pass in AMts to the function too.

Related

R parLapply: How to (or Can we) access an object within the parallel code

I am trying to use parLapply to run a custom function. Since my actual code and data is not very reader friendly, I am creating a pseudo code for reference. I do the following:
a) First, I create a custom function. This function takes an argument say "Argument1". Argument1 is a list object which is what I use to run the parLapply on later.
b) Inside the function, based on Argument1, I create a subset called subset_data (subsetting on the full dataset which is supplied while calling parLapply).
c) After getting subset_data, I obtain a list of unique items for Variable2 and then further subset it depending on the number of unique items in Variable2.
d) Finally I run a function (SomeOtherFunction) which takes subset_data2 as the argument.
SomeCustomFunction = function(Argument1){
subset_data = OriginalData[which(OriginalData$Variable1==Argument1),]
some_other_variable = unique(subset_data$Variable2)
for (object in some_other_variable){
subset_data2 = subset_data[which(subset_data$Variable2 == object),]
FinalOutput = SomeOtherFunction(subset_data2)
}
return(SomeOutput)
}
SomeOtherFunction=function(subset_data2){
#Do Some computation here
}
Next I can create clusters in this way:
cl=parallel::makeCluster(2,type="PSOCK")
registerDoParallel(cl)
And supply the objects Argument1, OriginalData by calling clusterExport and then finally run parLapply by supplying SomeCustomFunction and a list for Argument1 (suppose Argument1_list).
clusterExport(cl=cl, list("Argument1","OriginalData"),envir=environment())
zz=parLapply(cl=cl,fun=SomeCustomFunction,Argument1=Argument1_list)
However, in this case, when I run parLapply, I get an error saying
Error in get(name, envir = envir) : object 'subset_data2' not found
In this case, I was assuming that since subset_data2 is being created within the first function, the object subset_data2 will get supplied automatically. Clearly this is not happening.
Is there a way for me supply this 2nd subset (subset_data2) within the function SomeCustomFunction without passing it to the cluster when calling ClusterExport?
If the question is not clear, please let me know and I can modify it accordingly. Thanks in advance.
P.S. I read this question: using parallel's parLapply: unable to access variables within parallel code, but in my case I do not call parLapply inside my function.
In the related question you mention, the top answer passes clusterExport a character vector of variable names, whereas you pass a list. Also, help(clusterExport) reveals: "varlist: character vector of names of objects to export".
Also, you're missing a " after Argument1 here: list("Argument1,"OriginalData, but I'm guessing that's only the sample code you posted, not in your real code.
PS: It's a step in the right direction that you put some code, but your question will get more responses if you put sample data and code that can be directly pasted and run to reproduce the error.

Why does "<<-" messes with the scope of a function in Shiny

I run into a very interesting problem. I wrote a function and wanted to check the output of some variables within the function as well as the return result.
observe({
result <- myFunction()
})
myFunction <- function() {
# some calculations
# ...
# create Dataframe from previous calculated variables
# I was interested in the result of problematicVariable
# thats why I wanted to make it global for checking, after
# closing down the shiny app
problematicVariable <<- data.frame(...)
if(someCondition) {
# ...
} else {
# some calculations
# ...
# now I used problematicVariable for the first time
foo <- data.frame(problematicVariable$bar, problematicVariable$foo)
}
That gave me
data.frame: arguments imply differing number of rows: ...
However, since I made problematicVariable global I run the line where the App crashed manually (foo <- data.frame(problematicVariable$bar, problematicVariable$foo)). There was absolutely no problem. So I thought, that this is strange...
I got rid of the double << and changed it to problematicVariable <- ... and now it works.
So, using <<- to assign problematicVariable somehow made problematicVariable not available in the if...else.
Why causes <<- a behaviour like this? That messes with the scope?!
<<- doesn't always create variables in the global environment. It will, however, create variables in the parent scope. Sometimes the parent scope is the same as the global environment.
?assign is what you want. But I don't see any reason to create global variables from inside a function. Just return the variable - code is easier to debug that way and you'll get fewer unexpected results.
EDIT: Suspected that this was a dupe. Good discussion about this can be found here.

How do you re-write the rm() function in R to clear your workspace automatically [duplicate]

I am trying to find a way to clear the workspace in R using lists.
According to the documentation, I could simply create a vector with all my workspace objects: WS=c(ls()). But nothing happens when I try element wise deletion with rm(c(ls()) or rm(WS).
I know I can use the command rm(list=ls()). I am just trying to figure how R works. Where did I err in my thinking in applying the rm() function on a vector with the list of the objects?
Specifically, I'm trying to create a function similar to the clc function in MATLAB, but I am having trouble getting it to work. Here's the function that I've written:
clc <- function() { rm(list = ls()) }
From ?rm, "Details" section:
Earlier versions of R incorrectly claimed that supplying a character vector in ... removed the objects named in the character vector, but it removed the character vector. Use the list argument to specify objects via a character vector.
Your attempt should have been:
rm(list = WS)
HOWEVER, this will still leave you with an object (a character vector) named "WS" in your workspace since that was created after you called WS <- c(ls()). To actually get rid of the "WS" object, you would have had to use rm(WS, list = WS). :-)
How does it work? If you look at the code for rm, the first few lines of the function captures any individual objects that have been specified, whether quoted or unquoted. Towards the end of the function, you will find the line list <- .Primitive("c")(list, names) which basically creates a character vector of all of the objects individually named and any objects in the character vector supplied to the "list" argument.
Update
Based on your comment, it sounds like you're trying to write a function like:
.clc <- function() {
rm(list = ls(.GlobalEnv), envir = .GlobalEnv)
}
I think it's a little bit of a dangerous function, but let's test it out:
ls()
# character(0)
for (i in 1:5) assign(letters[i], i)
ls()
# [1] "a" "b" "c" "d" "e" "i"
.clc()
ls()
# character(0)
Note: FYI, I've named the function .clc (with a dot) so that it doesn't get removed when the function is run. If you wanted to write a version of the function without the ., you would probably do better to put the function in a package and load that at startup to have the function available.

Understanding element wise clearing of R's workspace

I am trying to find a way to clear the workspace in R using lists.
According to the documentation, I could simply create a vector with all my workspace objects: WS=c(ls()). But nothing happens when I try element wise deletion with rm(c(ls()) or rm(WS).
I know I can use the command rm(list=ls()). I am just trying to figure how R works. Where did I err in my thinking in applying the rm() function on a vector with the list of the objects?
Specifically, I'm trying to create a function similar to the clc function in MATLAB, but I am having trouble getting it to work. Here's the function that I've written:
clc <- function() { rm(list = ls()) }
From ?rm, "Details" section:
Earlier versions of R incorrectly claimed that supplying a character vector in ... removed the objects named in the character vector, but it removed the character vector. Use the list argument to specify objects via a character vector.
Your attempt should have been:
rm(list = WS)
HOWEVER, this will still leave you with an object (a character vector) named "WS" in your workspace since that was created after you called WS <- c(ls()). To actually get rid of the "WS" object, you would have had to use rm(WS, list = WS). :-)
How does it work? If you look at the code for rm, the first few lines of the function captures any individual objects that have been specified, whether quoted or unquoted. Towards the end of the function, you will find the line list <- .Primitive("c")(list, names) which basically creates a character vector of all of the objects individually named and any objects in the character vector supplied to the "list" argument.
Update
Based on your comment, it sounds like you're trying to write a function like:
.clc <- function() {
rm(list = ls(.GlobalEnv), envir = .GlobalEnv)
}
I think it's a little bit of a dangerous function, but let's test it out:
ls()
# character(0)
for (i in 1:5) assign(letters[i], i)
ls()
# [1] "a" "b" "c" "d" "e" "i"
.clc()
ls()
# character(0)
Note: FYI, I've named the function .clc (with a dot) so that it doesn't get removed when the function is run. If you wanted to write a version of the function without the ., you would probably do better to put the function in a package and load that at startup to have the function available.

Why can't I pass a dataset to a function?

I'm using the package glmulti to fit models to several datasets. Everything works if I fit one dataset at a time.
So for example:
output <- glmulti(y~x1+x2,data=dat,fitfunction=lm)
works just fine.
However, if I create a wrapper function like so:
analyze <- function(dat)
{
out<- glmulti(y~x1+x2,data=dat,fitfunction=lm)
return (out)
}
simply doesn't work. The error I get is
error in evaluating the argument 'data' in selecting a method for function 'glmulti'
Unless there is a data frame named dat, it doesn't work. If I use results=lapply(list_of_datasets, analyze), it doesn't work.
So what gives? Without my said wrapper, I can't lapply a list of datasets through this function. If anyone has thoughts or ideas on why this is happening or how I can get around it, that would be great.
example 2:
dat=list_of_data[[1]]
analyze(dat)
works fine. So in a sense it is ignoring the argument and just literally looking for a data frame named dat. It behaves the same no matter what I call it.
I guess this is -yet another- problem due to the definition of environments in the parse tree of S4 methods (one of the resons why I am not a big fan of S4...)
It can be shown by adding quotes around the dat :
> analyze <- function(dat)
+ {
+ out<- glmulti(y~x1+x2,data="dat",fitfunction=lm)
+ return (out)
+ }
> analyze(test)
Initialization...
Error in eval(predvars, data, env) : invalid 'envir' argument
You should in the first place send this information to the maintainers of the package, as they know how they deal with the environments internally. They'll have to adapt the functions.
A -very dirty- workaround for yourself, is to put "dat" in the global environment and delete it afterwards.
analyze <- function(dat)
{
assign("dat",dat,envir=.GlobalEnv) # put the dat in the global env
out<- glmulti(y~x1+x2,data=dat,fitfunction=lm)
remove(dat,envir=.GlobalEnv) # delete dat again from global env
return (out)
}
EDIT:
Just for clarity, this is really about the worst solution possible, but I couldn't manage to find anything better. If somebody else gives you a solution where you don't have to touch your global environment, by all means use that one.

Resources