R: how to pass functions as arguments to another function - r

Suppose I want to integrate some function that involves sums and products of a few other user defined functions. Lets take an extremely simple example, it gives the same error.
integrate(f = sin + cos, lower=0, upper=1)
This yields "Error in sin + cos : non-numeric argument to binary operator" which I think is saying it doesn't make sense to just add functions together without passing them some sort of argument. So I am a bit stuck here. This thread poses what I think is a solution to a more complicated question, that can be applied here, but it seems long for such a simple task in this case. I'm actually kind of surprised that I am unable to find passing function arguments to functions in the help manual so I think I am not using the right terminology.

Just write your own function:
> integrate(f = function(x) sin(x) + cos(x), lower=0, upper=1)
1.301169 with absolute error < 1.4e-14
In this example I've used an anonymous function, but that's not necessary. The key is to write a function that represents whatever function you want to integrate over. In this case, the function should take a vector input and add the sin and cos of each element.
Equivalently, we could have done:
foo <- function(x){
sin(x) + cos(x)
}
integrate(f = foo, lower=0, upper=1)

This is an old question, but I recently struggled with it, so here is a simple example in case it helps others in the future. #joran's answer is still the best.
Define your first function: f1 <- function(x){return(x*2)}
Test it: f1(8) (expect 8*2=16); returns [1] 16
Define your second function: f2 <-function(f, y){return(f+y)}
Test it: f2(f=f1(8), y=1) (expect 8*2 = 16 +1 = 17); returns [1] 17

Related

Function of x as input in function argument

I have written a function to approximate a derivate in a point x in R like this:
nderiv<- function(f,x,h){
(f(x+h)-f(x))/h
}
And want to make an input in f as either x^2, "x^2" or as a predefined function like:
ex<- function(x){
x^2
}
The code works fine if you use the last example (using a predefined function). But I can't get it to work when inserting the other options.
I either get the error
Error in nderiv(x^2, 1) : object 'x' not found
or
Error in nderiv("x^2", 1, 1e-04) : could not find function "f"
So I would like to be able to write nderiv(x^2,1,0.0001) or nderiv("x^2",1,0.0001) and get the value 2.0001.
Thanks in advance!
If you want to use x^2 as an anonymous function, pass it to nderiv as function(x){x^2}. Something like:
nderiv(function(x){x^2}, 1, 0.0001)

Automatic differentiation with ForwardDiff in Julia

I am having some trouble using correctly the ForwardDiff package in Julia. I have managed to isolate my problem in the following chunk of code.
In short, I define the function:
using ForwardDiff
function likelihood(mu,X)
N = size(X,2)
# Calculate likelihood
aux = zeros(N)
for nn=1:N
aux[nn] = exp(-0.5 * (X[:,nn]-mu)' * (X[:,nn]-mu))[1]
end
# return log-likelihood
return sum(log(aux))
end
I then check if the function works:
# Check if function works at all
X = randn(2,3) # some random data
mu = [1.0;2.0] # arbitrary mean
#show likelihood(mu,X) # works fine for me
I then try to obtain the gradient using:
ForwardDiff.gradient( ARG -> likelihood(ARG, X), mu)
Unfortunately this fails and I see in my screen:
ERROR: MethodError: convert has no method matching
convert(::Type{Float64}, ::ForwardDiff.Dual{2,Float64}) This may have
arisen from a call to the constructor Float64(...), since type
constructors fall back to convert methods. Closest candidates are:
call{T<:AbstractFloat}(::Type{T<:AbstractFloat}, ::Real,
::RoundingMode{T}) call{T}(::Type{T}, ::Any)
convert(::Type{Float64}, ::Int8) ... in likelihood at none:10 in
anonymous at none:1
What am I doing wrong? Thanks, in advance.
I was just informed that this was a careless mistake on my side, though a bit hard to spot to the untrained eye.
The error is at the call to zeros:
aux = zeros(N)
Changing this to
aux = zeros(eltype(mu),N)
solves the problem. Hope this is useful to others.

What causes this weird behaviour in the randomForest.partialPlot function?

I am using the randomForest package (v. 4.6-7) in R 2.15.2. I cannot find the source code for the partialPlot function and am trying to figure out exactly what it does (the help file seems to be incomplete.) It is supposed to take the name of a variable x.var as an argument:
library(randomForest)
data(iris)
rf <- randomForest(Species ~., data=iris)
x1 <- "Sepal.Length"
partialPlot(x=rf, pred.data=iris, x.var=x1)
# Error in `[.data.frame`(pred.data, , xname) : undefined columns selected
partialPlot(x=rf, pred.data=iris, x.var=as.character(x1))
# works!
typeof(x1)
# [1] "character"
x1 == as.character(x1)
# TRUE
# Now if I try to wrap it in a function...
f <- function(w){
partialPlot(x=rf, pred.data=iris, x.var=as.character(w))
}
f(x1)
# Error in as.character(w) : 'w' is missing
Questions:
1) Where can I find the source code for partialPlot?
2) How is it possible to write a function which takes a string x1 as an argument where x1 == as.character(x1), but the function throws an error when as.character is not applied to x1?
3) Why does it fail when I wrap it inside a function? Is partialPlot messing with environments somehow?
Tips/ things to try that might be helpful for solving such questions by myself in future would also be very welcome!
The source code for partialPlot() is found by entering
randomForest:::partialPlot.randomForest
into the console. I found this by first running
methods(partialPlot)
because entering partialPlot only tells me that it uses a method. From the methods call we see that there is one method, and the asterisk next to it tells us that it is a non-exported function. To view the source code of a non-exported function, we use the triple-colon operator :::. So it goes
package:::generic.method
Where package is the package, generic is the generic function (here it's partialPlot), and method is the method (here it's the randomForest method).
Now, as for the other questions, the function can be written with do.call() and you can pass w without a wrapper.
f <- function(w) {
do.call("partialPlot", list(x = rf, pred.data = iris, x.var = w))
}
f(x1)
This works on my machine. It's not so much environments as it is evaluation. Many plotting functions use some non-standard evaluation, which can be handled most of the time with this do.call() construct.
But note that outside the function you can also use eval() on x1.
partialPlot(x = rf, pred.data = iris, x.var = eval(x1))
I don't really see a reason to check for the presence of as.character() inside the function. If you can leave a comment we can go from there if you need more info. I'm not familiar enough with this package yet to go any further.

Error Function Erf(z)

This could be a quick one.
I have not been able to find a function for the mathematical "error function" or the "inverse error function" in R. I have not seen a package either.
I am aware I can script this but I thought someone must have made a package for its various approximations by now. Could be poor Googling due to generic terms "error function" ...
These are very closely related to pnorm() and qnorm(): see the last 4 lines of the example code in ?pnorm:
## if you want the so-called 'error function'
erf <- function(x) 2 * pnorm(x * sqrt(2)) - 1
## (see Abramowitz and Stegun 29.2.29)
## and the so-called 'complementary error function'
erfc <- function(x) 2 * pnorm(x * sqrt(2), lower = FALSE)
## and the inverses
erfinv <- function (x) qnorm((1 + x)/2)/sqrt(2)
erfcinv <- function (x) qnorm(x/2, lower = FALSE)/sqrt(2)
If you want to use complex-valued arguments, you need erfz from the pracma package (as commented above by #eipi10). Otherwise, it's not clear whether there's an advantage to using the versions in pracma (the implementations of pnorm() and qnorm() have been very thoroughly tested over a wide range of parameter values ...)
As far as searching goes,
library("sos")
findFn("erf")
seems to work pretty well ...

Rstudio - Error in user-created function - Object not found

First thing's first; my skills in R are somewhat lacking, so there is a chance I may be using something incorrectly in the following. If I go wrong somewhere, please let me know.
I've been having a problem in Rstudio where I try to create 2 functions for formulae, then use nls() to create a model using those, with which I will make a plot. When I try to run the line for creating it, I get an error message saying an object is missing. It is always the last object in the function of the first "formula", in this case, 'p'.
I'll provide my code here then explain what I am trying to do for a little context;
DATA <- read.csv(file.choose(), as.is=T)
formula <- function(m, h, g, p){(2*m)/(m+(sqrt(m^2+1)))*p*g*(h^2/2)}
formula.2 <- function(P, V, g){P*V*g}
m = 0.85
p = 766.42
g = 9.81
P = 0.962
h = DATA$lithothick
V = DATA$Vol
fit.1 <- nls(formula (P, V, g) ~ formula(m, h, g, p), data = DATA)
If I run it how it is shown, I get the error;
Error in (2 * m)/(m + (sqrt(m^2 + 1))) * p : 'p' is missing
However it will show h if I rearrange the objects in the formula to (m,g,p,h)
Error in h^2 : 'h' is missing
Now, what I'm trying to do is this; I have a .csv file with 3 thicknesses (0.002, 0.004, 0.006 meters) and 3 volumes (10, 25, 50 milliliters). I am trying to see how the rates of strength and buoyancy increase (in relation to each other) as the thickness and volume for each object (respectively) increases. I was hoping to come out with a graph showing the upward trend for each property (strength and buoyancy), as I believe them to be unequal (one exponential the other linear). I hope that isn't more confusing than clarifying, but any pointers would be GREATLY appreciated.
You cannot overload functions this way in R, what you can do is provide optional arguments (which is a kind of overload) with syntax function(mandatory, optionnal="")
For what you are trying to do, you have to use formula.2 if you want to use the 3-arguments formula.
A workaround could be to use one function with one optionnal argument and check if this argument has been used. Something like :
formula = function(m, h, g, p="") {
if (is.numeric(p)) {
(2*m)/(m+(sqrt(m^2+1)))*p*g*(h^2/2)
} else {
m*h*g
}
}
This is ugly and a very bad way to do it (your variables do not really mean the same thing from one call to the other) but it works.

Resources