生成大量随机卡片组 - NumPy

时间:2016-02-23 08:27:42

标签: arrays performance numpy vectorization

我需要生成大量随机扑克牌。速度很重要,所以一切都必须采用numpy矩阵形式。

我知道我可以从卡片中生成两张卡片如下:

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

如何执行相同的查询,以便在没有for循环的情况下创建二维数组?困难在于每一轮都需要从原始堆栈中分配,因此替换仅适用于行,而对于列则为False。

我也尝试了

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

但是在这里我们还需要生成originalDeck的2d数组然后每行?这可能吗?

3 个答案:

答案 0 :(得分:3)

由于你只是在寻找一对卡,你只有1128个可能的对(没有替换),所以你可以生成所有对,然后从这个集合中挑选随机卡:

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), :]

N_PAIRS是你想要的对数。

基准:

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

M非常小时,此方法非常快,因为M变大,组合数量呈指数增长,因此甚至无法创建all_pairs数组(已经使用M = 5,你有~1700000种可能的组合。)

答案 1 :(得分:1)

您可以根据argsort/argpartition使用诀窍模拟np.random.choice(..., replace=False)的行为。这个想法很简单:我们创建一个随机数组并对其进行排序。由此获得的排序索引是唯一的,类似于np.random.choice(..., replace=False)

因为,我们希望拥有一个具有这样功能的2D数组,从随机2D数组开始,并使用性能np.argpartition获取每行的前两个排序索引以模拟2卡片采摘。

因此,我们将采用像这样的矢量化方法 -

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

运行时测试 -

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

答案 2 :(得分:0)

另一种简单的方法,比@Holt最佳解决方案稍慢。

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(*u.T) #selecting valid output, Two differents cards.
    return u[w][:N]