53

リストにアイテムのコレクションがある場合。別の重みのリストに従って、そのリストから選択したいと思います。

たとえば、私のコレクションが['one', 'two', 'three']で、重みが[0.2, 0.3, 0.5]である場合、メソッドはすべての描画の約半分で「3」を返すと予想します。

そうする最も簡単な方法は何ですか?

4

7 に答える 7

11

この関数は、重みのリストと、選択するオブジェクトを含むリストの 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 ループは使用しません。

于 2012-05-29T16:30:10.027 に答える
5

多項分布(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 回出現しました。

多項分布について理解するのに苦労している場合は、ドキュメントが非常に役立つことがわかりました。

于 2012-05-29T17:01:19.267 に答える
4

を使用したくない場合は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

于 2012-05-29T17:01:02.370 に答える
2

リストを初期化して、選択を予想される重みと一致させるだけではどうですか。ここでは、目的の「プル」パーセンテージを表す 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

累積的ではありませんが、探しているもののようです。

于 2012-06-11T05:15:23.307 に答える
1

重み付けされたランダム値を繰り返し取得したい場合に最適な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]))
于 2012-05-29T17:14:41.143 に答える