Creating a large number of random card decks - NumPy

I need to create a large number of random poker decks. Speed ​​is important, so everything should be in matrix form.

I understand that I can create two cards from the deck:

np.random.choice(12*4,2, replace=False) 

How can I execute the same query to create a 2d array without a for loop? The difficulty is that each round will have to propagate from the original stack, so the replacement is only true for rows, but False for columns.

I also tried it with

 originalDeck=np.arange(1,12*4) np.random.shuffle(originalDeck) 

But even here we would need to create a 2d array of the original Deck, and then each row? Is it possible?

+1
source share
3 answers

You can model np.random.choice(..., replace=False) trick behavior here based on argsort/argpartition . The idea is simple: we create a random array and sort it. Thus, sorted indexes that are unique will resemble np.random.choice(..., replace=False) .

Since we want to have a 2D array with this function, let's start with a random 2D array and use np.argpartition to get the first two sorted indices along each row to simulate map selection 2 .

So we would have a vector approach like this:

 # N : Number of queries # M : Number of cards to be picked out = np.argpartition(np.random.rand(N,12*4),M,axis=1)[:,:M] 

Runtime Test -

 In [55]: # Input params ...: N = 1000000 # Number of queries ...: M = 2 # Number of cards to be picked ...: ...: def original_app(N,M): ...: out = np.empty((N,2),dtype=int) ...: for i in range(N): ...: out[i] = np.random.choice(12*4,M, replace=False) ...: return out ...: ...: def vectorized_app(N,M): ...: return np.argpartition(np.random.rand(N,12*4),M,axis=1)[:,:M] ...: In [56]: %timeit original_app(N,M) 1 loops, best of 3: 12.7 s per loop In [57]: %timeit vectorized_app(N,M) 1 loops, best of 3: 678 ms per loop 
+1
source

Since you are looking for only a pair of cards, you have only 1128 possible pairs (without replacement), so you can generate all pairs, and then select random cards from this set:

 from itertools import combinations # There may be a better way to generate all possible pairs in numpy, # but I am not aware of and this is pretty fast for this size all_pairs = np.array(list(combinations(range(12 * 4), 2))) cards = all_pairs[np.random.randint(all_pairs.shape[0], size = N_PAIRS), :] 

Where N_PAIRS is the number of pairs you want.

Landmarks:

 In [55]: # Input params ...: N = 1000000 # Number of queries ...: M = 2 # Number of cards to be picked ...: ...: def original_app(N,M): ...: out = np.empty((N,2),dtype=int) ...: for i in range(N): ...: out[i] = np.random.choice(12*4,M, replace=False) ...: return out ...: ...: def vectorized_app(N,M): ...: return np.argpartition(np.random.rand(N,12*4),M,axis=1)[:,:M] ...: ...: def itertools_app(N,M): ...: all_pairs = np.array(list(combinations(range(12 * 4), M))) ...: return all_pairs[np.random.randint(all_pairs.shape[0], size = N), :] In [46]: %timeit original_app(N,M) 1 loops, best of 3: 10.8 s per loop In [47]: %timeit vectorized_app(N,M) 1 loops, best of 3: 618 ms per loop In [48]: %timeit itertools_app(N,M) 10 loops, best of 3: 24.8 ms per loop 

This method is very fast when M very small, as M increases, the number of combinations increases exponentially, and therefore even creating an all_pairs array all_pairs impossible (already with M = 5 you have ~ 1,700,000 possible combinations).

+3
source

Another simple approach, a bit slower than the best @Holt solution.

 def vectorized_app(N): u=np.random.randint(0,12*4,(2*N*103//100)).reshape(-1,2) # 3% more tries. w=np.not_equal(*uT) #selecting valid output, Two differents cards. return u[w][:N] 
0
source

Source: https://habr.com/ru/post/1260514/


All Articles