raul
raul

Reputation: 1269

Random selection from list with replacement

I have a list of lists, like so:

a = [[1,2],[2,3]]

I want to create a random list with replacement of a given size from a. The numpy.random.choice() method only accepts 1D arrays. I can write my own function to do this, but is there already an optimized way?

Expected output:

[[1,2],[1,2],[2,3],[2,3]] 
// the size (4 here) has to be a parameter passed to the function

Upvotes: 7

Views: 9408

Answers (4)

miradulo
miradulo

Reputation: 29740

As of Python 3.6, you can directly use random.choices.

random.choices(list_of_lists, k=sample_size)
## [[1, 2], [3, 4], [3, 4], [1, 2]]

A rough benchmark suggests this seems to be more performant on varying sample sizes than the list comprehension approach.

>>> list_of_lists = [[1, 2], [3, 4]]
>>> sample_size = 4

>>> %timeit [random.choice(list_of_lists) for _ in range(sample_size)]
4.49 µs ± 20.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> %timeit random.choices(list_of_lists, k=sample_size)
1.99 µs ± 14.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> list_of_lists *= 100
>>> sample_size *= 1000

>>> %timeit [random.choice(list_of_lists) for _ in range(sample_size)]
3.54 ms ± 28.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit random.choices(list_of_lists, k=sample_size)
927 µs ± 1.39 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Upvotes: 1

pylang
pylang

Reputation: 44615

The more_itertools library implements more_itertools.random_combination_with_replacement:

import more_itertools as mit

list_of_lists = [[1, 2], [2, 3]]
sample_size = 4
list(mit.random_combination_with_replacement(list_of_lists, sample_size))
# [[1, 2], [1, 2], [2, 3], [2, 3]]

Upvotes: 0

Blacklight Shining
Blacklight Shining

Reputation: 1548

You can simply call the standard library's random.choice() repeatedly. No need for numpy.

>>> list_of_lists = [[1, 2], [2, 3]]
>>> sample_size = 4
>>> [random.choice(list_of_lists) for _ in range(sample_size)]
[[1, 2], [2, 3], [1, 2], [1, 2]]

This is an alternative to random.sample() that works without replacement and lets you choose a “sample” larger than the size of the original population.

Upvotes: 11

AGS
AGS

Reputation: 14498

Using numpy:

size = 4
a = np.array([[1,2],[2,3]])
b = np.random.randint(len(a), size = size)
a[b,:]

Out[93]:
array([[2, 3],
       [2, 3],
       [2, 3],
       [1, 2]])

Upvotes: 1

Related Questions