我有大约20,000个对象的字典。键是对象的字符串表示,值是对象本身。每个对象都有属性self.length
和self.rate
。 self.rate
计算为1.5E-8*self.length
。
我需要根据他们的费率选择一个预先确定的数字(我们假设这个例子是500)这个项目中的项目。具有较低速率的对象将不太可能被选择,而具有较高速率的对象则更有可能被选择。
我认为我能做到这一点的方式非常缓慢。
在while循环中,当所选对象的数量小于所需选择的数量时,我生成一个介于0之间的随机数和dict的长度并选择该元素。然后我生成另一个随机数,如果随机数小于列表中所选对象的rate
,则会将其添加到所选对象中。这开始似乎很好,但现在我意识到它太慢了。有没有人建议如何更快地做到这一点?
一些代码: 对象的类定义
from numpy import random
class object():
def __init__(self, length):
self.length = length
self.rate = (1.15E-8*self.length)
def select(self):
x = random.uniform(0,1)
if(x<self.rate):
return True
else:
return False
完成其余工作的功能(在另一个模块中):
def select_random(object_dict,maxselect):
nselect = 0
object_names = object_dict.keys()
selected_objects = []
while(nselect < maxselect):
x = random.randint(0,len(object_dict))
if(object_dict[object_names[x]].select()):
nselect +=1
selected_objects.append(object_names[x])
return(selected_objects)
我认为让它变得非常慢的原因是每个对象的选择概率都很小,甚至在选择一个对象之前需要进行多次迭代,更不用说500个或更多了。
长度分布:
Min. 1st Qu. Median Mean 3rd Qu. Max.
51 822 1311 1770 2112 103000
答案 0 :(得分:2)
试试这个:
import numpy as np # requires NumPy 1.7 (!)
def select_random(object_dict, n):
keys = object_dict.keys()
rate = np.array([x.rate for x in keys])
prob = rate / rate.sum()
return np.random.choice(keys, size=n, replace=True, p=prob)
P.S。,调用类object
是一个坏主意,因为这也是内置通用基类的名称。
答案 1 :(得分:1)
我不知道这种方法会更快但是更准确:
length
上做一个cumsum并将其保存到名为cumsum
cumsum
的最后一个元素之间的随机数让我们说lengths
为[1,4,2,10,5]
,然后cumsum
为[1,5,7,17,22]
现在您随机选择0
和22
之间的数字 - 你会得到i
概率为lengeths[i]/cumsum[-1]
的元素,这对我来说听起来更准确。
答案 2 :(得分:1)
通过逐步总结项目的权重,您可以根据权重随机选择一个,在[0,T)中统一选择一个随机数,其中T是所有权重的总和,并取项目&#39 ;第一个总数大于(通过例如二进制斩)。如果你想要一个更大的样本,你可以重复这个,或者像这样的代码对随机数进行排序并进行合并排序之类的步骤。复杂性是相同的,但代码有点简单,我认为二进制斩波总是容易出错。
import random
def accumulate_weights(weighted_items):
T = 0.0
for w, i in weighted_items:
T += w
yield (T, i)
def sample_weighted(weighted_items, n):
cumulative = list(accumulate_weights(weighted_items))
T = cumulative[-1][0]
i = 0
for sample in sorted(random.uniform(0, T) for _ in xrange(n)):
while sample > cumulative[i][0]:
i += 1
yield cumulative[i][1]
r = list(sample_weighted([(1.0, 'a'), (2.0, 'b'), (5.0, 'c'), (1.0, 'd')], 10000))
print [(x, r.count(x)) for x in 'abcd']
如果情况不明显,您可以使用&#39;费率&#39;作为权重。当你有一个物体的速率为0.15而另一个物体的速度为0.3时,重要的是第二个物体出现的频率是第一个物体的两倍。这是代码中的权重!
答案 3 :(得分:0)
您的费率介于5.865e-07和0.0011845之间,您的统一随机选择介于0和1之间,我相信如果您能够根据中位数1311选择500个对象,您将会很幸运。
您需要更改随机选择
x = random.uniform(0,1)
是
import random
x = random.triangular(51, 103000 , 1311 )
答案 4 :(得分:-2)
如果你需要足够的对象,可以用这种方式编写select函数:
def select(self):
x = randint(0,self.length)
if x > self.legth - c:
return False
return True
这种方式的概率取决于常数c和长度(反映速率)