I was trying to create a function to derive an expression and the command gives the error below.
Can anybody help me ?
derivada<- function(x){
expression(x)
z <- D(x,"x")
print(z)
}
derivada(x^2)
Error in D(x, "x") : object 'x' not found
Something like
derivada <- function(x) D(substitute(x), "x")
derivada(x^2)
## 2 * x
the main point here is that substitute(x) captures the expression that was passed as an argument without attempting to evaluate it. (Dealing with expressions and controlling when they get evaluated is tricky.)
I had the function return an expression (which then gets auto-printed) rather than printing the result
I didn't use curly brackets because the function only takes one expression (although arguably using curly brackets anyway would be better practice)
Related
Why does curve not seem to work with elements extracted from a list?
Consider two seemingly identical functions, but built differently:
a <- function(value){
function(x) x + value
}
m <- lapply(1:3, a)
f <- a(1)
all.equal(f, m[[1]])
#[1] TRUE
curve works for f, but not m[[1]]:
> curve(m[[1]])
Error in curve(m[[1]]) :
'expr' must be a function, or a call or an expression containing 'x'
But it works if the object is extracted before:
d <- m[[1]]
curve(d)
Is there a reason for it?
curve() is a "magic" function that tries to interpret its input as an expression when possible; it doesn't always work.
#user2554330 comments that curve() is expecting (from ?curve):
The name of a function, or a call or an expression written as a function of x which will evaluate to an object of the same length as x.
Instead, m[[1]] is an expression that evaluates to a function. In contrast, d is the name of a function. You can get what you want using curve(m[[1]](x)) which makes the input an expression written as a function of x.
In the code below, R looks at the expression passed to curve() and asks whether is.name(sexpr) is TRUE. This test passes for f but fails for m[[1]] (if you want to test it outside of the function context, you need to compare is.name(quote(f)) and is.name(quote(m[[1]])).
Weirdly enough, plot(m[[1]]) does work (it calls plot.function(), which calls curve() with different arguments internally).
sexpr <- substitute(expr)
if (is.name(sexpr)) {
expr <- call(as.character(sexpr), as.name(xname))
}
else {
if (!((is.call(sexpr) || is.expression(sexpr)) && xname %in%
all.vars(sexpr)))
stop(gettextf("'expr' must be a function, or a call or an expression containing '%s'",
xname), domain = NA)
expr <- sexpr
}
I'd like to wrap around the checkmate library's qassert to check multiple variable's specification at a time. Importantly, I'd like assertion errors to still report the variable name that's out of spec.
So I create checkargs to loop through input arguments. But to get the variable passed on to qassert, I use the same code for each loop -- that ambigious code string gets used for for the error message instead of the problematic variable name.
qassert() (via vname()) is getting what to display in the assertion error like deparse(eval.parent(substitute(substitute(x))). Is there any way to box up get(var) such that that R will see e.g. 'x' on deparse instead?
At least one work around is eval(parse()). But something like checkargs(x="n', system('echo malicious',intern=T),'") has me hoping for an alternative.
checkargs <- function(...) {
args<-list(...)
for(var in names(args))
checkmate::qassert(get(var,envir=parent.frame()),args[[var]])
# scary string interpolation alternative
#eval(parse(text=paste0("qassert(",var,",'",args[[var]], "')")),parent.frame())
}
test_checkargs <- function(x, y) {checkargs(x='b',y='n'); print(y)}
# checkargs is working!
test_checkargs(T, 1)
# [1] 1
# but the error message isn't helpful.
test_checkargs(1, 1)
# Error in checkargs(x = "b", y = "n") :
# Assertion on 'get(var, envir = parent.frame())' failed. Must be of class 'logical', not 'double'.
#
# want:
# Assertion on 'x' failed. ...
substitute() with as.name seems to do the trick. This still uses eval but without string interpolation.
eval(substitute(
qassert(x,spec),
list(x=as.name(var),
spec=args[[var]])),
envir=parent.frame())
Below I define an R function that includes <- as part of its name. I realize, without understanding, that this function uses the value of the right hand side of <-.
Whilst R says that object myfun is not found whilst myfun<- is a function, I cannot understand how I am still able to wrap myx in myfun. In doing so, am I actually calling the myfun<- function? Any insights and guidance from the stackoverflow experts would be appreciated!
'myfun<-' <- function (x,value) x <- paste0(value, " says hello")
myx <- "my_x"
myy <- "my_y"
myfun(myx) <- myy
myx
[1] "my_y says hello"
myfun
Error: object 'myfun' not found
`myfun<-`
function (x,value) x <- paste0(value, " says hello")
As #akrun says, a myfun and amyfun<- would be two different functions, the first one for accessing a value from the symbol table, and the other for assigning a value to a symbol. Looking at the "R Language Definition" in the Function Calls" section we see that:
A special type of function calls can appear on the left hand side of the assignment operator as in
class(x) <- "foo"
What this construction really does is to call the function class<- with the original object and the right hand side. This function performs the modification of the object and returns the result which is then stored back into the original variable.
Your definition of the function also has a aspect that exposes a further misconception. The assignment operation inside the body of that function is entirely unnecessary. The value of the <- function is in fact the RHS's value, so unless you had return()-ed the x, the assignment to x would not be needed. Let's leave the assignment out of the function body and try to make the assignment without first creating an entry in the symbol table for myx:
'myfun<-' <- function (x,value) paste0(value, " says hello")
myy <- "my_y"
myfun(myx) <- myy
#Error in myfun(myx) <- myy : object 'myx' not found
The usual way of creating an entry in the symbol table for an item is to use one of the empty class constructors:
myx <- character(0)
myfun(myx) <- myy
myx
#[1] "my_y says hello" # Success
Note that the assignment operator in the function name directs that the symbol myx be used as the "target", so there is no need for it to have to be a value of "my_x" or anything resembling it's character value. You could have used numeric(0) and you would have only been confusing yourself when you went back later to read your code, but the interpreter would have simply coerced the class of the target symbol to character. R is very weakly typed.
testing<-function(formula=NULL,data=NULL){
if(with(data,formula)==T){
print('YESSSS')
}
}
A<-matrix(1:16,4,4)
colnames(A)<-c('x','y','z','gg')
A<-as.data.frame(A)
testing(data=A,formula=(2*x+y==Z))
Error in eval(expr, envir, enclos) : object 'x' not found
##or I can put formula=(x=1)
##reason that I use formula is because my dataset had different location and I would want
##to 'subset' my data into different set
This is the main flow of my code. I had done some search and seems to be no one ask this kind of stupid question or it is not possible to pass a formula in a if statement. Thank you in advance
if you just want subset of your data.frame create a character object representing the formula like this:
formula="2*x+y==z"
testing<-function(data,formula){with(data = data,expr = eval(parse(text = formula)))}
subset(A,testing(A,formula=formula))
#x y z gg
#2 2 6 10 14
You can change the formula as per your need.
If we need to evaluate it, one option is eval(parse
testing<-function(formula=NULL,data=NULL){
data <- deparse(substitute(data))
if(any(eval(parse(text=paste("with(", data, ",",
deparse(substitute(formula)), ")")))))
print("YESSS")
}
testing(data=A,formula=(2*x+y==z))
#[1] "YESSS"
When you call a function in R it evaluates its arguments first before executing the function.
For example, prod(2+2, 3) is first turned into prod(4, 3) before the function prod() is even called.
Thus, in your code, R starts by trying to solve (2*x+y==Z). It fails because there is no x object outside of the function code. So, it not even begin running testing().
To use your function correctly you should make it clear to R that it is not supposed to calculate (2*x+y==Z). Instead it should pass this information as is. You could do that using the functions expression() and eval().
testing<-function(formula=NULL,data=NULL){
if(with(data,eval(formula==T)){
print('YESSSS')
}
}
A<-matrix(1:16,4,4)
colnames(A)<-c('x','y','z','gg')
A<-as.data.frame(A)
testing(data=A,formula=expression(2*x+y==Z))
However, you will notice that there other problems with your code.
For Z is different than z. Notice that the in colnames you use z and in the formula Z.
The if() only works for when there is a single value of true or false. In your case, you will have one value for each row in A. When this happens, if() will only check if the first row fits the criteria.
If your purpose is subsetting, it is much more easier to do:
A.subset <- subset(A, 2*A$x+A$y == A$z)
After a discussion with my colleague,
here is a kind of solution
testing<-function(cx,cy,px,py,z,data=NULL){
list<-NULL
for(m in 1:nrow(data)){
if(cx*data$x[m]^px+cy*data$y[m]^py+data$z==0){
print(m)}
}
}
but this can deal with polynomial only and with a lot of arguments in the function. I am think of a way to reduce it as a general equation.or maybe this is the most easiest equation.
I am trying to use the package Deriv, to compute symbolic derivatives of a function depending on one or two variables and a vector of parameters. However, i always obtain the error:
Error in FUN(X[[i]], ...) : Could not retrieve body of '[()'
I have tried:
test_fun <- function(x,y,par){x\*par[1]+y\*par[2]}
Deriv(test_fun,"x",par=c(2,2))
which yields the above error. So does
par <- c(2,2)
test_fun <- function(x,y,par){x\*par[1]+y\*par[2]}
Deriv(test_fun,"x")
Obviously
test_fun <- function(x,y,par){x\*2+y\*2}
Deriv(test_fun,"x")
works as intended, but is not what I want.
Reading the Documentation for the Deriv-package, it seems that directly passing additional arguments to the function is not supported. Is there any other way to achieve the desired result?
Updated answer (9/16):
There's two options below for passing the parameters through Deriv. Also note that Derive will retain curly braces in the original function, so either define your functions without them or call eval() afterwards.
Option 1. Define within the call to Deriv
test_fun <- function(x,y,par){x*par[1]+y*par[2]}
eval(Deriv(test_fun(par=c(2,2)),'x'))
# [1] 2
Option 2. Define the parameter values in as a function.
test_fun <- function(x,y,par){x*par[1]+y*par[2]}
tpar <- function() c(2,2)
eval(Deriv(test_fun(par=tpar()), "x"))
# [1] 2