python中从权重数组获取随机索引的快速方法
我经常发现自己需要一个数组或列表的随机索引,其中索引的概率不是均匀分布的,而是根据一定的正权重。什么是获得它们的快速方法?我知道我可以将权重传递给python中从权重数组获取随机索引的快速方法,python,algorithm,random,Python,Algorithm,Random,我经常发现自己需要一个数组或列表的随机索引,其中索引的概率不是均匀分布的,而是根据一定的正权重。什么是获得它们的快速方法?我知道我可以将权重传递给numpy.random.choice作为可选参数p,但该函数似乎相当慢,并且构建arange来传递它也不理想。权重之和可以是任意正数,并且不能保证为1,这使得在(0,1)中生成随机数,然后减去权重项直到结果为0或更小的方法不可能 虽然对于如何以简单的方式实现类似的事情(主要不是获取数组索引,而是相应的元素)有一些答案,例如,我正在寻找一个快速的解决方
numpy.random.choice
作为可选参数p
,但该函数似乎相当慢,并且构建arange
来传递它也不理想。权重之和可以是任意正数,并且不能保证为1,这使得在(0,1)中生成随机数,然后减去权重项直到结果为0或更小的方法不可能
虽然对于如何以简单的方式实现类似的事情(主要不是获取数组索引,而是相应的元素)有一些答案,例如,我正在寻找一个快速的解决方案,因为适当的函数经常被执行。我的权重经常变化,因此构建别名掩码之类的东西的开销很大(上有详细介绍)应被视为计算时间的一部分。累积求和和对分
在任何一般情况下,都建议计算权重的累积和,并使用对分模块中的对分来查找结果排序数组中的随机点
def weighted_choice(weights):
cs = numpy.cumsum(weights)
return bisect.bisect(cs, numpy.random.random() * cs[-1])
如果速度是一个问题,下面给出更详细的分析
注意:如果数组不是平面的,numpy.unravel\u index
可用于将平面索引转换为形状索引,如中所示
实验分析
使用numpy
内置函数有四种或多或少明显的解决方案。使用timeit
对所有这些解决方案进行比较,得出以下结果:
import timeit
weighted_choice_functions = [
"""import numpy
wc = lambda weights: numpy.random.choice(
range(len(weights)),
p=weights/weights.sum())
""",
"""import numpy
# Adapted from https://stackoverflow.com/a/19760118/1274613
def wc(weights):
cs = numpy.cumsum(weights)
return cs.searchsorted(numpy.random.random() * cs[-1], 'right')
""",
"""import numpy, bisect
# Using bisect mentioned in https://stackoverflow.com/a/13052108/1274613
def wc(weights):
cs = numpy.cumsum(weights)
return bisect.bisect(cs, numpy.random.random() * cs[-1])
""",
"""import numpy
wc = lambda weights: numpy.random.multinomial(
1,
weights/weights.sum()).argmax()
"""]
for setup in weighted_choice_functions:
for ps in ["numpy.ones(40)",
"numpy.arange(10)",
"numpy.arange(200)",
"numpy.arange(199,-1,-1)",
"numpy.arange(4000)"]:
timeit.timeit("wc(%s)"%ps, setup=setup)
print()
结果输出为
178.45797914802097
161.72161589498864
223.53492237901082
224.80936180002755
1901.6298267539823
15.197789980040397
19.985687876993325
20.795070077001583
20.919113760988694
41.6509403079981
14.240949985047337
17.335801470966544
19.433710905024782
19.52205040602712
35.60536142199999
26.6195822560112
20.501282756973524
31.271995796996634
27.20013752405066
243.09768892999273
这意味着
numpy.random.choice
出人意料地非常慢,甚至专用的numpysearchsorted
方法也比类型naivebisect
变体慢。(这些结果是使用Python3.3.5和numpy 1.8.1获得的,因此其他版本的情况可能不同。)基于numpy.random.multinomial
的函数对于大权重的效率低于基于累积求和的方法。argmax必须迭代整个数组并运行比较,这一事实在每一步中都起着重要作用,从递增和递增之间的四秒差也可以看出这一点减少权重列表。由于效率限制,我将收回我的收盘价,但相关:,