1
votes

According to the http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.random.choice.html, using the replace = False with Numpy's random.choice method should make the sample without replacement. However, this does not seem to work for me:

In [33]: import numpy as np

In [34]: arr = range(5)

In [35]: number = np.random.choice(arr, replace = False)

In [36]: arr
Out[36]: [0, 1, 2, 3, 4]

The array arr is still range(5) after sampling, and not missing a (random) number as I would expect. How could I sample a number from range(5) without replacement?

2
np.random.choice does not mutate the original array. It's not literally sampling from the array. - juanpa.arrivillaga
You are not assigning it back to arr. - Divakar
@Divakar that would be the complement of what OP is looking for. - juanpa.arrivillaga
"How could I sample a number from range(5) without replacement?" for a single number, "with or without" part is not important. If you want to sample two numbers, you'd just do np.random.choice(arr, 2, replace=False) - ayhan
@juanpa.arrivillaga Well I am not sure what OP is looking for, but since OP mentioned : array arr is still range(5), hence my earlier comment. - Divakar

2 Answers

12
votes

As mentioned in one of the comments, np.choice selects with or without replacement, a series of numbers from a sequence. But it does not modify the sequence.

Easy alternative

arr = range(5)
# numbers below will never contain repeated numbers (replace=False)
numbers = np.random.choice(arr, 3, replace=False) 

The behaviour I think you want would be:

arr = range(5)
all_but_one = np.random.choice(arr, len(arr) -1, replace=False)

so you would select N-1 numbers without replacement (to avoid repetitions), effectively removing a random element from the iterable.

More efficient alternative

arr = range(5)
random_index = np.random.randint(0, len(arr))
arr.pop(random_index)
1
votes

I ended up defining a function using the random library:

import random
def sample_without_replacement(arr):
    random.shuffle(arr)
    return arr.pop()

Its use is shown below:

In [51]: arr = range(5)

In [52]: number = sample_without_replacement(arr)

In [53]: number
Out[53]: 4

In [54]: arr
Out[54]: [2, 0, 1, 3]

Note that the method also shuffles the array in place, but for my purposes that doesn't matter.