オブジェクトのリスト「p」があり、すべてのオブジェクトにはいくつかの番号「a」があります(たとえば、p[3].a = 5)。オブジェクトを選択する確率が a の値に比例するように、リストからランダムなオブジェクトを選択したい。つまり、a=5 のオブジェクトを選択する確率は、a=1 のオブジェクトを選択する確率の 5 倍である. Python/Pylab/Numpyでどうすればいいですか?
ありがとう!
オブジェクトのリスト「p」があり、すべてのオブジェクトにはいくつかの番号「a」があります(たとえば、p[3].a = 5)。オブジェクトを選択する確率が a の値に比例するように、リストからランダムなオブジェクトを選択したい。つまり、a=5 のオブジェクトを選択する確率は、a=1 のオブジェクトを選択する確率の 5 倍である. Python/Pylab/Numpyでどうすればいいですか?
ありがとう!
これは整数カウントでは機能しますが、大きなカウントでは効率的ではありません。
c = collections.Counter({k:k.a for k in stuff})
random.choice(list(c.elements()))
より効率的な方法を次に示します。
import random
def weighted_choice(items):
# check if no items exist
if not items:
return None
# compute total of all weights
total = sum(item.weight for item in items)
# select a random point within the total
selection = random.randint(0, total - 1)
# find the corresponding item
count = 0
for item in items:
count += item.weight
if selection < count:
return item
bisectを使用することをお勧めします
from bisect import bisect
class Element(object):
def __init__(self, value):
self.a = value
def __repr__(self):
return 'Element({})'.format(self.a)
data = [Element(3), Element(5), Element(7), Element(1)]
last = 0
breakpoints = []
for element in data:
breakpoints.append(last + element.a)
last += element.a
print(breakpoints)
for random_value in xrange(last):
pos = bisect(breakpoints, random_value)
print(random_value, data[pos])
ブレークポイントを含むリストを 1 回だけ作成する必要があります。その後、必要に応じて、非常に高速な bisect アルゴリズムで使用できます。
最後のループは、結果を示すためのものです。
編集: ブレークポイントを取得する別の方法 (for ループは好きではありませんでした):
values = [value.a for value in data]
breakpoints = [sum(values[:pos+1]) for pos in xrange(len(values))]