我需要生成大量随机扑克牌。速度很重要,所以一切都必须采用numpy矩阵形式。
我知道我可以从卡片中生成两张卡片如下:
np.random.choice(12*4,2, replace=False)
如何执行相同的查询,以便在没有for循环的情况下创建二维数组?困难在于每一轮都需要从原始堆栈中分配,因此替换仅适用于行,而对于列则为False。
我也尝试了
originalDeck=np.arange(1,12*4)
np.random.shuffle(originalDeck)
但是在这里我们还需要生成originalDeck的2d数组然后每行?这可能吗?
答案 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]