Arrays 生成大量随机卡片组-NumPy
我需要生成大量随机扑克牌组。速度很重要,所以所有东西都必须是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) 但在这里
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他的原创应用程序
显然不是我的解决方案。