Home > Back-end >  Generating "Non-Random" Numbers in R?
Generating "Non-Random" Numbers in R?

Time:08-09

I know how to generate 100 random numbers in R (without replacement):

random_numbers = sample.int(100, 100, replace = FALSE)

I was now curious about learning how to generate 100 "non random" numbers (without replacement). The first comes to mind is to generate a random number, and the next number will be the old number 1 with a probability of 0.5 or an actual random number with probability 0.5. Thus, these numbers are not "fully random".

This was my attempt to write this code for numbers in a range of 0 to 100 (suppose I want to repeat this procedure 100 times):

library(dplyr)

all_games <- vector("list", 100) 

for (i in 1:100){

index_i = i
guess_sets <- 1:100 
prob_i = runif(n=1, min=1e-12, max=.9999999999)
    guess_i  = ifelse(prob_i> 0.5, sample.int(1, 100, replace = FALSE), guess_i   1)
    guess_sets_i <- setdiff(guess_sets_i, guess_i)
all_games_i = as.list(index_i, guess_i, all_games_i)
all_games[[i]] <- all_games_i
}

all_games <- do.call("rbind", all_games)

I tried to make a list that stores all guesses such that the range for the next guess automatically excludes numbers that have already been guessed, but I get this error:

Error in sample.int(1, 100, replace = FALSE) : 
  cannot take a sample larger than the population when 'replace = FALSE'

Ideally, I am trying to get the following results (format doesn't matter):

index_1 : 5,6,51,4,3,88,87,9 ...
index_2 77,78,79,2,65,3,1,99,100,4...
etc.
  • Can someone please show me how to do this? Are there easier ways in R to generate "non-random numbers"?

Thank you!

Note: I think an extra line of logic needs to be added - Suppose I guess the number 100, after guessing the number 100 I must guess a new random number since 100 1 is not included in the original range. Also, if I guess the number 5, 17 then 4 - and after guessing 4, the loop tells me to guess 4 1, this is impossible because 5 has already been guessed. In such a case, I would also have to guess a new random number?

CodePudding user response:

It would be tricky to make your algorithm very efficient in R... it doesn't lend itself nicely to vectorization. Here's how I'd write it directly as a for loop:

semirandom = function(n) {
  safe_sample = function(x, ...) {
    if(length(x) == 1) return(x)
    sample(x, ...)
  }
  
  result = numeric(n)
  result[1] = sample.int(n, size = 1)
  for(i in 2:length(result)) {
    if(runif(1) < .5 && 
       result[i - 1] < n &&
       !((result[i - 1]   1) %in% result)) {
      result[i] = result[i - 1]   1
    } else {
      result[i] = safe_sample(x = setdiff(1:n, result), size = 1)
    }
  }
  result
}

# generate 10 semirandom numbers 5 times
replicate(semirandom(10), n = 5)
#       [,1] [,2] [,3] [,4] [,5]
#  [1,]    6    4    4    2    6
#  [2,]    3    5    5    3    7
#  [3,]    4    3    6    4    5
#  [4,]    5    1    2    5    2
#  [5,]    7    9    3    6    3
#  [6,]    9   10   10    1    1
#  [7,]   10    2    8    9    4
#  [8,]    2    8    1    8   10
#  [9,]    1    7    9   10    9
# [10,]    8    6    7    7    8

CodePudding user response:

You get the error cannot take a sample larger than the population when 'replace = FALSE' because you attempt to extract 100 values from a vector of length one without replacement.

The following draws numbers between 1 and 100, draws each number not more than once, has a 50 percent chance of drawing the previous number 1 and a 50 percent chance of drawing another random number, if the previous number 1 has not been drawn yet, and a 100 percent chance to draw another random number, if the previous number 1 has been drawn.

i <- sample.int(100, 1)
j <- i
for(x in 1:99) {
  if((i   1L) %in% j) {
    i <- sample((1:100)[-j], 1L)
  } else {
    if(runif(1L) > 0.5 || i == 100L) {
      i <- sample((1:100)[-j], 1L)
    } else {
      i <- i   1L
    }
  }
  j <- c(j, i)
}
  • Related