Maximizing mathematical function which is saved as character string - r

I have the following problem: I'm writing a function which first constructs a long character string which stands for a mathematical function, e.g. "1/(1+exp(-x1+4x3))". I now want to maximize this function, but unfortunately I cannot do so because the mathematical function is only saved as a character string and not as an R-function. How can I solve this problem? Thanks in advance!

If we know what the arguments are ahead of time then (1) would be preferred as it is simpler (4 lines of code) but if we don't then (2) covers generating them as well (8 lines of code).
1) dynamic body This will convert the string s into a function f2 of 2 arguments which we can call from f1 having one argument as required by optim:
s <- "1/(1+exp(-x1+4*x3))" # test input
f1 <- function(x) do.call("f2", as.list(x)) # f1 calls f2
f2 <- function(x1, x3) {}
body(f2) <- parse(text = s)
optim(c(0, 0), f1, control = list(fnscale = -1))
2) dynamic body + dynamic args In the above we dynamically created the body from the string assuming we knew the arguments but if you want to dynamically create both the body and arguments then try this. Here f2 no longer necessarily has 2 arguments but has nv arguments and what they are is derived from the input s.
s <- "1/(1+exp(-x1+4*x3))" # test input - same as above
f1 <- function(x) do.call("f2", as.list(x)) # function on one argument - same as above
# f2 has nv arguments
f2 <- function() {}
p <- parse(text = s)
v <- all.vars(p) # character string of variable names used for arguments
nv <- length(v)
formals(f2) <- setNames(rep(alist(x=), nv), v)
body(f2) <- p
optim(numeric(nv), f1, control = list(fnscale = -1)) # first arg different from (1)

I'm writing a function which first constructs a long character string which stands for a mathematical function
Don't do that. I'm sure there is a better approach.
because the mathematical function is only saved as a character string and not as an R-function
You'd need to parse the string (after making it valid R syntax):
expr <- parse(text = gsub("((?<=\\d)[[:alpha:]])", "\\*\\1","1/(1+exp(-x1+4x3))", perl = TRUE))
Then you can use this expression to "find the maximum" with whatever method you'd like to use.
However, as fortune 106 says:
If the answer is parse() you should usually rethink the question.

Related

transfer character in function to the function in r

I have such a problem, I want to define the grad function as an input of the function. Please see the example below.
f<-function(grad="2*m-4"){
y=grad
return(y)
}
f(3)=2
I'm usually not a fan of using eval(parse(text=..)), but it does do this with a character string:
f <- function(m, grad="2*m-4"){
eval(parse(text = grad))
}
f(3)
# [1] 2
The two take-aways:
if your grad formula requires variables, you should make them arguments of your function; and
parse(text=..) parse the string as if the user typed it in to R's interpreter, and it returns an expression:
parse(text="2*m - 4")
# expression(2*m - 4)
This expression can then be evaluated with eval.

How to save the numbers in the printed strings in R

I want to save the number that is printed using the print() function R. For example,
I have a print(bf(X, Y) command that prints a sentence "Estimated value is : 0.5". How to save only the number 0.5 to a txt/excel file? because I have a loop that will print hundreds of that sentence with different numbers and I want to be able to save all the numbers in a file automatically. Thanks!
Suppose, your function bf(X,Y) returns a string like `"Estimated value is : 0.5". You could use
library(stringr)
as.double(str_extract(bf(X, Y), "\\d+.\\d+"))
to extract the number from this string. Assign it to a vector/data.frame and write it into a .csv.
With base R you could use
as.double(unlist(regmatches(bf(X, Y), gregexpr("\\d+.\\d+", bf(X, Y)))))
I agree with #Ben Bolker. Instead of operating on string you should return the number from the function bf. You can take the print statement outside the function.
For example, if the current state of the function is like this -
bf <- function(X, Y) {
#...some code
#...some code
#res <- calculation for res
print(c("Estimated value is : ", res))
}
Change it to -
bf <- function(X, Y) {
#...some code
#...some code
#res <- calculation for res
res
}
So you can save the output of the function in a variable (res <- bf(X, Y)). If you need the print statement you can add it outside the function.
res <- bf(X, Y)
print(c("Estimated value is : ", res))

Evaluate listed strings to create function object in r

I need a function created by a list of commands to fully evaluate so that it is identical to the "manual" version of the function.
Background: I am using ScaleR functions in Microsoft R Server and need to apply a set of transformations as a function. ScaleR is very picky about needing to be passed a function that is phrased exactly as specified below:
functionThatWorks <- function(data) {
data$marital_status_p1_ismarried <- impute(data$marital_status_p1_ismarried)
return(data)
}
I have a function that creates this list of transformations (and hundreds more, hence the need to functionalize its writing).
transformList <- list ("data$ismarried <- impute(data$ismarried)",
"data$issingle <- impute(data$issingle)")
This line outputs the evaluated string that I want to the console, but I am unaware of a way to move it from console output to being used in a function:
cat(noquote(unlist(bquote( .(noquote(transformList[1]))))))
I need to evaluate functionIWant so that it is identical to functionThatWorks.
functionIWant <- function(data){
eval( cat(noquote(unlist(bquote( .(noquote(transformList[1])))))) )
return(data)
}
identical(functionThatWorks, functionIWant)
EDIT: Adding in the answer based on #dww 's code. It works well in ScaleR. It is identical, minus meaningless spacing.
functionIWant <- function(){}
formals(functionIWant) <- alist(data=NULL)
functionIWant.text <- parse(text = c(
paste( bquote( .(noquote(transformList[1]))), ";", "return(data)\n")
))
body(functionIWant) <- as.call(c(as.name("{"), functionIWant.text))
Maybe something like this?
# 1st define a 'hard-coded' function
f1 <- function (x = 2)
{
y <- x + 1
y^2
}
f1(3)
# [1] 16
# now create a similar function from a character vector
f2 <- function(){}
formals(f2) <- alist(x=2)
f2.text <- parse(text = c('y <- x + 1', 'y^2'))
body(f2) <- as.call(c(as.name("{"), f2.text))
f2(3)
# [1] 16

have an object that is an equation written with sprintf evaluate in R

Say I have written the following object, an equation, eqn.r, using the sprintf command in R, that evaluates based on a vector of input, pizza:
eqn.r<- sprintf("sum((%s - mean(%s,na.rm=T))^2,na.rm=T)",pizza,pizza)
pizza<-c(1:10)
When I type eqn.r into the R console I get this:
"sum((pizza - mean(pizza,na.rm=T))^2,na.rm=T)"
I want it to actually evaluate, and print this:
> sum((pizza - mean(pizza,na.rm=T))^2,na.rm=T)
[1] 82.5
Given a variable name stored as a string, you can the variable's data from the passed data frame using standard indexing. In general, this is much preferred to generating code with something like sprintf or paste and then parsing and evaluating that code.
f <- function(dat, vname) sum((dat[,vname] - mean(dat[,vname], na.rm=T))^2, na.rm=T)
f(iris, "Sepal.Length")
# [1] 102.1683
If you wanted to invoke your function without quotes around the variable name, you could do:
f2 <- function(dat, vname) {
m <- match.call()
x <- with(eval(m[["dat"]]), eval(m[["vname"]]))
sum((x - mean(x,na.rm=T))^2,na.rm=T)
}
f2(iris, Sepal.Length)
# [1] 102.1683

R : Define a function from character string

I'd like to define a function f from parameters and an expression that are character strings read from a .csv file.
This function f has the following expression :
f = function( parameters ) { expression }
where parameters are a list of n parameters and the expression is a function of these parameters.
For example: the parameters are x1,x2,x3, and expression is (x1+x2)*x3.
The function f is then f = function(x1,x2,x3){ (x1+x2)*x3 }.
How I proceed in R to define such functions ?
EDIT add more context:
Given 2 charcaters strings , for body and arguments
body="(x1+x2)*x3"
args = "x1,x2,x3"
How we can get ?:
function (x1, x2, x3)
(x1 + x2) * x3
Note that this question is similar but don't answer exactly this one, since the solution proposed don't create the function formals (arguments) from a character string.
eval() and parse(), used together, may help you do what you want:
body <- "(x1 + x2) * x3"
args <- "x1, x2, x3"
eval(parse(text = paste('f <- function(', args, ') { return(' , body , ')}', sep='')))
# Text it:
f(3,2,5)
## 10
The explanation: parse() will return the parsed, but unevaluated, expression. I use the text argument in the function to pass a string to the parser. eval() will evaluate the parsed expression (in this case, it will execute the code block you've just parsed).
Hope this helps

Resources