cclams4444
cclams4444

Reputation: 27

Generate new column in R, keep value if it meets a condition, else use the previous column

I'm using R to generate two separate column vectors of length 20, and I want to add 150 additional column vectors to them and keep the new values based on values in previous columns. I initiate both column vectors using the code below:

n <- 20
set.seed(4)
x0 <- runif(n = n, min = -9, max = 9)
set.seed(16)
y0 <- runif(n = n, min = -9, max = 9)

This gives me the first column for each vector. Then, I generate a second column based on these values. However, I only want to keep the new values per row if they meet certain conditions. If they don't meet the conditions, I want the new column values to be replaced by the old column values. The code below is to generate the new column, analyze its values, and keep the new value or replace it with the old value, then repeat 150 iterations:

iter <- 150
for(j in 1:iter){
  St <- runif(n = n, min = 0, max = 2)
  dt <- runif(n = n, min = 0, max = 2*pi)
  dx <- cos(dt)
  dy <- sin(dt)
  xm <- St*dx
  ym <- St*dy
  x0 <- cbind(x0, xm)
  y0 <- cbind(y0, ym)
  xall <- t(apply(x0, 1, cumsum))
  yall <- t(apply(y0, 1, cumsum))
  for(i in 1:n){
    if(xall[i,j+1]<=3 & xall[i,j+1]>=-3 & yall[i,j+1]<=3 & yall[i,j+1]>=-3){
      xall[i,j+1] <- xall[i,j+1]
      yall[i,j+1] <- yall[i,j+1]
    }
    else if(xall[i,j]>3 | xall[i,j]<(-3) | yall[i,j]>3 | yall[i,j]<(-3)){
      xall[i,j+1] <- xall[i,j+1]
      yall[i,j+1] <- yall[i,j+1]
    }
    else{
      xall[i,j+1] <- xall[i,j]
      yall[i,j+1] <- yall[i,j]
    }
  }
}

The "xall" and "yall" arrays keep adding columns onto them, one by one for 150 iterations. After each iteration and a new column is added, it should follow these rules below:

I'll give an example output of my code here, which currently isn't working as needed:

> xall[3,10:14]
      x10       x11       x12       x13       x14 
-3.657078 -2.558799 -2.790860 -2.797736 -3.372856 

> yall[3,10:14]
      y10       y11       y12       y13       y14  
-1.938531 -2.991856 -2.597014 -2.694228 -3.363116 

Starting at x10 and y10. At least one of them is out of range [-3,3], so they should accept the new column value for column 11 (working as expected). In column 11, both x11 and y11 are within range, but the next column x12 and y12 are also both within range, so they should accept the new values (working as expected). Jumping to x13 and y13, both are within range, but at least one of the next values is not. So x14 and y14 should copy the previous values (not working as expected). The goal is to get something like this for x14 and y14:

> xall[3,10:14]
      x10       x11       x12       x13       x14 
-3.657078 -2.558799 -2.790860 -2.797736 -2.797736

> yall[3,10:14]
      y10       y11       y12       y13       y14  
-1.938531 -2.991856 -2.597014 -2.694228 -2.694228 

This is essentially a random walk problem. Is there a way for each point to reach the goal of being between [-3,3] and then not leaving once arrived?

Upvotes: 0

Views: 207

Answers (1)

AndreasM
AndreasM

Reputation: 952

I think the problem is that your loop is running over index j (1 to 150) and replacing values in column j+1. Therefore the values may get replaced in the next iteration of the loop (depending on the new j and j+1 values).

Does separating creation of the columns and checking/replacing the values get you want you want? This keeps the values in range if both values (x/y) are in range in the same column (which is what you want, I assume).

To simplify things a bit, I used a logical vector instead of a loop over rows for the conditional replacement of value.

n <- 20
set.seed(4)
x0 <- runif(n = n, min = -9, max = 9)
set.seed(16)
y0 <- runif(n = n, min = -9, max = 9)

iter <- 150

for(j in 1:iter){
  St <- runif(n = n, min = 0, max = 2)
  dt <- runif(n = n, min = 0, max = 2*pi)
  dx <- cos(dt)
  dy <- sin(dt)
  xm <- St*dx
  ym <- St*dy
  x0 <- cbind(x0, xm)
  y0 <- cbind(y0, ym)
}

xall <- t(apply(x0, 1, cumsum))
yall <- t(apply(y0, 1, cumsum))

#function to check if values are in target range
chk <- function(x) {x <= 3 & x >= -3}

for(icol in 1:iter) {
  
  #condition1: values in column icol+1 between -3 and 3
  idx1 <- chk(xall[,icol+1]) &  chk(yall[,icol+1])

  #condition2: values in column icol between -3 and 3
  idx2 <- chk(xall[,icol]) &  chk(yall[,icol])

  #replace values in icol+1 with icol if condition 2 but not condition 1
  idx3 = !idx1 & idx2
  
  xall[idx3,icol+1] <- xall[idx3,icol]
  yall[idx3,icol+1] <- yall[idx3,icol]
  
}
xall[3,10:14]
       xm        xm        xm        xm        xm 
-3.657078 -2.558799 -2.790860 -2.797736 -2.797736 

yall[3,10:14]
       ym        ym        ym        ym        ym 
-1.938531 -2.991856 -2.597014 -2.694228 -2.694228 

Upvotes: 1

Related Questions