I need to write a function with a function argument, which will slightly modify the function and return the modified function.
what I have so far is
discriminant.functions <- function(priordist1,PC1)
{
g1 <- PC1*match.fun(priordist1)
return(g1)
}
but it doesn't work - i get the following error message when I call the function:
discriminant.functions(function(x1,x2) 36*x1*x2*(1-x1)*(1-x2),0.5)
Error in PC1 * match.fun(priordist1) :
non-numeric argument to binary operator
I am not very experienced with R and so I don't know if there are obvious ways to do this, it really seems like it should be very simple. Any help appreciated, thank you very much!
match.fun is used to check if the argument is a function, you need to call the function here. Either directly func(...) or using do.call like this:
## use ... for extra func arguments
discriminant.functions <-
function(func,PC1,...){
match.fun(func) ## check if func s a function
function(...) PC1* do.call(func,list(...))
}
I test it for * function:
mult2 <- discriminant.functions ("*",2)
mult2(5,4)
[1] 40
Related
I have a problem that there is a function (ex:ROC()). I want to assign this function a name such as right_roc <- ROC() but I have an error like that: object 'right_roc' not found. How to solve this problem? Thanks in advance.
Do it without the parenthesis to get the function itself but not the call of the function:
# create an alias for the sum function
f <- sum
f(1,2,3)
#[1] 6
Do partial function evaluation to create more specific versions of a function:
right_roc <- purrr::partial(nsROC::gROC, side="right")
right_roc(X, D)
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)
I have made a function that takes as an argument another function, the argument function takes as its argument some object (in the example a vector) which is supplied by the original function. It has been challenging to make the function call in the right way. Below are three approaches I have used after having read Programming with dplyr.
Only Option three works,
I would like to know if this is in fact the best way to evaluate a function within a function.
library(dplyr);library(rlang)
#Function that will be passed as an argument
EvaluateThis1 <- quo(mean(vector))
EvaluateThis2 <- ~mean(vector)
EvaluateThis3 <- quo(mean)
#First function that will recieve a function as an argument
MyFunc <- function(vector, TheFunction){
print(TheFunction)
eval_tidy(TheFunction)
}
#Second function that will recieve a function as an argument
MyFunc2 <- function(vector, TheFunction){
print(TheFunction)
quo(UQ(TheFunction)(vector)) %>%
eval_tidy
}
#Option 1
#This is evaluating vector in the global environment where
#EvaluateThis1 was captured
MyFunc(1:4, EvaluateThis1)
#Option 2
#I don't know what is going on here
MyFunc(1:4, EvaluateThis2)
MyFunc2(1:4, EvaluateThis2)
#Option 3
#I think this Unquotes the function splices in the argument then
#requotes before evaluating.
MyFunc2(1:4, EvaluateThis3)
My question is:
Is option 3 the best/most simple way to perform this evaluation
An explanation of what is happening
Edit
After reading #Rui Barradas very clear and concise answer I realised that I am actually trying to do someting similar to below which I didn't manage to make work using Rui's method but solved using environment setting
OtherStuff <-c(10, NA)
EvaluateThis4 <-quo(mean(c(vector,OtherStuff), na.rm = TRUE))
MyFunc3 <- function(vector, TheFunction){
#uses the captire environment which doesn't contain the object vector
print(get_env(TheFunction))
#Reset the enivronment of TheFunction to the current environment where vector exists
TheFunction<- set_env(TheFunction, get_env())
print(get_env(TheFunction))
print(TheFunction)
TheFunction %>%
eval_tidy
}
MyFunc3(1:4, EvaluateThis4)
The function is evaluated within the current environment not the capture environment. Because there is no object "OtherStuff" within that environment, the parent environments are searched finding "OtherStuff" in the Global environment.
I will try to answer to question 1.
I believe that the best and simpler way to perform this kind of evaluation is to do without any sort of fancy evaluation techniques. To call the function directly usually works. Using your example, try the following.
EvaluateThis4 <- mean # simple
MyFunc4 <- function(vector, TheFunction){
print(TheFunction)
TheFunction(vector) # just call it with the appropriate argument(s)
}
MyFunc4(1:4, EvaluateThis4)
function (x, ...)
UseMethod("mean")
<bytecode: 0x000000000489efb0>
<environment: namespace:base>
[1] 2.5
There are examples of this in base R. For instance approxfun and ecdf both return functions that you can use directly in your code to perform subsequent calculations. That's why I've defined EvaluateThis4 like that.
As for functions that use functions as arguments, there are the optimization ones, and, of course, *apply, byand ave.
As for question 2, I must admit to my complete ignorance.
I'm using R to build a mathematical model. I want to write a function f(a, b, g) that takes in 3 arguments and the last one is a function. I want to know can I pass a function as an argument to another function? If this is possible, can you guys give me a simple example?
It is certainly legitimate to pass a function as an argument to another function. Many elementary R functions do this. For example,
tapply(..., FUN)
You can check them by ?tapply.
The thing is, you only treat the name of the function as a symbol. For example, in the toy example below:
foo1 <- function () print("this is function foo1!")
foo2 <- function () print("this is function foo2!")
test <- function (FUN) {
if (!is.function(FUN)) stop("argument FUN is not a function!")
FUN()
}
## let's have a go!
test(FUN = foo1)
test(FUN = foo2)
It is also possible to pass function arguments of foo1 or foo2 to test, by using .... I leave this for you to have some research.
If you are familiar with C language, then it is not difficult to understand why this is legitimate. R is written in C (though its language syntax belongs to S language), so essentially this is achieved by using pointers to function. If case you want to learn more on this, see How do function pointers in C work?
Here's a really simple example from Hadley's text:
randomise <- function(f) f(runif(1e3))
randomise(mean)
#> [1] 0.5059199
randomise(mean)
#> [1] 0.5029048
randomise(sum)
#> [1] 504.245
I'm writing a function which forecasts some user-inputted data, by fitting an AR model. Outside the function, the code may look like
dat <- c(1,1.1,1,1.2)
print(forecast(ar(dat)))
This runs just fine.
If this is now put inside a function, like:
func <- function(data_input)
{
temp <- forecast(ar(data_input))
print(temp)
}
func(dat)
I get this error:
Error in ts(x) : 'ts' object must have one or more observations
Please could someone explain what's going on here?
It works like this:
# library
library(forecast)
# data
dat <- c(1,1.1,1,1.2)
# function definition
func <- function(x){
(temp <- forecast(ar(x)))
}
# usage
func(dat)
However, I do not know why it does not work in your case.
I used the workaround suggested in Why can't I pass a dataset to a function?
This seems to work, so could the issue be
the definition of environments in the parse tree of S4 methods?