I'm not very familiar with the optim function, and I wanted to get these informations from its results: a) how many iterations were needed for achieving the result? and b) to plot the sequence of partial solutions, that is, the solution obtained in the end of each iteration.
My code until now looks like this:
f1 <- function(x) {
x1 <- x[1]
x2 <- x[2]
x1^2 + 3*x2^2
}
res <- optim(c(1,1), f1, method="CG")
How can I improve it to get further information?
Thanks in advance
You could modify your function to store the values that are passed into it into a global list.
i <- 0
vals <- list()
f1 <- function(x) {
i <<- i+1
vals[[i]] <<- x
x1 <- x[1]
x2 <- x[2]
x1^2 + 3*x2^2
}
res <- optim(c(1,1), f1, method="CG")
Now if you examine i and vals after you run the function you can see what happened. If you want to see the values while optim is running throw a print statement into the function as well.
Passing trace=1 as a control parameter to optim gives you more detailed information about the progress of the optimization:
res <- optim(c(1,1), f1, method="CG", control=list(trace=1))
# Conjugate gradients function minimizer
# Method: Fletcher Reeves
# tolerance used in gradient test=3.63798e-12
# 0 1 4.000000
# parameters 1.00000 1.00000
# * i> 1 4 0.480000
# parameters 0.60000 -0.20000
# i> 2 6 0.031667
# ......
# * i> 13 34 0.000000
# parameters -0.00000 0.00000
# 14 34 0.000000
# parameters -0.00000 0.00000
# Exiting from conjugate gradients minimizer
# 34 function evaluations used
# 15 gradient evaluations used
However, it seems like the information is only written to standard output, so you will have to use sink to pipe the output to a text file, and then do some editing to get the parameter values for plotting.
If all you wanted was the number of function evaluations, see the $counts element of the result:
counts: A two-element integer vector giving the number of calls to
‘fn’ and ‘gr’ respectively. This excludes those calls needed
to compute the Hessian, if requested, and any calls to ‘fn’
to compute a finite-difference approximation to the gradient.
For the partial solutions you'll need #Dason's solution or something like it.
Related
I am struggling to write fast code to compute a function of the following vector:
Currently I code it using for loop, which is very slow:
rho <- 0.9
E_D <- numeric(100)
E_D[1] <- 1
for (t in 2:100){
summm <- sum(cumsum(0.9^(0:(t-2)))^2)
E_D[t] <- t+exp(summm)
}
summm is the element of the vector I analytically defined in the picture above. E_D is a vector, which is some function of that vector. If I set maximum t to 5000, then the code above runs for more than 1 sec on my machine, which is too slow for my purposes.
I tried data.table solution, but it can not accommodate intermediate vector output within a cell:
tempdt <- data.table(prd=2:100 ,summm=0)
tempdt[, summm:=sum(cumsum(rho^(0:(prd-2)))^2)]
Warning message:
In 0:(prd - 2) : numerical expression has 99 elements: only the first used
How to make the code above faster? Please do not tell me that I have to do it in Matlab...
EDIT: To clarify, I need to compute the following vector:
Maybe something like:
n <- 100L
cp <- cumprod(rep(0.9, n - 1L)) / 0.9
cssq <- cumsum(cp)^2
cumsum(cssq)
truncated output:
[1] 1.00000 4.61000 11.95410 23.78082 40.55067 62.50542 89.72283 122.15959 ...
The : is not vectorized. We may need to either loop with sapply/lapply or do a group by row
library(data.table)
tempdt[, summm := sum(cumsum(rho^(0:(prd-2)))^2), seq_len(nrow(tempdt))]
head(tempdt)
# prd summm
#1: 2 1.00000
#2: 3 4.61000
#3: 4 11.95410
#4: 5 23.78082
#5: 6 40.55067
#6: 7 62.50542
My professor has assigned a question for programming in R and I am stuck. He wants us to make a function that will take the exponential (e^(x[i]) of all the numbers in a vector and then sum them. the equation is:
the summation of e^x(i), n, and i=1.
I have made a function that will give me the exponential of the first value in my vector. But I want to get the exponential of all the values and sum them. Here is my code
#Vector for summing
x=c(2,1,3,0.4)
#Code for function
mysum = 0
myfun=function(x){
for (i in 1:length(x)){
mysum = mysum + exp(x[i])
return(mysum)
}
}
myfun(x)
#returns 7.389056
I have also tried using i = 1:1 because the equation specifies i=1, even though I knew that would only go through 1 number, and it gave me the same answer.... obviously.
myfun=function(x){
for (i in 1:1)
Does anyone have any suggestions to get it to sum?
You need to set the initial value of mysum to the accumulation afterwards, and also move the line return(mysum) outsides your for loop to return the result, i.e.,
myfun=function(x){
mysum <- 0
for (i in 1:length(x)){
mysum = mysum + exp(x[i])
}
return(mysum)
}
or just
myfun=function(x){
mysum <- 0
for (i in x){
mysum = mysum + exp(x)
}
return(mysum)
}
Since exp operation is vectoroized, you can also define your function myfun like below
myfun <- function(x) sum(exp(x))
You could also use the fact that most base functions are already vectorized :
1) create a dummy vector
1:10
#> [1] 1 2 3 4 5 6 7 8 9 10
2) apply your function on that vector, you get vectorized result
exp(1:10)
#> [1] 2.718282 7.389056 20.085537 54.598150 148.413159
#> [6] 403.428793 1096.633158 2980.957987 8103.083928 22026.465795
3) Sum that vector
sum(exp(1:10))
#> [1] 34843.77
4) Write your function to gain (a little) time
my_fun <- function(x){sum(exp(x))}
my_fun(1:10)
#> [1] 34843.77
function(q,b,Data1,Data2){
x<-sum(
ifelse(Data1[13+q,b]/Data1[12+q,b]>Data2[13+q,1]/Data2[12+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[11+q,b]>Data2[13+q,1]/Data2[11+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[10+q,b]>Data2[13+q,1]/Data2[10+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[9+q,b]>Data2[13+q,1]/Data2[9+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[8+q,b]>Data2[13+q,1]/Data2[8+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[7+q,b]>Data2[13+q,1]/Data2[7+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[6+q,b]>Data2[13+q,1]/Data2[6+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[5+q,b]>Data2[13+q,1]/Data2[5+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[4+q,b]>Data2[13+q,1]/Data2[4+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[3+q,b]>Data2[13+q,1]/Data2[3+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[2+q,b]>Data2[13+q,1]/Data2[2+q,1],1,0)+
ifelse(Data1[13+q,b]/Data1[1+q,b]>Data2[13+q,1]/Data2[1+q,1],1,0)
)/12
}
Is there a way to simplify this? (no characters, only numbers in the data sets)
Thank you
Two pieces of knowledge you can combine to improve your code:
Firstly, you can divide a single number by a vector and R will return a vector with elementwise divisions. For example:
5 / c(1,2,3,4,5,6)
# [1] 5.0000000 2.5000000 1.6666667 1.2500000 1.0000000 0.8333333
The numerator on both sides of the inequality are the same all the time, you can use the above. So instead of explicitly calling it for every inequality, you can just call it once.
Secondly, an expression with TRUE or FALSE will be coerced to 1 and 0 when you try to perform arithmetic operations (in your case division, or calculating a mean). Inequalities return TRUE or FALSE values. Explicitly telling R to convert them to 0 and 1 is wasted energy, because R will automatically do it in your last step.
Putting this together in a simplified function:
function(q, b, Data1, Data2){
qseq <- (1:12) + q # Replaces all "q+1", "q+2", ... , "q+12"
dat1 <- Data1[qseq, b] # Replaces all "Data1[q+1, b]", ... "Data1[q+12, b]"
dat2 <- Data2[qseq, 1] # Replaces all "Data2[q+1, 1]", ... "Data2[q+12, 1]"
mean( Data1[13+q, b]/dat1 > Data2[13+q, 1]/dat2 )
this simplify a bit:
function(q,b,Data1,Data2){
data1_num <- Data1[13+q,b]
data2_num <- Data2[13+q,1]
x <- 0
for (i in 1:12) {
x <- x + ((data1_num/Data1[i+q,b]) > (data2_num /Data2[i+q,1]))
}
x <- x /12
#return(x)
}
But If you provide data example, and the output your expecting, i'm sure there is way to simplify it better
Say I have a two objects, a and b, and a function f1 in R
a<- 5
b<- 10
f1<-function(){
out<- a+b
return(out)
I want to write a for loop that evaluates the sensitivity of this function to the values of a and b by changing them each and running the function again. I imagine creating a vector of the objects and then running some code like this:
params<- c(a,b)
for(i in params){
store<- i #save the initial value of the object so I can restore it later.
base<-f1() #save function output with original object value
i<- i*1.1 #increase object value by 10%
base.10<- f1() #recalculate and save function output with new object value
calc<- base.10/base #generate a response metric
i<- store #reset the object value to its original value
return(calc)
}
It sounds like you have a function f1 that relies on objects a and b (which are not defined in that function), and you want to test the sensitivity of its output to values of a and b. One way to approach this would be looping through the values you want for the sensitivity analysis and manipulating the parent environment of f1 so it uses these values:
f1 <- function() a + b
sensitivity <- function(params) {
old.f1.env <- environment(f1)
grid <- expand.grid(lapply(params, function(x) x * c(1, 1.1)))
grid$outcome <- apply(grid, 1, function(x) {
for (n in names(x)) {
assign(n, x[n])
}
environment(f1) <- environment()
ret <- f1()
environment(f1) <- old.f1.env
ret
})
grid
}
sensitivity(list(a=5, b=10))
# a b outcome
# 1 5.0 10 15.0
# 2 5.5 10 15.5
# 3 5.0 11 16.0
# 4 5.5 11 16.5
Here, we've performed computed the function value for a grid of a and b values, both at the original a and b value and at a 10% increased value.
Note that a lot of our work came from specifying the variables in the parent environment of f1. I would encourage you to restructure your code so your function f1 takes the relevant parameters as input. Then you could use:
f1 <- function(a, b) a + b
sensitivity <- function(params) {
grid <- expand.grid(lapply(params, function(x) x * c(1, 1.1)))
grid$outcome <- apply(grid, 1, function(x) do.call(f1, as.list(x)))
grid
}
sensitivity(list(a=5, b=10))
# a b outcome
# 1 5.0 10 15.0
# 2 5.5 10 15.5
# 3 5.0 11 16.0
# 4 5.5 11 16.5
This sounds like a perfect use case for closures.
get_f1 <- function(a, b) {
f1<-function(){
out<- a+b
return(out)
}
return(f1)
}
Then:
my_f1 <- get_f1(a=5, b=10)
my_f1() #uses a=5 and b=10 because they are defined in the envir associated with my_f1
So in your loop you could simply do:
base <- (get_f1(a, b))()
base.10 <- (get_f1(a*1.1, b*1.1))()
Obviously you could define get_f1 with arguments i=c(a, b).
Use a closure (function attached to an environment) rather than tinkering with environments!
tl;dr: closures are awesome
Reading some of your comments, I think this is actually what you want: sensitivity takes a function and a list of arguments and returns the sensitivity of the function to its arguments. (BTW what you call sensitivity, already means something else)
sensitivity <- function(fun, args) {
out <- lapply(names(args), function(cur) {
base10 <- do.call(fun, `[[<-`(args, cur, `[[`(args,cur)*1.1))
base10 / do.call(fun, args)
})
names(out) <- names(args)
return(out)
}
Example:
f1 <- function(a,b) a+b
a1 <- list(a=5, b=2)
sensitivity(f1, a1)
This gives
$a
[1] 1.03
$b
[1] 1.07
Example 2:
f2 <- function(x, y, z) x^2 +3*y*z
sensitivity(f2, list(x=1, y=2, z=3))
$x
[1] 1.011053
$y
[1] 1.094737
$z
[1] 1.094737
It works "plug-and-play" with any function, BUT it requires you to define f differently (one would say, correctly). I could write something that would work with your function f as it is written but it would be much work and bad taste. If you want code modularity, you just cannot use side effects...
PS: if you would prefer to have a vector returned instead of a list, simply change lapply to sapply in the definition of sensitivity.
This would give for the last example:
> sensitivity(f2, list(x=1, y=2, z=3))
x y z
1.011053 1.094737 1.094737
PPS: any reason why you are not computing the gradient of f rather than doing what you are doing?
I am trying to optimise a code that I have written using the apply() and similar functions (e.g. lapply()). Unfortunately I do not see much of improvement so searching I came across this post apply() is slow - how to make it faster or what are my alternatives? where a suggestion is to use the function with() instead of apply() which is certainly much faster.
What I want to do is to apply a user defined function to every row of a matrix. This function takes as input the data from the row, makes some calculations and returns a vector with the results.
A toy example where I use the apply() function, the with() and a vectorized version:
#Generate a matrix 10x3
prbl1=matrix(runif(30),nrow=10)
prbl2=data.frame(prbl1)
prbl3=prbl2
#function for the apply()
fn1=function(row){
x=row[1]
y=row[2]
z=row[3]
k1=2*x+3*y+4*z
k2=2*x*3*y*4*z
k3=2*x*y+3*x*z
return(c(k1,k2,k3))
}
#function for the with()
fn2=function(x,y,z){
k1=2*x+3*y+4*z
k2=2*x*3*y*4*z
k3=2*x*y+3*x*z
return(c(k1,k2,k3))
}
#Vectorise fn2
fn3=Vectorize(fn2)
#apply the functions:
rslt1=t(apply(prbl1,1,fn1))
rslt2=t(with(prbl2,fn2(X1,X2,X3)))
rslt2=cbind(rslt2[1:10],rslt2[11:20],rslt2[21:30])
rslt3=t(with(prbl3,fn3(X1,X2,X3)))
All three produce the same output, a matrix 10x3 which is what I want. Nevertheless, notice at rslt2 that I need to bind the results as the output of using with() is a vector of length 300. I suspected that this is due to the fact that the function is not vectorised (if I understood this correctly). In rslt3 I am using a vectorised version of fn2 which generated the output in the expected way.
When I compare the performance of the three, I get:
library(rbenchmark)
benchmark(rslt1=t(apply(prbl1,1,fn1)),
rslt2=with(prbl2,fn2(X1,X2,X3)),
rslt3=with(prbl3,fn3(X1,X2,X3)),
replications=1000000)
test replications elapsed relative user.self sys.self user.child sys.child
1 rslt1 1000000 103.51 7.129 102.63 0.02 NA NA
2 rslt2 1000000 14.52 1.000 14.41 0.01 NA NA
3 rslt3 1000000 123.44 8.501 122.41 0.05 NA NA
where with() without vectorisation is definitely faster.
My question: Since rslt2 is the most efficient approach, is there a way that I can use this correctly without the need to bind the results afterwards? It does the job but I feel is not efficient coding.
The first and third functions you give are being applied 1 row at a time, so are called 10 times in your example. The second function is taking advantage of the fact that multiplication and addition in R are already vectorised and so using any form of loop or ply function is unnecessary. The function is only called once. If you wanted to use your current code, all you'd need to do is change the c to cbind in fn2.
fn2=function(x,y,z){
k1=2*x+3*y+4*z
k2=2*x*3*y*4*z
k3=2*x*y+3*x*z
return(cbind(k1,k2,k3))
}
All that with does is evaluate the expression it's given in the list, data.frame or environment given. So with(prbl2,fn2(X1,X2,X3)) is entirely equivalent to fn2(prbl2$X1, prbl2$X2, prbl2$X3).
Is this your real function? If it is, then problem solved. If not, then it depends on whether your real function consists entirely of operations and functions that already are vectorised or can be replaced with vectorised equivalents.
For the amended function per the comments:
Single row:
fn1 <- function(row){
x <- row[1]
y <- row[2]
z <- row[3]
k1 <- 2*x+3*y+4*z
k2 <- 2*x*3*y*4*z
k3 <- 2*x*y+3*x*z
if (k1>0 & k2>0 &k3>0){
return(cbind(k1,k2,k3))
} else {
k1 <- 5*x+3*y+4*z
k2 <- 5*x*3*y*4*z
k3 <- 5*x*y+3*x*z
if (k1<0 || k2<0 || k3<0) {
return(cbind(0,0,0))
} else {
return(cbind(k1,k2,k3))
}
}
}
Whole matrix:
fn2 <- function(mat) {
x <- mat[, 1]
y <- mat[, 2]
z <- mat[, 3]
k1 <- 2*x+3*y+4*z
k2 <- 2*x*3*y*4*z
k3 <- 2*x*y+3*x*z
l1 <- 5*x+3*y+4*z
l2 <- 5*x*3*y*4*z
l3 <- 5*x*y+3*x*z
out <- array(0, dim = dim(mat))
useK <- k1 > 0 & k2 > 0 & k3 > 0
useL <- !useK & l1 >= 0 & l2 >= 0 & l3 >= 0
out[useK, ] <- cbind(k1, k2, k3)[useK, ]
out[useL, ] <- cbind(l1, l2, l3)[useL, ]
out
}