リストにアイテムのコレクションがある場合。別の重みのリストに従って、そのリストから選択したいと思います。
たとえば、私のコレクションが['one', 'two', 'three']
で、重みが[0.2, 0.3, 0.5]
である場合、メソッドはすべての描画の約半分で「3」を返すと予想します。
そうする最も簡単な方法は何ですか?
この関数は、重みのリストと、選択するオブジェクトを含むリストの 2 つの引数を取ります。
from numpy import cumsum
from numpy.random import rand
def weightedChoice(weights, objects):
"""Return a random item from objects, with the weighting defined by weights
(which must sum to 1)."""
cs = cumsum(weights) #An array of the weights, cumulatively summed.
idx = sum(cs < rand()) #Find the index of the first weight over a random value.
return objects[idx]
Python ループは使用しません。
多項分布(numpy から) を使用して、必要なことを行うことができます。例えば
elements = ['one', 'two', 'three']
weights = [0.2, 0.3, 0.5]
import numpy as np
indices = np.random.multinomial( 100, weights, 1)
#=> array([[20, 32, 48]]), YMMV
results = [] #A list of the original items, repeated the correct number of times.
for i, count in enumerate(indices[0]):
results.extend( [elements[i]]*count )
したがって、1 番目の位置の要素は 20 回、2 番目の位置の要素は 32 回、3 番目の位置の要素は 48 回出現しました。
多項分布について理解するのに苦労している場合は、ドキュメントが非常に役立つことがわかりました。
を使用したくない場合はnumpy
、次のような方法で同じ方法に従うことができます。
from random import random
from itertools import takewhile
def accumulate(iterator):
"""Returns a cumulative sum of the elements.
accumulate([1, 2, 3, 4, 5]) --> 1 3 6 10 15"""
current = 0
for value in iterator:
current += value
yield current
def weightedChoice(weights, objects):
"""Return a random item from objects, with the weighting defined by weights
(which must sum to 1)."""
limit = random()
return objects[sum(takewhile(bool, (value < limit for value in accumulate(weights))))]
itertools.takewhile()
停止したいポイントに到達したら、値のチェックを避けるために使用します。それ以外の場合、これは基本的にミーシャ・オブレヒトの答えと同じ考えですが、 はありませんnumpy
。
リストを初期化して、選択を予想される重みと一致させるだけではどうですか。ここでは、目的の「プル」パーセンテージを表す 100 個の値のリストを作成しています。
>>> import random
>>> elements = ['one', 'two', 'three']
>>> weights = [0.2, 0.3, 0.5]
>>>
>>> # get "sum" of result list of lists (flattens list)
>>> choices = sum([[element] * int(weight * 100)for element, weight in zip(elements, weights)], [])
>>> random.choice(choices)
three
累積的ではありませんが、探しているもののようです。
重み付けされたランダム値を繰り返し取得したい場合に最適なMaus の答えに基づいて構築するには、単一の値のみが必要な場合は、numpy.random.multinomial()
とを組み合わせることで非常に簡単にこれを行うことができitertools.compress()
ます。
from itertools import compress
from numpy.random import multinomial
def weightedChoice(weights, objects):
"""Return a random item from objects, with the weighting defined by weights
(which must sum to 1)."""
return next(compress(objects, multinomial(1, weights, 1)[0]))