0

From this thread I found out that I can use an approach with the random.choices for my needs:

class Weights:
    ITEM = {
        'a': 0.5,
        'b': 0.4,
        'c': 0.3,
        'd': 0.2,
        'e': 0.1
    }

import random
slot_1 = random.choices(population=list(Weights.ITEM.keys()), weights=list(Weights.ITEM.values()), k=1)[0]
slot_2 = ...?
slot_3 = ...?

Is it possible for me to get an array with the k=3 that will have "unique" results (probably [a,b,c]) or somehow to exclude any previously selected value from the next call (with k=1)?
For example lets say slot_1 got "b" and slot_2 will get a random from the list of everything else without the "b" value.
This step can be sensitive to the performance and I think that creating new arrays each time is not a good idea. Maybe there is something except random.choices that can be applied in this case.

IgorZ
  • 1,125
  • 3
  • 20
  • 44

1 Answers1

1

You could take all the samples all at once using numpy's random.choice with the replace = False option (assuming the weights are just renormalized between steps,) and store them using multiple assignment, to get it into one line of code.

import numpy as np

slot_1, slot_2, slot_3 = np.random.choice(list(Weights.ITEM.keys()), size = 3, replace=False, p=list(Weights.ITEM.values()))

More generally, you could have a function that generated arbitrary length subsamples (k is length, n is number of samples):

def a(n,k,values,weights):
    a = np.split(np.random.choice(values, size = n*k,replace=False, p=weights), n)
    return [list(sublist) for sublist in a]

>>> a(3,5, range(100), [.01]*100)
[[39, 34, 27, 91, 88], [19, 98, 62, 55, 38], [37, 22, 54, 11, 84]]
Cody E
  • 36
  • 4
  • Is it correct that `random.choices` accepts any weighted values when `np.random.choice` takes only an array with `sum == 1` ? – IgorZ Sep 02 '20 at 13:27
  • 1
    This appears to be the case, yes. ```>>> a(3,5, range(100), [1]*100) Traceback (most recent call last): File "", line 1, in a(3,5, range(100), [1]*100) File "", line 2, in a a = np.split(np.random.choice(values, size = n*k,replace=False, p=weights), n) File "mtrand.pyx", line 926, in numpy.random.mtrand.RandomState.choice ValueError: probabilities do not sum to 1``` It's correctable by using: ```map(lambda x: x/sum(myweights), myweights)``` – Cody E Sep 02 '20 at 15:31
  • You might want to throw that through a ```list``` since it returns a generator though. – Cody E Sep 02 '20 at 15:38