I try to use the apply function using my own function. However, I keep getting this error: Error in match.fun(FUN) :
'calculate_3month_average_volume(volume_matrix, 90)' is not a function, character or symbol
Code below:
#Calculate 3 monthtly average volume (does not work, coding issue)
calculate_3month_average_volume <- function(stock, number_of_days){
return(SMA(stock, number_of_days))
}
avg_volume_matrix <- apply(X = volume_matrix, MARGIN = 2, FUN = calculate_3month_average_volume(volume_matrix,90))
avg_volume_matrix <- apply(volume_matrix,2,function(x){
SMA(x,90) #can also be return(SMA(x,90))
})
Should also do the trick as you don't have to call the function into your environment to begin with.
The issue you are having specifically is that within your apply loop when you state "FUN= calculate_3month_average_volume(volume_matrix,90)", you should match your arguments in the called function with respect to x, as apply(x=,MARGIN=,FUN=,...). If we were using a function that was called into the environment as you have, we would use:
avg_volume_matrix <- apply(volume_matrix,2,calculate_3month_average_volume(x,90))
Related
I created this function to generate the data with the characteristics I need:
genereting_fuction<-function(n){
X1=rnorm(n)+mean_shifts[1]
X4=rnorm(n)+mean_shifts[4]
X2=X1*p12+std_e2*rnorm(n)+mean_shifts[2]
X3=X1*p13+X4*p43+std_e3*rnorm(n)+mean_shifts[3]
X5=X2*p25+X3*p35+std_e5*rnorm(n)+mean_shifts[5]
sample=cbind(X1,X2,X3,X4,X5)
return(sample)
}
if I call it for a single item it works but when I call it in the applay function as follows:
dati<-lapply(1:100, genereting_fuction(100))
I get this error:
Error in genereting_fuction(100) :
could not find function "genereting_fuction"
Note that I prefer the replicate solution by #Jakub.Novotny for your purpose, but to understand what went wrong using lapply, this is why and how to solve it.
Using apply and a function, it assumes x the value of your apply to be provided always in the function.
To make it work you can do two things.
lapply(1:100, function(x) genereting_fuction(100))
include x in your function like genereting_fuction <- function(x, n) { # code here } and then you can use lapply(1:100, genereting_fuction, n = 100)
In my code there is a situation where I conditionally want to use one accessor function or another throughout the code. Instead of having an if-else statement for every time I want to pick which accessor to use and coding it explicitly, I tried to conditionally assign either of the accessor functions to a new function called accessor_fun and use it throughout the code, but this returns an error when I use the accessor function to reassign the values it accesses. Here is a simplified example of the problem I am having:
#reassigning the base r function names to a new function name
alt_names_fun <- names
example_list <- list(cat = 7, dog = 8, fish = 33)
other_example_list <- list(table = 44, chair = 101, desk = 35)
#works
alt_names_fun(example_list)
#throws error
alt_names_fun(example_list) <- alt_names_fun(other_example_list)
#still throws error
access_and_assign <- function(x, y, accessor) {
accessor(x) <- accessor(y)
}
access_and_assign(x = example_list, y = other_example_list, accessor = alt_names_fun)
#still throws error
alt_names_fun_2 <- function(x){names(x)}
alt_names_fun_2(example_list) <- alt_names_fun_2(other_example_list)
#works
names(example_list) <- names(other_example_list)
As you see if you try the code above, an example of the kind of error I am getting is
Error in alt_names_fun(example_list) <- alt_names_fun(other_example_list) :
could not find function "alt_names_fun<-"
So my question is, is there a way to do the reassignment of R accessor functions and use them in a way like I am trying to in the example above?
Accessor functions are really pairs of functions. One for retrieval and one for assignment. If you want to replicate that, you need to replicate both parts
alt_names_fun <- names
`alt_names_fun<-` <- `names<-`
The assignment versions have <- in their name. This is a special naming convection that R uses to find them. Since these are character normally not allowed in basic symbol names, you need to use the back ticks to enclose the function names.
I have script main.R, where I create inv_cov_mat variable. I later load metrics.R and use it to calculate function value (I use it as kind of inter-script function closure). I get error "object 'inv_cov_mat' not found". My code:
main.R:
knn <- function(...)
{
# some code
source("./source/metrics.R")
if (metric == "mahalanobis")
inv_cov_mat <- solve(cov(training_set))
# other code
# calculate distance in given metric between current vector and every row vector from training set matrix
distances <- apply(training_set, 1, metric, vec2=curr_vec) # error
metrics.R:
mahalanobis <- function(vec1, vec2)
{
diff <- vec1 - vec2
sqrt(t(diff) %*% inv_cov_mat %*% diff)
}
I've found simple, even if not elegant answer: use inv_cov_mat as global variable, not inside knn function. Then other scripts can see it.
It's not entirely clear what you want, but if I understand you correctly---you have a character string identifying the metric you want to use, and a function with the same name. So you should be able to use get to retrieve the function based on the name.
metric == "mahalanobis"
metric.fun = get(metric)
distances <- apply(training_set, 1, metric.fun, vec2=curr_vec)
That said, there are probably better ways to organize your code that would avoid this problem entirely, e.g. create a named list of functions for accessing metrics.
EDIT regarding the issue of inv_cov_mat, either pass it as an argument to your metric function or use get inside that function to access variables from the parent environment using the envir argument. Passing the variable as an argument to your metric function is definitely the better and cleaner approach.
Is there any way to throw a warning (and fail..) if a global variable is used within a R function? I think that is much saver and prevents unintended behaviours...e.g.
sUm <- 10
sum <- function(x,y){
sum = x+y
return(sUm)
}
due to the "typo" in return the function will always return 10. Instead of returning the value of sUm it should fail.
My other answer is more about what approach you can take inside your function. Now I'll provide some insight on what to do once your function is defined.
To ensure that your function is not using global variables when it shouldn't be, use the codetools package.
library(codetools)
sUm <- 10
f <- function(x, y) {
sum = x + y
return(sUm)
}
checkUsage(f)
This will print the message:
<anonymous> local variable ‘sum’ assigned but may not be used (:1)
To see if any global variables were used in your function, you can compare the output of the findGlobals() function with the variables in the global environment.
> findGlobals(f)
[1] "{" "+" "=" "return" "sUm"
> intersect(findGlobals(f), ls(envir=.GlobalEnv))
[1] "sUm"
That tells you that the global variable sUm was used inside f() when it probably shouldn't have been.
There is no way to permanently change how variables are resolved because that would break a lot of functions. The behavior you don't like is actually very useful in many cases.
If a variable is not found in a function, R will check the environment where the function was defined for such a variable. You can change this environment with the environment() function. For example
environment(sum) <- baseenv()
sum(4,5)
# Error in sum(4, 5) : object 'sUm' not found
This works because baseenv() points to the "base" environment which is empty. However, note that you don't have access to other functions with this method
myfun<-function(x,y) {x+y}
sum <- function(x,y){sum = myfun(x+y); return(sUm)}
environment(sum)<-baseenv()
sum(4,5)
# Error in sum(4, 5) : could not find function "myfun"
because in a functional language such as R, functions are just regular variables that are also scoped in the environment in which they are defined and would not be available in the base environment.
You would manually have to change the environment for each function you write. Again, there is no way to change this default behavior because many of the base R functions and functions defined in packages rely on this behavior.
Using get is a way:
sUm <- 10
sum <- function(x,y){
sum <- x+y
#with inherits = FALSE below the variable is only searched
#in the specified environment in the envir argument below
get('sUm', envir = environment(), inherits=FALSE)
}
Output:
> sum(1,6)
Error in get("sUm", envir = environment(), inherits = FALSE) :
object 'sUm' not found
Having the right sum in the get function would still only look inside the function's environment for the variable, meaning that if there were two variables, one inside the function and one in the global environment with the same name, the function would always look for the variable inside the function's environment and never at the global environment:
sum <- 10
sum2 <- function(x,y){
sum <- x+y
get('sum', envir = environment(), inherits=FALSE)
}
> sum2(1,7)
[1] 8
You can check whether the variable's name appears in the list of global variables. Note that this is imperfect if the global variable in question has the same name as an argument to your function.
if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv))
stop("Do not use a global variable!")
The stop() function will halt execution of the function and display the given error message.
Another way (or style) is to keep all global variables in a special environment:
with( globals <- new.env(), {
# here define all "global variables"
sUm <- 10
mEan <- 5
})
# or add a variable by using $
globals$another_one <- 42
Then the function won't be able to get them:
sum <- function(x,y){
sum = x+y
return(sUm)
}
sum(1,2)
# Error in sum(1, 2) : object 'sUm' not found
But you can always use them with globals$:
globals$sUm
[1] 10
To manage the discipline, you can check if there is any global variable (except functions) outside of globals:
setdiff(ls(), union(lsf.str(), "globals")))
Is there any way to throw a warning (and fail..) if a global variable is used within a R function? I think that is much saver and prevents unintended behaviours...e.g.
sUm <- 10
sum <- function(x,y){
sum = x+y
return(sUm)
}
due to the "typo" in return the function will always return 10. Instead of returning the value of sUm it should fail.
My other answer is more about what approach you can take inside your function. Now I'll provide some insight on what to do once your function is defined.
To ensure that your function is not using global variables when it shouldn't be, use the codetools package.
library(codetools)
sUm <- 10
f <- function(x, y) {
sum = x + y
return(sUm)
}
checkUsage(f)
This will print the message:
<anonymous> local variable ‘sum’ assigned but may not be used (:1)
To see if any global variables were used in your function, you can compare the output of the findGlobals() function with the variables in the global environment.
> findGlobals(f)
[1] "{" "+" "=" "return" "sUm"
> intersect(findGlobals(f), ls(envir=.GlobalEnv))
[1] "sUm"
That tells you that the global variable sUm was used inside f() when it probably shouldn't have been.
There is no way to permanently change how variables are resolved because that would break a lot of functions. The behavior you don't like is actually very useful in many cases.
If a variable is not found in a function, R will check the environment where the function was defined for such a variable. You can change this environment with the environment() function. For example
environment(sum) <- baseenv()
sum(4,5)
# Error in sum(4, 5) : object 'sUm' not found
This works because baseenv() points to the "base" environment which is empty. However, note that you don't have access to other functions with this method
myfun<-function(x,y) {x+y}
sum <- function(x,y){sum = myfun(x+y); return(sUm)}
environment(sum)<-baseenv()
sum(4,5)
# Error in sum(4, 5) : could not find function "myfun"
because in a functional language such as R, functions are just regular variables that are also scoped in the environment in which they are defined and would not be available in the base environment.
You would manually have to change the environment for each function you write. Again, there is no way to change this default behavior because many of the base R functions and functions defined in packages rely on this behavior.
Using get is a way:
sUm <- 10
sum <- function(x,y){
sum <- x+y
#with inherits = FALSE below the variable is only searched
#in the specified environment in the envir argument below
get('sUm', envir = environment(), inherits=FALSE)
}
Output:
> sum(1,6)
Error in get("sUm", envir = environment(), inherits = FALSE) :
object 'sUm' not found
Having the right sum in the get function would still only look inside the function's environment for the variable, meaning that if there were two variables, one inside the function and one in the global environment with the same name, the function would always look for the variable inside the function's environment and never at the global environment:
sum <- 10
sum2 <- function(x,y){
sum <- x+y
get('sum', envir = environment(), inherits=FALSE)
}
> sum2(1,7)
[1] 8
You can check whether the variable's name appears in the list of global variables. Note that this is imperfect if the global variable in question has the same name as an argument to your function.
if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv))
stop("Do not use a global variable!")
The stop() function will halt execution of the function and display the given error message.
Another way (or style) is to keep all global variables in a special environment:
with( globals <- new.env(), {
# here define all "global variables"
sUm <- 10
mEan <- 5
})
# or add a variable by using $
globals$another_one <- 42
Then the function won't be able to get them:
sum <- function(x,y){
sum = x+y
return(sUm)
}
sum(1,2)
# Error in sum(1, 2) : object 'sUm' not found
But you can always use them with globals$:
globals$sUm
[1] 10
To manage the discipline, you can check if there is any global variable (except functions) outside of globals:
setdiff(ls(), union(lsf.str(), "globals")))