Home > database >  R: Correctly Using the Break Statement
R: Correctly Using the Break Statement

Time:06-15

I am working with the R programming language.

I am trying to adapt the answer provided over here (Manual simulation of Markov Chain in R). The code below simulates some random numbers based on some user specified probabilities:

alpha <- c(0,1,0,0, 0)
mat <- matrix(c(1,0,0,0,0,0.2,0.2,0.5,0.05,0.05, 0.3, 0.1,0.1,0.2,0.3, 0.2, 0.2, 0.2, 0.2, 0.2, 0,0,0,0,1), nrow = 5, ncol = 5, byrow = TRUE) 

chainSim <- function(alpha, mat, n) {
  out <- numeric(n)
  out[1] <- sample(1:5, 1, prob = alpha)
  for(i in 2:n) 
    out[i] <- sample(1:5, 1, prob = mat[out[i - 1], ])
  out
}

When we run this function, we can see examples of these random numbers (here, we specify the function to generate 6 random numbers):

chainSim(alpha, mat, 6)
[1] 2 3 1 1 1 1

I want to adapt this code so that when the first "1" or "5" is encountered, the sequence stops. I tried to do this as follows (using the WHILE and BREAK commands):

alpha <- c(0,1,0,0, 0)
mat <- matrix(c(1,0,0,0,0,0.2,0.2,0.5,0.05,0.05, 0.3, 0.1,0.1,0.2,0.3, 0.2, 0.2, 0.2, 0.2, 0.2, 0,0,0,0,1), nrow = 5, ncol = 5, byrow = TRUE) 

chainSim <- function(alpha, mat, n) {
    out <- numeric(n)
    out[1] <- sample(1:5, 1, prob = alpha)
    for(i in 2:n) {
        repeat{
            out[i] <- sample(1:5, 1, prob = mat[out[i - 1], ])
            out
            if (1 %in% out[i] || 5 %in% out[i] ) break
        }
    }}

# simulate numbers until first 1 or 5 is encountered : does not work
chainSim(alpha, mat, n)

# repeat chainSim 100 times : does not work ("sim_final" will have likely have an uneven number of entries in each row)

sim <- replicate(chainSim(alpha, mat, n), n = 100)
sim_final = data.frame(t(sim))

But when I tried to do this, chainSim() does not produce any random numbers and "sim" produces 100 NULL's.

Can someone please show me how to fix this?

Thanks!

CodePudding user response:

There is no need for a repeat or while loop. The code below breaks after the first 1 or 5.

To return only the vector until that point, change the function's last instruction to out[out != 0]. But then the return vectors will be of different lengths and data.frame won't make any sense, the output of replicate should be kept a list.

chainSim <- function(alpha, mat, n) {
  out <- integer(n)
  out[1] <- sample(1:5, 1L, prob = alpha)
  for(i in 2:n) {
    if(out[i - 1L] %in% c(1, 5)) break
    out[i] <- sample(1:5, 1L, prob = mat[out[i - 1], ])
  }
  out
}

alpha <- c(0, 1, 0, 0, 0)
mat <- matrix(c(1, 0, 0, 0, 0,
                0.2, 0.2, 0.5, 0.05, 0.05,
                0.3, 0.1, 0.1, 0.2, 0.3, 
                0.2, 0.2, 0.2, 0.2, 0.2, 
                0, 0, 0, 0, 1), 
              nrow = 5, ncol = 5, byrow = TRUE)

set.seed(2022)
n <- 6L
# simulate numbers until first 1 or 5 is encountered
chainSim(alpha, mat, n)
#> [1] 2 1 0 0 0 0

sim <- replicate(chainSim(alpha, mat, n), n = 100)
sim_final <- data.frame(t(sim))
head(sim_final)
#>   X1 X2 X3 X4 X5 X6
#> 1  2  1  0  0  0  0
#> 2  2  1  0  0  0  0
#> 3  2  3  5  0  0  0
#> 4  2  3  1  0  0  0
#> 5  2  1  0  0  0  0
#> 6  2  3  4  4  4  1

Created on 2022-06-14 by the reprex package (v2.0.1)

  • Related