Non-repetitive random number in numpy

RandomNumpyNumbersNon Repetitive

Random Problem Overview


How can I generate non-repetitive random numbers in numpy?

list = np.random.random_integers(20,size=(10))

Random Solutions


Solution 1 - Random

numpy.random.Generator.choice offers a replace argument to sample without replacement:

from numpy.random import default_rng

rng = default_rng()
numbers = rng.choice(20, size=10, replace=False)

If you're on a pre-1.17 NumPy, without the Generator API, you can use random.sample() from the standard library:

print(random.sample(range(20), 10))

You can also use numpy.random.shuffle() and slicing, but this will be less efficient:

a = numpy.arange(20)
numpy.random.shuffle(a)
print a[:10]

There's also a replace argument in the legacy numpy.random.choice function, but this argument was implemented inefficiently and then left inefficient due to random number stream stability guarantees, so its use isn't recommended. (It basically does the shuffle-and-slice thing internally.)

Some timings:

import timeit
print("when output size/k is large, np.random.default_rng().choice() is far far quicker, even when including time taken to create np.random.default_rng()")
print(1, timeit.timeit("rng.choice(a=10**5, size=10**4, replace=False, shuffle=False)", setup="import numpy as np; rng=np.random.default_rng()", number=10**3)) #0.16003450006246567
print(2, timeit.timeit("np.random.default_rng().choice(a=10**5, size=10**4, replace=False, shuffle=False)", setup="import numpy as np", number=10**3)) #0.19915290002245456

print(3, timeit.timeit("random.sample( population=range(10**5), k=10**4)", setup="import random", number=10**3))   #5.115292700007558

print("when output size/k is very small, random.sample() is quicker")
print(4, timeit.timeit("rng.choice(a=10**5, size=10**1, replace=False, shuffle=False)", setup="import numpy as np; rng=np.random.default_rng()", number=10**3))  #0.01609779999125749
print(5, timeit.timeit("random.sample( population=range(10**5), k=10**1)", setup="import random", number=10**3))  #0.008387799956835806

So numpy.random.Generator.choice is what you usually want to go for, except for very small output size/k.

Solution 2 - Random

I think numpy.random.sample doesn't work right, now. This is my way:

import numpy as np
np.random.choice(range(20), 10, replace=False)

Solution 3 - Random

Years later, some timeits for choosing 40000 out of 10000^2 (Numpy 1.8.1, imac 2.7 GHz):

import random
import numpy as np

n = 10000
k = 4
np.random.seed( 0 )

%timeit np.random.choice( n**2, k * n, replace=True )  # 536 µs ± 1.58 µs
%timeit np.random.choice( n**2, k * n, replace=False ) # 6.1 s ± 9.91 ms

# https://docs.scipy.org/doc/numpy/reference/random/index.html
randomstate = np.random.default_rng( 0 )
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=False )  # 766 µs ± 2.18 µs
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=True )   # 1.05 ms ± 1.41 µs

%timeit random.sample( range( n**2 ), k * n )          # 47.3 ms ± 134 µs

(Why choose 40000 out of 10000^2 ? To generate large scipy.sparse.random matrices -- scipy 1.4.1 uses np.random.choice( replace=False ), slooooow.)

Tip of the hat to numpy.random people.

Solution 4 - Random

You can get this by sorting as well:

random_numbers = np.random.random([num_samples, max_int])
samples = np.argsort(random_numbers, axis=1)

Solution 5 - Random

Python set-list conversion can be used. 10 random non repetitive numbers between 0 and 20 can be obtained as:

import random
numbers=set()
while(len(numbers)<10):
    numbers.add(random.randint(0,20))

numbers=list(numbers)
random.shuffle(numbers)
print(numbers)

Solution 6 - Random

Simply generate an array that contains the required range of numbers, then shuffle them by repeatedly swapping a random one with the 0th element in the array. This produces a random sequence that doesn't contain duplicate values.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAcademiaView Question on Stackoverflow
Solution 1 - RandomSven MarnachView Answer on Stackoverflow
Solution 2 - RandomstrnamView Answer on Stackoverflow
Solution 3 - RandomdenisView Answer on Stackoverflow
Solution 4 - RandomBenView Answer on Stackoverflow
Solution 5 - RandomAli ŞentürkView Answer on Stackoverflow
Solution 6 - RandomPolynomialView Answer on Stackoverflow