我需要创建一个10,000 x 50的数组,其中每行包含1到365之间的递增系列随机数,如下所示:
sample_dates = np.array([np.sort(np.random.choice(365, 50, replace=False)) for _ in range(10000)])
我想通过迭代器来解决这个问题的唯一方法:
{{1}}
哪个有效,但速度很慢(运行时间约为0.33秒),而且我将要做这几千次)。有没有更快的方法来实现这一目标?
编辑:据我所知,这个解决方案中最昂贵的部分是迭代和对np.random.choice的10k个别调用,而不是排序
答案 0 :(得分:2)
考虑到数组的形状,我认为迭代列可能会提供一些改进。所以我的想法是产生10k数字 - 替换。然后,在循环中,生成另外10k个数字并检查行方式重复。如果有的话,消除那些并生成那么多随机数。如果我没记错的话,这也称为命中和未命中算法。
这是工作代码:
arr = np.random.choice(365, 10000)
for i in range(49):
arr2 = np.random.choice(365, 10000)
comp = (arr2 == arr)
while comp.any():
duplicate = comp if i==0 else comp.any(axis=0)
arr2[duplicate] = np.random.choice(365, duplicate.sum())
comp = (arr2 == arr)
arr = np.vstack([arr, arr2])
arr = arr.T
arr.sort(axis=1)
这需要93.4毫秒才能完成。您的计算机在我的计算机上需要590毫秒,因此它提供了大约6倍的改进。
答案 1 :(得分:2)
这是np.argpartition/np.argsort
的诀窍。
这个想法是 -
获取一组形状为(10000,365)
的浮动随机数组,并在每行上执行argsort
。这将为我们提供唯一的索引,从而模拟与replace=False
一起使用的np.random.choice
条件。
为每行切出第一个50
列。
最后,每行的排序都可以完成排序数据的工作。
现在,我们可以使用np.argpartition
进一步提升效果,以k=50
为每行进行分区。
因此,我们将有一个矢量化解决方案,如此 -
np.sort(np.random.rand(10000,365).argpartition(50,axis=1)[:,:50])
让我们验证输出数据的一致性
In [209]: out = np.sort(np.random.rand(10000,365).argpartition(50,axis=1)[:,:50])
In [210]: count = np.bincount(out.ravel(), minlength=365)
In [211]: print count.min(), count.max()
1277 1466
看起来很漂亮!让我们来看主要业务,即获得业绩数据。
运行时测试
方法 -
# Original approach
def org_app():
return np.array([np.sort(np.random.choice(365, 50, replace=False)) for _ in range(10000)])
# @Nils Werner's soln
def sort_random_choice():
return np.sort([np.random.choice(365, 50, replace=False) for _ in range(10000)], axis=1)
# @Miriam Farber's soln
def random_permute():
l = np.array([True]*50 + [False]*315)
total = np.arange(1,366)
return np.array([total[np.random.permutation(l)] for _ in range(10000)])
# Proposed in this post
def argpartition_sort(nrows=10000, maxc=365, ncols=50):
return np.sort(np.random.rand(nrows,maxc).argpartition(ncols,axis=1)[:,:ncols])
# @ayhan's soln
def while_loop():
arr = np.random.choice(365, 10000)
for i in range(49):
arr2 = np.random.choice(365, 10000)
comp = (arr2 == arr)
while comp.any():
duplicate = comp if i==0 else comp.any(axis=0)
arr2[duplicate] = np.random.choice(365, duplicate.sum())
comp = (arr2 == arr)
arr = np.vstack([arr, arr2])
arr = arr.T
arr.sort(axis=1)
return arr
计时 -
In [44]: %timeit org_app()
...: %timeit sort_random_choice()
...: %timeit random_permute()
...: %timeit argpartition_sort()
...: %timeit while_loop()
...:
1 loops, best of 3: 258 ms per loop
1 loops, best of 3: 232 ms per loop
10 loops, best of 3: 166 ms per loop
10 loops, best of 3: 79.9 ms per loop
10 loops, best of 3: 58.6 ms per loop
答案 2 :(得分:1)
一种可能的优化是通过将sort
置于循环之外来对其进行矢量化:
sample_dates = np.sort([np.random.choice(365, 50, replace=False) for _ in range(10000)], axis=1)
答案 3 :(得分:1)
以下解决方案不使用sort:
l = np.array([True]*50 + [False]*315)
total = np.arange(1,366)
sample_dates = np.array([total[np.random.permutation(l)] for _ in range(10000)])
因此它似乎比其他建议的解决方案更快(我的计算机需要0.44秒,而#34; Nils Werner"解决方案需要0.77秒.OP的解决方案需要0.81秒)。