Search code examples
pythonnumpyrandomcombinationsprobability

numpy random.choise - get several values with a minimum distance between them


I am using numpy's random.choise to get n integers in range(0,1000), where the same integer can't be chosen twice (replace=false).

But since each integer is a starting point of a sublist with a certain length (e.g.- 10), I want to have the random function not choosing any other integer that is +- 10 from already chosen ones.

using the p= parameter is not possible because i do not know in advance which n's will be chosen. (It could be possible to use a loop - where each iteration the +-10 integers from the newly chosen one are added to the list of probabilities with assigned probability 0, but that seems to me like a not optimal solution...)

for example:

myseries = list(range(1000))
n = 30 
blockRange = 10
np.random.choice(myseries, n, replace=False)

This returns 30 numbers, two of them are 33 and 37 - but I want to 'forbid' this (if 33 is there, no number between 24 to 42 should be allowed!)

thanks


Solution

  • A solution is to build it iteratively, it will be slower than a numpy method for sure but I can't find a way to do your particular random distribution with numpy.

    I create a res list and a forbidden set.

    I iterate n times (here n=30), try to compute a random number in specific bounds. If it's not forbidden, meaning that this number is not in the forbidden set I can add it to my res list.

    And I also add to my forbidden set every int in this range : [rand_num-9; rand_numb[.

    But if it is in my forbidden set I retry thanks to a while loop to find a suitable random number.

    code :

    import random 
    
    n, lower_bound, upper_bound = 30, 0, 1000
    res = []
    forbidden = set()
    for _ in range(n):
        rand_numb = random.randint(lower_bound, upper_bound)
        while rand_numb in forbidden:
            rand_numb = random.randint(0,1000)
        res.append(rand_numb)
        forbidden = forbidden.union(set(range(rand_numb-9, rand_numb+10)))