I have been reading Hadley Wickham's Advanced R in order to gain a better understanding of the mechanism or R and how it works behind the scene. I have so far enjoyed and everything is quite clear, there is one question that occupy s my mind for which I have not yet found an explanation.
I am quite familiar with the scoping rules of R which determines how values are assigned to FREE VARIABLES, However I have been grappling with the idea that why R cannot find the value of a formal argument through lexical scoping in the first case? consider the following example:
y <- 4
f1 <- function(x = 2, y) {
x*2 + y
}
f1(x = 3)
I normally throws and error cause I didn't assign a default value for argument y, however if I create a local variable y in the body of the function it won't throw any error:
f1 <- function(x = 2, y) {
y <- 4
x*2 + y
}
f1(x = 3)
Thank you very much in advance
You have defined y in f1(), you just haven't bound a value to it. The y that is in the global environment is a completely different variable.
You have specified an argument y for the function, but not providing any value when asked for a value in return. So this will work
f1(x = 3, y)
[1] 10
Here it takes y your defined variable as an input for the second argument which incidentally is also named y and returns a value.
even this will also work. As you have defined a default value to this function
y1 <- 4
f1 <- function(x = 2, y= y1) {
x*2 + y
}
f1(x=3)
#> [1] 10
f1(x = 3, 5)
#> [1] 11
Created on 2021-05-03 by the reprex package (v2.0.0)
If you want to evaluate any function without giving any value for any argument, you have to define that in function itself.
Related
I am trying to fix the code below. The below code is a simplified version of my real code
fa=function(x){
x+y
}
fb=function(x,func){
y=rnorm(1)
func(x)
}
fb(3,fa)
Running the code returns the error:
"Error in func(x) : object 'y' not found".
I can fix it by moving y=rnorm(1) to the global environment but I need y to be in function since in my real code there is a for loop and y changes in each iteration.
Really appreciate any help to fix this problem
You could use match.fun to pass function as an argument. I'm not sure about what is the best approach for this particular question though.
fa = function(x, y){
x + y
}
set.seed(42)
fb = function(x, func){
y = rnorm(1)
match.fun(func)(x, y)
}
fb(3, fa)
#[1] 4.370958
I have a bivariate step function that I want to create a surface of. The function looks essentially as follows:
df<-data.frame(a = rnorm(100, 0, 10), b = rnorm(100, 0, 10))
f<-function(x,y){
mean(df$a * x >= df$b * y)
}
When I use plot3d of the rgl package, I always receive an error message like
Error in dim(zvals) <- dim(xvals) :
dims [product 10201] do not match the length of object [1]
What is the problem here? Is there any alternative how to 3d-plot my function?
The problem is the definition of f. plot3d(f) is going to pass in vectors for x and y, and your function is going to take the mean of everything and return a single value.
The simplest way to fix this is to call the Vectorize function, which wraps f in loops to compute it separately for each x, y pair. For example, with your definition of f as in the question,
plot3d(Vectorize(f), xlim = c(-2,2), ylim = c(-2, 2))
produces this plot:
My question is regarding the following code:
myfunc <- function(v1) {
deparse(substitute(v1))
}
myfunc(foo)
[1] "foo"
I typed in ?deparse and ?substitute into R and obtained the following:
deparse = Turn unevaluated expressions into character strings.
and
substitute = returns the parse tree for the (unevaluated) expression expr,
substituting any variables bound in env.
I don't seem to really understand this language. Would someone be able to simplify the technical aspect of these descriptions so that I could begin to appreciate how these two functions work together to allow us to do something cool like access the variable name of an object?
I struggle(d) with this too. The myplot() example from ?substitute is helpful. There, they define:
myplot <- function(x, y)
plot(x, y, xlab = deparse(substitute(x)),
ylab = deparse(substitute(y)))
calling
myplot(x=1:10, y = rnorm(10))
gives
whereas the alternative
x = 1:10
y = rnorm(10)
plot(x, y, xlab = x, ylab = y)
gives
Hopefully this shows what deparse(substitute()) is used for. In the plot version, the xlab and ylab arguments are the outputs of whatever was used to generate x and y. myplot knows to pass "character string versions of the actual arguments to the function" for xlab and ylab. (quotes from ?substitute)
How does the following code work? I got the example when I was reading the help line of R ?curve. But i have not understood this.
for(ll in c("", "x", "y", "xy"))
curve(log(1+x), 1, 100, log = ll,
sub = paste("log= '", ll, "'", sep = ""))
Particularly , I am accustomed to numeric values as arguments inside the for-loop as,
for(ll in 1:10)
But what is the following command saying:
for(ll in c("","x","y","xy"))
c("","x","y","xy") looks like a string vector? How does c("","x","y","xy") work inside curve
function as log(1+x)[what is x here? the string "x"? in c("","x","y","xy")] and log=ll ?
Apparently, there are no answers on stack overflow about how the curve function in R works and especially about the log argument so this might be a good chance to delve into it a bit more (I liked the question btw):
First of all the easy part:
c("","x","y","xy") is a string vector or more formally a character vector.
for(ll in c("","x","y","xy")) will start a loop of 4 iterations and each time ll will be '','x','y','xy' respectively. Unfortunately, the way this example is built you will only see the last one plotted which is for ll = 'xy'.
Let's dive into the source code of the curve function to answer the rest:
First of all the what does the x represent in log(1+x)?
log(1+x) is a function. x represents a vector of numbers that gets created inside the curve function in the following part (from source code):
x <- exp(seq.int(log(from), log(to), length.out = n)) #if the log argument is 'x' or
x <- seq.int(from, to, length.out = n) #if the log argument is not 'x'
#in our case from and to are 1 and 100 respectively
As long as the n argument is the default the x vector will contain 101 elements. Obviously the x in log(1+x) is totally different to the 'x' in the log argument.
as for y it is always created as (from source code):
y <- eval(expr, envir = ll, enclos = parent.frame()) #where expr is in this case log(1+x), the others are not important to analyse now.
#i.e. you get a y value for each x value on the x vector which was calculated just previously
Second, what is the purpose of the log argument?
The log argument decides which of the x or y axis will be logged. The x-axis if 'x' is the log argument, y-axis if 'y' is the log argument, both axis if 'xy' is the log argument and no log-scale if the log argument is ''.
It needs to be mentioned here that the log of either x or y axis is being calculated in the plot function in the curve function, that is the curve function is only a wrapper for the plot function.
Having said the above this is why if the log argument is 'x' (see above) the exponential of the log values of the vector x are calculated so that they will return to the logged ones inside the plot function.
P.S. the source code for the curve function can be seen with typing graphics::curve on the console.
I hope this makes a bit of sense now!
I would like to write a function that takes any user-provided mathematical function (e.g., x^2) and do different things with it, for example:
#-----------------nonworking code---------------------
foo <- function(FUN, var){
math_fun <- function(x){
FUN
}
curve(math_fun, -5, 5) #plot the mathematical function
y = math_func(var) #compute the function based on a user provided x value.
points(x=var, y=y) #plot the value from the last step.
}
#A user can use the function defined above in a way as shown below:
Function <- x^2 + x
foo(FUN=Function, var = 2)
But obviously this function doesn't work:
First of all, if I run this function, I get Error in math_fun(x) : object 'x' not found.
Second of all, even if the function did work, I am assuming that the variable is x, but the user can make use of any letter.
For this second problem, one potential solution is to also ask the user to specify the letter they use as the variable.
foo <- function(FUN, var, variable){
math_fun <- function(variable){
FUN
}
curve(math_fun, -5, 5)
y = math_func(var)
points(x=var, y=y)
}
But I am at loss as to how exactly I can implement this... If someone can help me solve at least part of the problem, that would be great. Thanks!
It is a lot simpler than that. The user defined function should contain the arguments in its definition, e.g. function(x) x^2 + x instead of x^2 + x. Then it can be passed and called directly:
foo <- function(math_fun, var){
curve(math_fun, -5, 5) #plot the mathematical function
y = math_fun(var) #compute the function based on a user provided x value
points(x=var, y=y) #plot the value from the last step.
}
#A user can use the function defined above in a way as shown below:
Function <- function(x) x^2 + x
foo(Function, var = 2)