R: Storing Loop Result in a Vector - r

I'm trying to run a loop that stores results in a vector. But I also need to increase the counter across a predetermined vector for the stored calculation to run properly. I'm stuck on two parts: (1) increasing the counter, and (2) storing the result of the loop in a vector.
I'm new to loops so bear with the most likely incorrect syntax below; here's what I'm working with:
x <- c(.01,.05,.10,.20,.25) # observed defect rates
for(i in x) {
j <- 1
if(x < 1){
atmost2[] <- dbinom(0,size=10,prob=x[[j]])+
dbinom(1,size=10,prob=x[[j]])+
dbinom(2,size=10,prob=x[[j]]) &&
j <- j + 1
}
}
atmost2
Essentially I'd like to store the result in a new vector, atmost2, with each successive loop running across the vector values in x by increasing j; j should increase to change the prob parameter in dbinom from the predetermined vector values in x.
Can anyone help out?

A few things:
juljo is correct to initialize the vector before a loop, and they made some other corrections, but I think their code only works if you have already established:
j <- 1
Without that, juljo's code breaks.
Also, your code doesn't need the '&&' to work. Just put j<-j+1 on a new line, like this (Using julgo's code)
j <- 1
x <- c(.01,.05,.10,.20,.25) # observed defect rates
atmost2 <- as.numeric(1:length(x)) # this initializes the vector to a predetermined length which may help with very large loops
for(i in 1:length(x)) {
if(x < 1){
atmost2[i] <- dbinom(0,size=10,prob=x[j])+ # note that the double brackets are gone
dbinom(1,size=10,prob=x[j])+
dbinom(2,size=10,prob=x[j])
}
j <- j + 1 # I think you want j to increment outside the if statement
}
atmost2
This code does 'something' but there are a few warnings and I'm not sure what you are trying to do.
You could also skip the adding of the dbinoms and instead to this:
j <- 1
x <- c(.01,.05,.10,.20,.25) # observed defect rates
atmost2 <- as.numeric(1:length(x)) # this initializes the vector to a predetermined length which may help with very large loops
for(i in 1:length(x)) {
if(x < 1){
atmost2[i] <- sum(dbinom( 0:2 , size=10,prob=x[j])) #dbinom will give a vector that can be summed
}
j <- j + 1 # I think you want j to increment outside the if statement
}
atmost2
But I think using the j iterator might be habit from other programming languages. Notice the same out put using a loop but without j:
x <- c(.01,.05,.10,.20,.25) # observed defect rates
atmost2 <- as.numeric(1:length(x)) # this initializes the vector to a predetermined length which may help with very large loops
for(i in 1:length(x)) {
if(x < 1){
atmost2[i] <- sum(dbinom(0:2,size=10,prob=x[i]))
}
}
atmost2
These all produce the same output:
> atmost2
[1] 0.9998862 0.9884964 0.9298092 0.6777995 0.5255928
But I have follow up questions:
Should atmost2 be the same length as x?
Are you using the values in x as probabilities? So, atmost2 is a sum of dbinom probabilities based on the value of x[i]?
Does it have to be a loop? R uses vectors very well, so the apply functions may be helpful. You might find lapply to be of use here.
?apply might start you off while
?lapply will give descriptions of the other apply functions.
So your code may look like this
x <- c(.01, .05, .10, .20, .25)
atmost2 <- as.numeric(1:length(x))
atmost2 <- lapply(x, function(x) sum(dbinom( 0:2 , size = 10, prob = x)))
atmost2 # this is a list, not a vector
the lapply function reads like this:
apply to items in a list, 'x', a function.
In this case, the function is an anonymous function "sum(dbinom....)"
So, apply to each value of x the function sum(dbinom...) and return a list.
Basically, it does the loop for you. And often times faster than a for-loop (in R).
If you need atmost2 to not be a list and instead a vector, you can:
unlist(atmost2)
> unlist(atmost2)
[1] 0.9998862 0.9884964 0.9298092 0.6777995 0.5255928
edit based on the reminder of Rui
Using sapply, everything else is the same but the output is indeed a vector.
x <- c(.01, .05, .10, .20, .25)
atmost2 <- as.numeric(1:length(x))
atmost2 <- sapply(x, function(x) sum(dbinom( 0:2 , size = 10, prob = x)))
atmost2 # this is a vector

How about calling elements like this:
x <- c(.01,.05,.10,.20,.25) # observed defect rates
atmost2 <- numeric() # Initialize vector before filling it in the loop
for(i in 1:length(x)) {
if(x[i] < 1){
atmost2[i] <- dbinom(0,size=10,prob=x[i])+
dbinom(1,size=10,prob=x[i])+
dbinom(2,size=10,prob=x[i])
}
}
atmost2

Related

While loop that stores values in a vector and stops when a value is already in the vector [R Programming]

I have a function, say fun(x), this function calculates a value and returns it. Then, using the returned value, run the function fun(x) with that value. I would like to code a while loop that uses this function, to generate values and store them in a vector, until the generated value from the function has already appeared in the vector.
This is what I have attempted.
x <-1 #initial value to run the function with
vec <-numeric(100) #create an empty vector to store the values
k <- 0 # have a counter for the vector position
while((fun(x) %in% vec) != TRUE){ #this while loop with run until the value from the function is already in the vector
k<- k+ 1 #increase counter
vec[k] <- fun(x) #run the function, store that value
x <- vec[k] #set x as the stored value
}
I cannot seem to figure out how to code this properly. Any help is appreciated
Something like this? Obviously sample() will return different numbers in the while statement than in the loop, but I assume your function isn't random?
sample(1:10,1)
vec <- c() ## empty vector
x=10
while(!sample(1:x,1) %in% vec){
x=sample(1:x,1)
vec <- c(vec,x)
}
Here is a way. It calls the function only once per iteration, saving its value in an auxiliary variable y. There is also a stop condition when the vector is full.
The function fun is an example meant for tests only returning one Poisson random number.
I have changed the starting value to x <- 10.
fun <- function(x) rpois(1, x)
x <- 10 # initial value to run the function with
n <- 100L # results vector length
vec <- numeric(n) # create an empty vector to store the values
k <- 0L # have a counter for the vector position
while(!((y <- fun(x)) %in% vec) && k < n){
k <- k + 1L
vec[k] <- y
x <- y
}
vec

Understanding Breakpoint function: how for loops work inside functions

I have the following exercise to be solved in R. Under the exercise, there is a hint towards the solution.
Exercise: If there are no ties in the data set, the function above will produce breakpoints with h observations in the interval between two consecutive breakpoints (except the last two perhaps). If there are ties, the function will by construction return unique breakpoints, but there may be more than h observations in some intervals.
Hint:
my_breaks <-function(x, h = 5) {
x <-sort(x)
breaks <- xb <- x[1]
k <- 1
for(i in seq_along(x)[-1])
{if(k<h)
{k <- k+1}
else{
if(xb<x[i-1]&&x[i-1]<x[i])
{xb <- x[i-1]
breaks <-c(breaks, xb)
k <- 1
}
}
}
However, I am having a hard time understanding the above function particularly the following lines
for(i in seq_along(x)[-1])
{if(k<h)
{k <- k+1}
Question:
How is the for loop supposed to act in k if k is previously defined as 1 and i is different than k? How are the breakpoints chosen according to the h=5 gap if the for loop is not acting on x? Can someone explain to me how this function works?
Thanks in advance!
First, note that your example is incomplete. The return value and the final brace are missing there. Here is the correct version.
my_breaks <-function(x, h = 5) {
x <- sort(x)
breaks <- xb <- x[1]
k <- 1
for(i in seq_along(x)[-1]){
if(k<h) {
k <- k+1
} else {
if(xb<x[i-1]&&x[i-1]<x[i]){
xb <- x[i-1]
breaks <-c(breaks, xb)
k <- 1
}
}
}
breaks
}
Let's check if it works.
my_breaks(c(1,1,1:5,8:10), 2)
#[1] 1 2 4 8
my_breaks(c(1,1,1:5,8:10), 5)
#[1] 1 3
As you can see, everything is fine. And what is seq_along(x)[-1]? We could write this equation as 2:length(x). So the for loop goes through each element of the vector x in sequence, skipping the first element.
What is the k variable for? It counts the distance to take into account the h parameter.

Trying to understand how some function works

I was given a task to write a function, which I name: my_mode_k.
The input is consisted of two variables:
(x, k)
as x, is a vector of natural numbers with the length of n. the greatest object of x can be k, given that k < n.
my_mode_k output is the highest frequency object of x. if there's more then one object in the vector that are common in x the same number of times - then the function will output the minimum object between them.
for example:
my_mode_k(x = c(1, 1, 2, 3, 3) , k =3)
1
This is code I wrote:
my_mode_k <- function(x, k){
n <- length(x)
x_lemma <- rep(0, k)
for(i in 1:n){
x_lemma[i] < x_lemma[i] +1
}
x_lem2 <- 1
for( j in 2:k){
if(x_lemma[x_lem2] < x_lemma[j]){
x_lem2 <- j
}
}
x_lem2
}
which isn't working properly.
for example:
my_mode_k(x = c(2,3,4,3,2,2,5,5,5,5,5,5,5,5), k=5)
[1] 1
as the function is supposed to return 5.
I don't understand why and what is the intuition to have in order to even know if a function is working properly (It took me some time to realize that it's not executing the needed task) - so I could fix the mistake in it.
Here are a few steps on how you can achieve this.
k <- 5
input <- c(2,3,4,3,3,3,3,3,3,3,2,2,5,5,5,5,5,5,5,5)
# Calculate frequencies of elements.
tbl <- table(input[input <= k])
# Find which is max. Notice that it returns the minimum of there is a tie.
tbl.max <- which.max(tbl)
# Find which value is your result.
names(tbl.max)
input <- c(2,2,3,3,3,5,5,5)
names(which.max(table(input[input <= k])))
# 3
input <- c(2,2,5,5,5,3,3,3)
names(which.max(table(input[input <= k])))
# 3

For-Loop in R with if-else: How to save the output

I am trying to save the output of the code below. I know "print" is the problem, but I do not know what works instead.
I generally wonder if there is not another way instead of the for-loop: For each value in the vector (x), I want to draw a new random number (here with runif) and match it to a given value (here for example 0.5). Depending on the result, a new value for x should be stored in a vector x2 (similar to the if-else example below). Waiving the for-loop, I could not find a way to always draw a new random number for each value in vector x.
I would be very grateful for any help!
x <- c(2,2,2,3,3,3)
for(i in x){
if(runif(1) <= 0.5){
print(i + 1)
} else {
print(i)
}
}
Or you could use lapply, then you don't have to modify an object outside your loop each step.
x <- c(2,2,2,3,3,3)
x2 <- unlist(lapply(x, function(x){
if(runif(1) <= 0.5) return(x +1)
return(x)
}))
x2
Try this code:
x <- c(2,2,2,3,3,3)
x2<-NULL
for(i in 1:length(x)){
if(runif(1) <= 0.5){
x2[i]<-1
} else {
x2[i]<-2
}
}
Your output
x2
[1] 1 2 2 1 2 1
In x2 you have random numbers with given values (1 and 2) related to the runif probability.
This is the same thing in a single row:
ifelse(runif(n = length(x))<=0.5,1,2)
[1] 1 2 2 2 1 1

Nested rolling sum in vector

I am struggling to produce an efficient code to compute the vector result r result from an input vector v using this function.
r(i) = \sum_{j=i}^{i-N} [o(i)-o(j)] * exp(o(i)-o(j))
where i loops (from N to M) over the vector v. Size of v is M>>N.
Of course this is feasible with 2 nested for loops, but it is too slow for computational purposes, probably out of fashion and deprecated style...
A MWE:
for (i in c(N+1):length(v)){
csum <- 0
for (j in i:c(i-N)) {
csum <- csum + (v[i]-v[j])*exp(v[i]-v[j])
}
r[i] <- csum
}
In my real application M > 10^5 and the v vector is indeed several vectors.
I have been trying with nested applications of lapply and rollapply without success.
Any suggestion is welcome.
Thanks!
I don't know if it is any more efficient but something you can try:
r[N:M] <- sapply(N:M, function(i) tail(cumsum((v[i]-v[1:N])*exp(v[i]-v[1:N])), 1))
checking that both computations give same results, I got r with your way and r2 with mine, initializing r2 to rep(NA, M) and assessed the similarity:
all((r-r2)<1e-12, na.rm=TRUE)
# [1] TRUE
NOTE: as in #lmo answer, tail(cumsum(...), 1) can be efficiently replaced by just using sum(...):
r[N:M] <- sapply(N:M, function(i) sum((v[i]-v[1:N])*exp(v[i]-v[1:N])))
Here is a method with a single for loop.
# create new blank vector
rr <- rep(NA,M)
for(i in N:length(v)) {
rr[i] <- sum((v[i] - v[seq_len(N)]) * exp(v[i] - v[seq_len(N)]))
}
check for equality
all.equal(r, rr)
[1] TRUE
You could reduce the number of operations by 1 if you store the difference. This should add a little speed up.
for(i in N:length(v)) {
x <- v[i] - v[seq_len(N)]
rr[i] <- sum(x * exp(x))
}

Resources