optim in R, finding numeric solution - r

I need to find exact and numerical solutions to a function but my code in R shows Error in optim(start_val[i, ], g) :
function cannot be evaluated at initial parameters
that is my code:
g <- function(x) (3*x[1]+2*x[2]+4*x[3]-4)^2 + (4*x[1]+2*x[2]+4*x[3]-2)^2 + (1*x[1]+1*x[2]+4*x[3]-4)^2
start_val <- expand.grid(c(-10,0,10),c(-10,0,10),c(-10,0,10))
optim_on_a_multiple_grid <- function(start_val, fun, ...) {
opt_result <- sapply(1:nrow(start_val),
function(i) {
res <- optim(start_val[i,], g)
c(res[[1]], res[[2]], res[[4]])
})
rownames(opt_result) <-
c(paste("x_", 1:ncol(start_val),
"_start_val", sep = ""),
paste("x_", 1:ncol(start_val),
"_sol", sep = ""),
paste(c(deparse(substitute(
fun
)), "_min"), collapse = ""),
"convergence")
opt_result
}
round(optim_on_a_multiple_grid(expand.grid(c(-10, 0, 10), c(-10, 0, 10)), g), 3)
Please, point me at my mistakes and explain how to fix them, I am stuck on it for quite a while now

I do not know why you have alot of objects while your aim is to optimize:
Do
# Define g
g <- function(x){
a <- (3 * x[1] + 2 * x[2] + 4 * x[3] - 4)^2
b <- (4 * x[1] + 2 * x[2] + 4*x[3] - 2)^2
d <- (x[1] + x[2] + 4*x[3] - 4)^2
a +b +d
}
optim(par=c(0,0,1), fn=g)
$par
[1] -1.9998762 3.9996836 0.5000453
$value
[1] 8.468819e-09
$counts
function gradient
160 NA
$convergence
[1] 0
$message
NULL
If you need your code:
The problem lies at the very end of it:
You should have:
round(optim_on_a_multiple_grid(start_val, g), 3)

Related

loop though a matrix in R

I try to loop trough a matrix but cant find a easy and elegant way instead of writing many (>10) equations... Can anyone help me please?
My Matrix looks like this:
and I want to calculate the following:
(0 * 0 * 4/24) + (0 * 1 * 6/24) + (0 * 2 * 3/24) + (1 * 0 * 3/24) + (1 * 1 * 4/24) + (1 * 2 * 4/24)
instead of using
__
btw: my code for the matrix
vals<- c(4/24, 6/24, 3/24, 3/24, 4/24, 4/24)
x <- c(0,1)
y <- c(0,1,2)
df <- matrix(vals, byrow = TRUE, nrow = 2, ncol = 3,
dimnames = list(x,y))
instead of calculation each step manually, I think there should be a for-loop method, but cant figure it out..
A possible solution:
c(x %*% df %*% y)
#> [1] 0.5
Another possible solution, based on outer:
sum(outer(x, y, Vectorize(\(x,y) x*y*df[x+1,y+1])))
#> [1] 0.5
x <- c(0, 1)
y <- c(0, 1, 2)
vals<- c(4/24, 6/24, 3/24, 3/24, 4/24, 4/24)
mat <- matrix(vals, byrow = TRUE, nrow = 2, ncol = 3,
dimnames = list(x,y)) ## not a data frame; don't call it "df"
There is even a better way than a for loop:
sum(tcrossprod(x, y) * mat)
#[1] 0.5
sum((x %o% y) * df)
Explanation:
x %o% y gets the outer product of vectors x and y which is:
#> [,1] [,2] [,3]
#> [1,] 0 0 0
#> [2,] 0 1 2
Since that has the same dimensions as df, you can multiply the corresponding elements and get the sum: sum((x %o% y) * df)
If you are new to R (as I am), here is the loop approach.
result = 0
for (i in 1:length(x)) {
for (j in 1:length(y)) {
result = result + x[i] * y[j] * df[i, j]
}
}
result

Vectorized R function

I have to write a vectorized R function f that takes a vector x= (x_1, . . . , x_m) and a natural number n, and returns the value f_n(x) given by:
Example:
> x = seq(-1, 3, by = 0.4)
> f(x,6) # here n=6
[1] 0.000000e+00 0.000000e+00 0.000000e+00
[4] 2.666667e-06 6.480000e-04 8.333333e-03
[7] 4.430667e-02 1.410800e-01 3.050933e-01
[10] 4.755467e-01 5.500000e-01
This is what I got:
f = function(x, n){
s = 0
for(j in 0:x)
s = s + (-1)^j*choose(n, j)*(x-j)^(n-1)
s/factorial(n-1)
}
x = seq(-1, 3, by = 0.4)
f(x,6)
Warning in 0:x: numerical expression has 11 elements: only the first used
[1] -8.333333e-03 -6.480000e-04 -2.666667e-06 2.666667e-06 6.480000e-04
[6] 8.333333e-03 4.481867e-02 1.574640e-01 4.294693e-01 9.901147e-01
[11] 2.025000e+00
Clearly it is not what it should be in the example. What did I do wrong here? TIA
EDIT: Maybe using outer and apply might help with x?
This is a slightly different way of doing this solely based on base R:
x = seq(-1, 3, by = 0.4)
n <- 6
fn <- function(x, n) {
x[x <= 0] <- 0
sapply(x, function(x) {
Reduce(function(a, b) {
a + (-1) ^ b * (factorial(n)/(factorial(b) * factorial(n-b))) * (x - b) ^ (n-1)
}, seq(0, x), init = 0) * (1/factorial(n-1))
})
}
fn(x, 6)
[1] 0.000000e+00 0.000000e+00 0.000000e+00 2.666667e-06 6.480000e-04 8.333333e-03 4.430667e-02
[8] 1.410800e-01 3.050933e-01 4.755467e-01 5.500000e-01
Try this code. It can be modified to become tidier but maybe it can solve your problem in its current form. I used both base R and purr functions for iteration instead of for loop but maybe for loop alone can do the job.
library(tidyverse)
n <- 6
x <- seq(-1, 3, by = 0.4)
x[x<= 0] <- 0
seq_fun <- function(x) seq(0, x)
d <- sapply(x, seq_fun)
fun <- function(r, t) {
sum((-1) ^ r *choose(n, r)*(r-t)^(n-1)) / factorial(n - 1)
}
as_vector(map2(d, x, fun))

Maximum Product of Spacings using R

I would like to estimate the parameter for exponential distribution using Maximum Product of Spacings (MPS). I will have to minimize:
-(1/(n + 1))*(sum of log D[i] from i = 1 to n + 1),
where D[i] = F(x[i]) - F(x[i - 1])
And the following is my R code:
n<- 10
mydata<- rexp(n, rate=2)
x<- sort(mydata)
fnn<- function(lambda,x){
for (i in 2:n){
c<- 1-exp(-lambda*x[i])
d<- 1-exp(-lambda*x[i-1])
}
s<- (1/(n-1))*sum(log(c-d))
return(-s)
}
optim(0.8, fnn, x=x)
Can someone please verify if I am doing the right thing here?
The output I obtained is far from the true value of lambda = 2.
$`par`
[1] 0.92375
$value
[1] 0.1847188
$counts
function gradient
18 NA
$convergence
[1] 0
$message
NULL
what modifications should I include?
The problem with your code is that it is rewriting c and d each time through the for loop. It also had a bug in the computation of the multiplicative constant 1/(n + 1).
Here is a corrected version. The key is to reserve memory before the loop with numeric(n - 1).
I also include a simpler version, taking advantage of R's built-in pexp.
fnn <- function(lambda, x){
n <- length(x)
c <- numeric(n - 1)
d <- numeric(n - 1)
for (i in 2:n){
c[i - 1] <- 1 - exp(-lambda*x[i])
d[i - 1] <- 1 - exp(-lambda*x[i-1])
}
s <- (1/(n + 1))*sum(log(c - d))
return(-s)
}
fnn2 <- function(lambda, x){
n <- length(x)
D <- log(pexp(x[-1], rate = lambda,) - pexp(x[-n], rate = lambda))
s <- sum(D)/(n + 1)
-s
}
set.seed(1234)
n <- 10
mydata <- rexp(n, rate = 2)
x <- sort(mydata)
opt <- optim(0.8, fnn, x = x)
opt2 <- optim(0.8, fnn2, x = x)
opt$par
#[1] 2.9225
opt2$par
#[1] 2.9225
identical(opt$par, opt2$par)
#[1] TRUE

Function: sapply in apply, removing outliers

I'm working on a function which will get rid of outliers in a given data set based on 3 sigma rule. My code is presented below. "data" is a data set to be processed.
rm.outlier <- function(data){
apply(data, 2, function(var) {
sigma3.plus <- mean(var) + 3 * sd(var)
sigma3.min <- mean(var) - 3 * sd(var)
sapply(var, function(y) {
if (y > sigma3.plus){
y <- sigma3.plus
} else if (y < sigma3.min){
y <- sigma3.min
} else {y <- y}
})
})
as.data.frame(data)
}
In order to check if the function works I wrote a short test:
set.seed(123)
a <- data.frame("var1" = rnorm(10000, 0, 1))
b <- a
sum(a$var1 > mean(a$var1) + 3 * sd(a$var1)) # number of outliers in a
As a result, I get:
[1] 12
So the variable var1 in the data frame a has 12 outliers. Next, I try to apply my function on this object:
a2 <- rm.outlier(a)
sum(b$var1 - a2$var1)
Unfortunately, it gives 0 which clearly indicates that something does not work. I have already worked out that the implementation of sapply is correct so there must be a mistake in my apply. Any help would be appreciated.
If runtime is important for you, you might consider another approach. You could vectorize this filtering, e.g. by using pmin and pmax which is equally readable and > 15x times faster. If you like it a little bit more complex you could use findInterval and get even more speed:
rm.outlier2 <- function(x) {
## calculate -3/3 * sigma borders
s <- mean(x) + c(-3, 3) * sd(x)
pmin(pmax(x, s[1]), s[2])
}
rm.outlier3 <- function(x) {
## calculate -3/3 * sigma borders
s <- mean(x) + c(-3, 3) * sd(x)
## sorts x into intervals 0 == left of s[1], 2 == right of s[2], 1
## between both s
i <- findInterval(x, s)
## which values are left/right of the interval
j <- which(i != 1L)
## add a value between s to directly use output of findInterval for subsetting
s2 <- c(s[1], 0, s[2])
## replace all values that are left/right of the interval
x[j] <- s2[i[j] + 1L]
x
}
Benchmarking the stuff:
## slightly modified OP version
rm.outlier <- function(x) {
sigma3 <- mean(x) + c(-3,3) * sd(x)
sapply(x, function(y) {
if (y > sigma3[2]){
y <- sigma3[2]
} else if (y < sigma3[1]){
y <- sigma3[1]
} else {y <- y}
})
}
set.seed(123)
a <- rnorm(10000, 0, 1)
# check output
all.equal(rm.outlier(a), rm.outlier2(a))
all.equal(rm.outlier2(a), rm.outlier3(a))
library("rbenchmark")
benchmark(rm.outlier(a), rm.outlier2(a), rm.outlier3(a),
order = "relative",
columns = c("test", "replications", "elapsed", "relative"))
# test replications elapsed relative
#3 rm.outlier3(a) 100 0.028 1.000
#2 rm.outlier2(a) 100 0.102 3.643
#1 rm.outlier(a) 100 1.825 65.179
It seems like you just forgot to assign your results of the apply function to a new dataframe. (Compare the 3rd line with your code)
rm.outlier <- function(data){
# Assign the result to a new dataframe
data_new <- apply(data, 2, function(var) {
sigma3.plus <- mean(var) + 3 * sd(var)
sigma3.min <- mean(var) - 3 * sd(var)
sapply(var, function(y) {
if (y > sigma3.plus){
y <- sigma3.plus
} else if (y < sigma3.min){
y <- sigma3.min
} else {y <- y}
})
})
# Print the new dataframe
as.data.frame(data_new)
}
set.seed(123)
a <- data.frame("var1" = rnorm(10000, 0, 1))
sum(a$var1 > mean(a$var1) + 3 * sd(a$var1)) # number of too big outliers
# 15
sum(a$var1 < mean(a$var1) - 3 * sd(a$var1)) # number of too small outliers
# 13
# Overall 28 outliers
# Check the function for the number of outliers
a2 <- rm.outlier(a)
sum(a2$var1 == a$var1) - length(a$var1)

How to define a flexible 'function expression' in R

Is it possible to write a flexible function expression?
I want to use input arguments to control the expression of function.
For example
input arg -> function
c(1,1) -> func1 = function(x) x+1
c(1,3,2) -> func2 = function(x) x^2+3*x+2
c(6,8,-1) -> func3 = function(x) 6*x^2+8*x-1
makepoly <- function(b)
{
p <- rev(seq_along(b) - 1)
function(x)
{
xp <- outer(x, p, '^')
rowSums(xp * rep(b, each=length(x)))
}
}
# x^2 + 2x + 3
f <- makepoly(1:3)
f(0:4)
[1] 3 6 11 18 27
Here is my take on this task
create_poly <- function(coef)
paste(rev(coef),
paste("x", seq_along(coef) - 1, sep = "^"),
sep = "*", collapse = " + ")
make_polyfun <- function(input) {
myfun <- paste("function(x)", create_poly(input))
eval(parse(text = myfun))
}
With the example the OP gave we have :
make_polyfun(c(1, 1))
## function(x) 1*x^0 + 1*x^1
## <environment: 0x243a540>
make_polyfun(c(1, 3, 2))
## function(x) 2*x^0 + 3*x^1 + 1*x^2
## <environment: 0x1bd46e0>
make_polyfun(c(6, 8, 1))
## function(x) 1*x^0 + 8*x^1 + 6*x^2
## <environment: 0x22a59c0>
You can use polynom
library(polynom)
as.polynomial(c(2,3,1))
2 + 3*x + x^2
as.polynomial(c(6,8,1)
1 + 8*x + 6*x^2
EDIT you can of course coerce the result to a function using the genericas.function.polynomial. better here you can use ,as.polylist` to create many polynomials given a list of coefficients lists. For example:
lapply(as.polylist(list(c(2,3,1),c(6,8,1),c(6,8,-1))),
as.function)
[[1]]
function (x)
{
w <- 0
w <- 1 + x * w
w <- 3 + x * w
w <- 2 + x * w
w
}
<environment: 0x00000000113bd778>
[[2]]
function (x)
{
w <- 0
w <- 1 + x * w
w <- 8 + x * w
w <- 6 + x * w
w
}
<environment: 0x0000000011524168>
[[3]]
function (x)
{
w <- 0
w <- -1 + x * w
w <- 8 + x * w
w <- 6 + x * w
w
}
<environment: 0x0000000011527f28>
It's not clear how general you want to be from OP. For the particular case of polynomials, you can do:
f = function(x, coeffs) {
sum(outer(x, seq_along(coeffs) - 1, `^`) * coeffs)
}
f(2, c(1,2,3)) # 1 + 2*x + 3*x^2, with x = 2
#[1] 17
I read this as the desire to make functions and I think the agstudy/eddi responses would probably do this, but I thought trying it from scratch might be instructive:
poly.maker <- function(coefs) { func <- function(x){} #empty func in x
body(func) <- parse(text= paste( seq_along(coefs),"*x^",
(length(coefs)-1):0,collapse="+" ) )
return(func) }
func2 <- poly.maker(c(1,2,3)) # return a function
func2(3) # now test it out
#[1] 18
Note I needed to swap the order to agree with the OP request, which I only noticed after getting different results than #dickoa. This seems less clunky:
poly.make2 <- function(coefs) { func <- function(x){}
body(func) <- bquote(sum(.(coefs)*x^.( (length(coefs)-1):0 ) ) )
return(func) }
func <- poly.make2(c(1,2,5))
func
#function (x)
#sum(c(1, 2, 5) * x^c(2L, 1L, 0L))
#<environment: 0x29023d508>
func(3)
#[1] 20
One liner:
polymaker2 <- function(coefs)
{
eval(parse(text=paste0( "function(x) sum(x^(",length(coefs)-1,":0) * ",capture.output(dput(coefs)),")" )))
}
Vectorized form:
polymaker3 <- function(coefs)
{
eval(parse(text=paste0( "function(x) colSums(t(outer(x, ",length(coefs)-1,":0, `^`))*",capture.output(dput(coefs)),")" )))
}

Resources