Python には重み付けされたサンプリング機能が組み込まれていません (NumPy/SciPy には組み込まれています) が、このような非常に単純なケースでは、非常に簡単です。
import itertools
import random
probabilities = [0.3, 0.2, 0.5]
totals = list(itertools.accumulate(probabilities))
def sample():
n = random.uniform(0, totals[-1])
for i, total in enumerate(totals):
if n <= total:
return i
Python 3.2+ を持っていない場合、accumulate
関数はありません。リストが本当に短い場合は、非効率的なワンライナーでそれを偽造できます。
totals = [sum(probabilities[:i+1]) for i in range(len(probabilities))]
…または、明示的なループまたは醜い呼び出しを作成するか、ドキュメントreduce
から同等の Python 関数をコピーすることができます。
また、数値の合計が 1.0 になることが確実な場合random.uniform(0, totals[-1])
は、より複雑な書き方になることに注意してください。random.random()
これをテストする簡単な方法:
>>> samples = [sample() for _ in range(100000)]
>>> samples.count(0)
29878
>>> samples.count(1)
19908
>>> samples.count(2)
50214
これらは、それぞれ 100000 の 30%、20%、50% にかなり近い値です。