Arrays 生成大量随机卡片组-NumPy

Arrays 生成大量随机卡片组-NumPy,arrays,performance,numpy,vectorization,Arrays,Performance,Numpy,Vectorization,我需要生成大量随机扑克牌组。速度很重要,所以所有东西都必须是numpy矩阵形式 我知道我可以从一副牌中生成两张牌,如下所示: np.random.choice(12*4,2, replace=False) 如何执行相同的查询,以便在不使用for循环的情况下创建二维数组?困难在于每一轮都需要从原始堆栈中分配,因此replace只对行有效,而对列无效 我也试过了 originalDeck=np.arange(1,12*4) np.random.shuffle(originalDeck) 但在这里

我需要生成大量随机扑克牌组。速度很重要,所以所有东西都必须是numpy矩阵形式

我知道我可以从一副牌中生成两张牌,如下所示:

np.random.choice(12*4,2, replace=False)
如何执行相同的查询,以便在不使用for循环的情况下创建二维数组?困难在于每一轮都需要从原始堆栈中分配,因此replace只对行有效,而对列无效

我也试过了

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

但在这里,我们也需要生成一个二维的originalDeck数组,然后是每一行?这是可能的吗?

因为您只寻找一对卡片,所以您只有
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个可能的组合).

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

因为,我们希望有一个具有这种功能的2D数组,从一个随机2D数组开始,为了性能起见,我们将沿着每行获得前两个排序索引,以模拟
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

另一种简单的方法,比@Holt best 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(*u.T) #selecting valid output, Two differents cards.
    return u[w][:N]

首先实现一个循环版本怎么样?将有超过1m个卡片组,所以循环太慢了。速度对于这个问题非常重要。这不是一个简单的解决方案。使用列表很容易,但速度很慢。@nickpick您只使用列表生成初始对集,它只包含我在文章中提到的
1128
对。这显然并不慢,除非您需要多次生成它。如果是这种情况,你应该详细说明你想对你的问题做什么。@nickpick无论你选择什么解决方案,你都不应该总是相信“完整的numpy”解决方案。对于
N=1000000
M=2
,上述解决方案比@DivakarNot根据其上述定时帖子提出的
矢量化应用程序
快得多。他说12秒vs。7secs@nickpick他的
原创应用程序
显然不是我的解决方案。