How to avoid coding first iteration outside while loop - r

I frequently have problems that lend themselves to while loops, but come out ugly, and I'm here to ask if there is an elegant solution or if all possible solutions are ugly. Is there?
Here's a simplified example: suppose we are trying to find the minimum value of a function f <- function(x){x^2}, as well as the location at which it is found. Suppose we elect to find the minimum by making an initial guess x and evaluating f(x). Then we evaluate f(x-0.1), and f(x+0.1). If either of these values is lower than f(x), our new guess is the argmin. We repeat until such shifts no longer decrease the value.
The best solution I have come up with is to run part of the first iteration of the algorithm outside of the loop. But this requires me to duplicate code from the loop, namely the section of code enclosed with !!!!!!!.
# function to minimize
f <- function(x){x^2}
# initial guess
x.current <- 1
f.current <- f(x.current)
# !!!!!!!!!!!!
# part of first iteration
x.guess <- c(x.current - 0.1, x.current + 0.1)
f.guess <- sapply(x.guess, f)
best.ind <- which.min(f.guess)
x.new <- x.guess[best.ind]
f.new <- f.guess[best.ind]
# !!!!!!!!!!!!
# part of first iteration and later iterations
while (f.new < f.current){
x.current <- x.new
f.current <- f.new
x.guess <- c(x.current - 0.1, x.current + 0.1)
f.guess <- sapply(x.guess, f)
best.ind <- which.min(f.guess)
x.new <- x.guess[best.ind]
f.new <- f.guess[best.ind]
}
print("best guess = ")
print(x.current)
Is there a "nicer" way of doing this?

There are a variety of ways to deal with this situation. Whether one is 'ugly' or 'pretty' is a matter of opinion, and therefore off topic for StackOverflow. Nonetheless, we can make some generalisations about some different options:
Option 1: wrap repetitive lines in their own function
A common rule of thumb is that one should avoid repeating code segments. Whenever you see a sequence of lines repeated at various places in your program, one should strongly consider placing those lines into their own function and calling this function repeatedly.
This aids in the readability of the overall code by making it more succinct, and requiring a maintainer to only read through and understand that section once.
Perhaps more importantly, it also aids in maintainability of the code because any changes to that snippet will automatically propagate through the whole program. Having to hunt down and alter every instance of a repeated code snippet is not only frustrating when it comes to editing code, but it is also a potentially error-prone procedure.
Here's one way you might apply this principle here, using an additional trick of placing the function call inside the loop condition expression, so that we only need to call it once here (although the code inside a while loop is not guaranteeed to execute, the code in its condition must always be executed at least once:
# initial guess
x <- 1
fx <- f(x)
find.new = function(x){
x.new <- c(x - 0.1, x + 0.1)
f.new <- sapply(x.new, f)
best.ind <- which.min(f.new)
x.new <- x.new[best.ind]
f.new <- f.new[best.ind]
return(list(x=x.new, fx=f.new))
}
while ((new <- find.new(x))$fx < fx){
x <- new$x
fx <- new$fx
}
2 use a repeat loop instead
If, as in this case, there is some code inside the loop that we would always want to execute at least onse, then consider using a repeat loop instead of while. We can then test for the exit condition to either update values or to break from the loop. If the repeated code snippet in your original does not need to execute anywhere else in your program, this can be more concise than wrapping it in its own function
repeat {
x.new <- c(x - 0.1, x + 0.1)
f.new <- sapply(x.new, f)
best.ind <- which.min(f.new)
x.new <- x.new[best.ind]
f.new <- f.new[best.ind]
if (f.new < fx) {
x <- x.new
fx <- f.new
} else {
break
}
}

As pointed out by dww there are several options. There is a third one which initializes the variables which are referenced in the first iteration of the loop and in the test condition of the loop appropriately:
# function to minimize
f <- function(x){x^2}
# initialize values
x.new <- 1
f.new <- f(x.new)
f.current <- f.new + 0.1 # just to fulfill test condition
# part of first iteration and later iterations
while (f.new < f.current){
x.current <- x.new
f.current <- f.new
x.guess <- c(x.current - 0.1, x.current + 0.1)
f.guess <- sapply(x.guess, f)
best.ind <- which.min(f.guess)
x.new <- x.guess[best.ind]
f.new <- f.guess[best.ind]
}
print("best guess = ")
print(x.current)

Related

Prioblems with the "Deriv" R package

I am having two related problems with the Deriv() function from the Deriv package (from CRAN).
Problem (1): I believe that the code in the rule for differentiating dbinom() w.r.t "prob" is incorrect. Evidence for this (and my proposed correction) is shown in the following code. I would have preferred to attach text files containing the code, but as far as I can see there is no way to do this.
#
# Script demo01.R.
#
library(Deriv)
# Plot dbinom as a function of probabiity.
plot(function(p){dbinom(3,8,p)},from=0,to=1,xlab="parameter \"prob\"",
ylab="binomial probability",main="dbinom")
abline(v=3/8,col="red")
readline("Go? ")
# Plot the derivative of dbinom, with respect to prob, calculated by
# Deriv(), as a function of probability.
Ddb <- Deriv(dbinom,"prob")
plot(function(p){Ddb(3,8,p)},from=0,to=1,xlab="parameter \"prob\"",
ylab="",main="derivative of dbinom")
readline("Go? ")
# Replace what I believe to be incorrect code for the rule for
# differentiating dbinom() with what I believe to be correct code.
# This rule should, strictly speaking, be placed in a new environment
# rather than over-writing the existing rule, but this seems to
# break down when second derivatives are taken.
drule[["dbinom"]] <- alist(x=NULL,size=NULL,prob={
.e1 <- 1 - prob
.e2 <- size - 1
if (x == 0)
-(x * .e1^(x - 1))
else if (x == size)
prob^.e2 * size
else size*(dbinom(x-1,.e2,prob) - dbinom(x,.e2,prob)) *
(if (log) dbinom(x, size, prob) else 1)
})
# Plot the derivative of dbinom, with respect to prob, calculated by
# the corrected version of Deriv(), as a function of probability.
Ddb <- Deriv(dbinom,"prob")
plot(function(p){Ddb(3,8,p)},from=0,to=1,xlab="parameter \"prob\"",
ylab="",main="derivative of dbinom, corrected")
abline(v=3/8,col="red")
abline(h=0,col="blue")
You will observe that the derivative of dbinom()
should be positive for prob < 3/8 and negative for prob > 3/8. My corrected version has this property, whereas the derivative produced by the uncorrected version is negative everywhere.
Can anyone confirm that I am right about about there being a bug in the Deriv package? (I.e. that I am not making some sort of stupid mistake?)
Problem (2). I "crosschecked" the calculations performed by Deriv() by applying this function to a "roll-your-own" version of dbinom() for which no special rule is needed. I also applied the (corrected version) of Deriv() to dbinom(). The code that I used is as follows:
#
# Script demo02.
#
library(Deriv)
# Replace what I believe to be incorrect code for the rule for
# differentiating dbinom() with what I believe to be correct code.
# This rule should, strictly speaking, be placed in a new environment
# rather than over-writing the existing rule, but this seems to
# break down when second derivatives are taken.
drule[["dbinom"]] <- alist(x=NULL,size=NULL,prob={
.e1 <- 1 - prob
.e2 <- size - 1
if (x == 0)
-(x * .e1^(x - 1))
else if (x == size)
prob^.e2 * size
else size*(dbinom(x-1,.e2,prob) - dbinom(x,.e2,prob)) *
(if (log) dbinom(x, size, prob) else 1)
},log=NULL)
fooB1 <- function(x,prob,size) {
dbinom(x,size,prob)
}
fooB2 <- function(x,prob,size) {
choose(size,x)*prob^x*(1-prob)^(size-x)
}
dfooB1 <- Deriv(fooB1,"prob")
dfooB2 <- Deriv(fooB2,"prob")
d2fooB1 <- Deriv(fooB1,"prob",nderiv=2)
d2fooB2 <- Deriv(fooB2,"prob",nderiv=2)
vB1 <- fooB1(x=3,prob=0.6,size=8)
vB2 <- fooB2(x=3,prob=0.6,size=8)
dB1 <- dfooB1(x=3,prob=0.6,size=8)
dB2 <- dfooB2(x=3,prob=0.6,size=8)
d2B1 <- d2fooB1(x=3,prob=0.6,size=8)
d2B2 <- d2fooB2(x=3,prob=0.6,size=8)
If you run this code you will see that the function values (vB1 and vB2) agree, both having the value 0.123863. Likewise the first derivative values dB1 and dB2 agree: -0.9289728.
However the second derivatives disagree. The value of d2B1 is 1.769472, whereas the value of d2B2 is 2.064384. I have no idea which (if either) of these answers is correct.
Something (the chain rule?) is not working as it should.
Is there any action that I can take to resolve this discrepancy?

Speed of Daisy Function

I'm working on improving the speed of a function (for a dissimilarity measure) I'm writing which is quite similar mathematically to the Euclidean distance function. However, when I time my function compared to that implemented in the daisy function from the cluster package, I find quite a significant difference in speed, with daisy performing much better. Given that (I'm assuming) a dissimilarity measure would require O(n x p) time due to the need to compare each object to itself over all variables (where n is number of objects and p is number of variables), I find it difficult to understand how the daisy function performs so well (near constant time, from the few experiments I've done) relative to my simple and direct implementation. I present the code I have used both to implement and test below. I have tried looking through the r source code for the implementation of the daisy function, but I found it difficult to understand. I found no nested for loop. Any help with understanding why this function performs so fast and how I could possibly modify my code to have similar speed would be very highly appreciated.
euclidean <- function (df){
no_obj <- nrow(df)
dist <- array(0, dim = c(no_obj, no_obj))
for (i in 1:no_obj){
for (j in 1:no_obj){
dist_v <- 0
if(i != j){
for (v in 1:ncol(df)){
dist_v <- dist_v + sqrt((df[i,v] - df[j,v])^2)
}
}
dist[i,j] <- dist_v
}
}
return(dist)
}
data("iris")
tic <- Sys.time()
dst <- euclidean(iris[,1:4])
time <- difftime(Sys.time(), tic, units = "secs")[[1]]
print(paste("Time taken [Euclidean]: ", time))
tic <- Sys.time()
dst <- daisy(iris[,1:4])
time <- difftime(Sys.time(), tic, units = "secs")[[1]]
print(paste("Time taken [Daisy]: ", time))
one option:
euclidean3 <- function(df) {
require(data.table)
n <- nrow(df)
i <- CJ(1:n, 1:n) # generate all row combinations
dl <- sapply(df, function(x) sqrt((x[i[[1]]] - x[i[[2]]])^2)) # loop over columns
dv <- rowSums(dl) # sum values of columns
d <- matrix(dv, n, n) # fill in matrix
d
}
dst3 <- euclidean3(iris[,1:4])
all.equal(euclidean(iris[,1:4]), dst3) # TRUE
[1] "Time taken [Euclidean3]: 0.008"
[1] "Time taken [Daisy]: 0.002"
Largest bottleneck in your code is selecting data.frame elements in loop (df[j,v])). Maybe changing it to matrix also could improver speed. I believe there could be more performant approach on stackoverflow, you just need to search by correct keywords...

I am beginner in R and I'm trying to solve a system of equations but when i run i get error in R [duplicate]

This question already has an answer here:
Simple for loop in R producing "replacement has length zero" in R
(1 answer)
Closed 4 years ago.
# my error : Error in F[1] <- n/(X[0]) - sum(log(1 + Y^exp(X[1] + X[2] * x))) : replacement has length zero
set.seed(16)
#Inverse Transformation on CDF
n=100
SimRRR.f <- function(100, lambda=1,tau)) {
x= rnorm(100,0,1)
tau= exp(-1-x)
u=runif(100)
y= (1/(u^(1/lambda)-1))^(1/tau)
y
}
Y<-((1/u)-1)^exp(-1-x)
# MLE for Simple Linear Regresion
# System of equations
library(rootSolve)
library(nleqslv)
model <- function(X){
F <- numeric(length(X))
F[1] <- n/(X[0])-sum(log(1+Y^exp(X[1]+X[2]*x)))
F[2] <- 2*n -(X[0]+1)*sum(exp(X[1]+X[2]*x))*Y^( exp(X[1]+X[2]*x))*log(Y)/(1+ Y^( exp(X[1]+X[2]*x)))
F[3] <- sum(x) + sum(x*log(Y))*exp(X[1]+X[2]*x) -(X[0]+1)*X[1]*sum(exp(X[1]+X[2]*x)*Y^(exp(X[1]+X[2]*x)*log(Y)))/(1+ Y^( exp(X[1]+X[2]*x)))
# Solution
F
}
startx <- c(0.5,3,1) # start the answer search here
answers<-as.data.frame(nleqslv(startx,model))
The problem is that you define x, u, tau and y inside the SimRRR function, but are trying to define Y in terms of them outside the function.
Using a function, you give it input, and you get back output. All the other variables defined in the course of the function doing its job go away at the end. As it stands, Y should be a series of NAs (unless you defined the above variables in the global environment as you were working on your function...)
Try the following functions, see if they do the job:
# I usually put all my library calls together at the beginning of the script.
library(rootSolve)
library(nleqslv)
x = rnorm(n,0,1) # see below for why this is pulled out.
SimRRR.f <- function(x, lambda=1,tau)) { # 100 can't be by itself in the function call. everything in there needs to be attached to a variable.
n <- length(x)
tau= exp(-1-x)
u=runif(n)
y= (1/(u^(1/lambda)-1))^(1/tau)
y
}
Y_sim = SimRRR.f(n = 100, lambda = 1, tau = 1) # pick the right tau, it's never defined here.
Your second function has more issues. Namely, it relies on x, which is not defined anywhere that can be found. Either you need x from the previous function, or you really meant X. I'm going to assume you do need the values of x, since X is only of length 3. This is why I pulled it out of the last function call - we need it now.
[Update]
It's also been pointed out in the comments that the indexing here is wrong. I didn't catch that previously (and the F elements are defined correctly). I think I've fixed the indexing issues too now:
model <- function(X, Y, x){ # If you use x and Y in the function, define them here.
n <- length(x)
F <- numeric(length(X))
F[1] <- n/(X[1])-sum(log(1+Y^exp(X[2]+X[3]*x)))
F[2] <- 2*n -(X[1]+1)*sum(exp(X[2]+X[3]*x))*Y^( exp(X[2]+X[3]*x))*log(Y)/(1+ Y^( exp(X[2]+X[3]*x)))
F[3] <- sum(x) + sum(x*log(Y))*exp(X[2]+X[3]*x) -(X[1]+1)*X[2]*sum(exp(X[2]+X[3]*x)*Y^(exp(X[2]+X[3]*x)*log(Y)))/(1+ Y^( exp(X[2]+X[3]*x)))
# Solution
F
}
I'm not familiar with the nleqslv package, but unless there is a method defined to convert it to a data frame, that might not go so well. I'd make sure everything else is working before the conversion.
startx <- c(0.5,3,1) # start the answer search here
answers <- nleqslv(startx,model, Y = Y_sim, x = x)
answer_df <- as.data.frame(answers)

Exponential distribution in R

I want to simulate some data from an exp(1) distribution but they have to be > 0.5 .so i used a while loop ,but it does not seem to work as i would like to .Thanks in advance for your responses !
x1<-c()
w<-rexp(1)
while (length(x1) < 100) {
if (w > 0.5) {
x1<- w }
else {
w<-rexp(1)
}
}
1) The code in the question has these problems:
we need a new random variable on each iteration but it only generates new random variables if the if condition is FALSE
x1 is repeatedly overwritten rather than extended
although while could be used repeat seems better since having the test at the end is a better fit than the test at the beginning
We can fix this up like this:
x1 <- c()
repeat {
w <- rexp(1)
if (w > 0.5) {
x1 <- c(x1, w)
if (length(x1) == 100) break
}
}
1a) A variation would be the following. Note that an if whose condition is FALSE evaluates to NULL if there is no else leg so if the condition is FALSE on the line marked ## then nothing is concatenated to x1.
x1 <- c()
repeat {
w <- rexp(1)
x1 <- c(x1, if (w > 0.5) w) ##
if (length(x1) == 100) break
}
2) Alternately, this generates 200 exponential random variables keeping only those greater than 0.5. If fewer than 100 are generated then repeat. At the end it takes the first 100 from the last batch generated. We have chosen 200 to be sufficiently large that on most runs only one iteration of the loop will be needed.
repeat {
r <- rexp(200)
r <- r[r > 0.5]
if (length(r) >= 100) break
}
r <- head(r, 100)
Alternative (2) is actually faster than (1) or (1a) because it is more highly vectorized. This is despite it throwing away more exponential random variables than the other solutions.
I would advise against a while (or any other accept/reject) loop; instead use the methods from truncdist:
# Sample 1000 observations from a truncated exponential
library(truncdist);
x <- rtrunc(1000, spec = "exp", a = 0.5);
# Plot
library(ggplot2);
ggplot(data.frame(x = x), aes(x)) + geom_histogram(bins = 50) + xlim(0, 10);
It's also fairly straightforward to implement a sampler using inverse transform sampling to draw samples from a truncated exponential distribution that avoids rejecting samples in a loop. This will be a more efficient method than any accept/reject-based sampling method, and works particularly well in your case, since there exists a closed form of the truncated exponential cdf.
See for example this post for more details.

Solve non-linear system of equations R

I try to solve a set of non-linear systems of equation using the nleqslv function in R. Unfortunately I run into troubles guessing the right initial values to make the function run sucessfully. I have a vector with values between 0 and 1, which are called c(t). They should satisfy the following equation
c(t)=A*(exp(-mt)+exp(-m(1024-t)))+B^2
Using three subsequent values of t I aim to determine the coefficients A,B,m using the following code
library(nleqslv)
C10 <- c(1.000000e+00,9.754920e-01,9.547681e-01,9.359057e-01,9.182586e-01,9.014674e-01)
system_size <- 1024
for(i in 2:5)
{
C <- c(C10[i-1],C10[i],C10[i+1],i-2)
#function
target <- function(Coeffs){
y <- numeric(3)
y[1] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]-1))+exp(-Coeffs[2]*(system_size-(C[4]-1))))+Coeffs[3]^2-C[1]
y[2] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]))+exp(-Coeffs[2]*(system_size-(C[4]))))+Coeffs[3]^2-C[2]
y[3] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]+1))+exp(-Coeffs[2]*(system_size-(C[4]+1))))+Coeffs[3]^2-C[3]
y
}
init <- c(0.001,0.01,0)
sol <- nleqslv(init, target,control=list(btol=.01), method="Broyden")
}
The used initial values reflect what I get when plotting the associated values c(t). Nonetheless the generated output sol gives
chr "Jacobian is ill-conditioned (1/condition=9.0e-18) (see allowSingular option)"
Any idea what is going wrong and how to solve this?
OP edit: Modified Code to have minimal working example: added first few values for C10, adjusted loop and added value for system_size
With your addition of some data for C10 the example runs perfectly ok if one takes into account that the loop should take account of length(C10).
Like this (with some changes; for why see below):
library(nleqslv)
C10 <- c(1.000000e+00,9.754920e-01,9.547681e-01,9.359057e-01,9.182586e-01,9.014674e-01)
system_size <- 1024
target <- function(Coeffs){
y <- numeric(3)
y[1] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]-1))+exp(-Coeffs[2]*(system_size-(C[4]-1))))+Coeffs[3]^2-C[1]
y[2] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]))+exp(-Coeffs[2]*(system_size-(C[4]))))+Coeffs[3]^2-C[2]
y[3] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]+1))+exp(-Coeffs[2]*(system_size-(C[4]+1))))+Coeffs[3]^2-C[3]
y
}
init <- 50*c(0.001,0.01,0)
for(i in 2:min(length(C10)-1,(system_size/2)))
{
C <- c(C10[i-1],C10[i],C10[i+1],i-2)
#function
target <- function(Coeffs){
y <- numeric(3)
y[1] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]-1))+exp(-Coeffs[2]*(system_size-(C[4]-1))))+Coeffs[3]^2-C[1]
y[2] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]))+exp(-Coeffs[2]*(system_size-(C[4]))))+Coeffs[3]^2-C[2]
y[3] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]+1))+exp(-Coeffs[2]*(system_size-(C[4]+1))))+Coeffs[3]^2-C[3]
y
}
cat("i=",i,"init=",init, "target(init)=",target(init),"\n")
sol <- nleqslv(init, target,control=list(btol=.01), method="Broyden")
print(sol)
}
With your initial starting values the model doesn't solve and gives the error message you mention. I have changed the value of init by increasing the value. And then a solution is found up-to i=5. Larger values with the given C10 won't run since within the loop C10[i+1] is referenced (and it doesn't exist).
I have inserted a cat statement before the call of nleqslv and a print(sol) after the function call so that one can at least see what's going on and if a solution is actually found.
You do not need to specify method="Broyden" since it is the default.
You should test sol$termcd in the for loop end exit if an error occurs.
With scripts like this always print stuff inside the loop!
Mislav was correct: starting values can be totally wrong.
Even if starting values are ok the algorithms used can fail. That's why the package provides function testnslv and searchZeros.
I did some experiments (not shown here) with testnslv and the conclusion is that method="Newton" is a failure. The dogleg global strategies always seem to work. The linesearch strategies don't always work.

Resources