ここでは、必要な処理を行うプレーンなPythonアルゴリズムを示します。現在行っていることよりも効率的ですが、よりスマートな方法があると確信しています。 :)
num
を必要なサンプルの総数とします。最初にnum
の乱数を0 - 1の範囲で生成し、それぞれの確率範囲内で発生する数の数を維持しながら、望ましい累積確率に対してそれらをテストします。次に、サンプル・サイズとして最初のステップで見つかったカウントを使用して、各シーケンスをサンプリングします。最後に、これらのサンプルを一緒にシャッフルします。
以下のコードでは、コードのテスト中に何が起こっているのかを簡単に確認できるようにシャッフルする行をコメントアウトしました。
from random import seed, random, sample, shuffle
from itertools import accumulate
def multi_sample(seqs, probs, num):
''' Sample from each sequence in list/tuple `seqs` with the corresponding
probability in list/tuple `probs`. Return a list containing `num` samples
'''
# Compute the cumulative probability
# This really should raise ValueError if aprobs[-1] != 1.0
# and we ought to check that len(seqs) == len(probs)...
aprobs = list(accumulate(probs))
# Determine how many samples to take from each seq
counts = [0] * len(seqs)
for _ in range(num):
x = random()
for i, p in enumerate(aprobs):
if x < p:
break
counts[i] += 1
lst = []
for seq, count in zip(seqs, counts):
lst.extend(sample(seq, count))
#shuffle(lst)
return lst
# Test
N_ITEMS = 1000
items = list(range(N_ITEMS))
vpop = int(N_ITEMS * 0.1)
pop = int(N_ITEMS * 0.3)
#shuffle(items)
vpop_items = items[:vpop]
pop_items = items[vpop:pop]
reg_items = items[pop:]
all_items = (vpop_items, pop_items, reg_items)
list_of_items = multi_sample(all_items, probs=[0.5, 0.35, 0.15], num=100)
print(list_of_items)
# Verify
#list_of_items.sort()
#print(list_of_items)
# Should be ~50
print(sum(1 for x in list_of_items if x < vpop))
# Should be ~35
print(sum(1 for x in list_of_items if vpop <= x < pop))
典型的な出力
[65, 16, 81, 97, 30, 33, 52, 92, 96, 72, 50, 4, 75, 7, 44, 18, 90, 9, 91, 56, 85, 28, 84, 88, 76, 21, 14, 77, 8, 59, 22, 34, 93, 95, 63, 10, 99, 41, 60, 36, 66, 2, 13, 64, 51, 43, 11, 106, 153, 235, 189, 132, 150, 226, 196, 247, 245, 194, 172, 227, 202, 256, 163, 205, 131, 192, 295, 147, 246, 108, 291, 155, 128, 171, 141, 124, 102, 210, 294, 284, 276, 148, 122, 290, 948, 566, 894, 884, 310, 476, 562, 313, 357, 846, 794, 317, 335, 599, 370, 988]
47
37
この関数が失敗することがあるので注意してください:あなたはsample(seq, count)
を呼び出す場合、それはValueError: Sample larger than population
を調達する場所count > len(seq)
。そのため、num
が発生しないように十分に小さくする必要があります。完全に安全であるためには、num
が< =が最小シーケンスの長さよりも大きいことを確認してください。与えられたデータでは、num
は100で、最小のシーケンスはvpop_items
です。これは100個のアイテムを含んでいますので、心配する必要はありません。
この重要な点を私の注意を引くためにAndras Deakに感謝します。
私が先に言ったように、そこには、これを行うためのよりスマートな方法であることがバインドされています:むしろループでcounts
を計算するよりも、我々はは、ちょうど適切な数学を使用して直接それらの数を生成することができるはずですが、私はよ私はそれをする方法を知らない(または覚えていない)のではないかと恐れている。もちろん、は "チート"でした。 :)与えられたデータを使って、vpop_items
から約50個、pop_items
から35個、残りの15個をreg_items
から求めます。したがって、counts
を[50, 35, 15]
に設定し、合計を100に保つように注意しながら、各カウントに小さなランダムな調整を加えることができます。
私が正しくあなたを理解していれば、あなたがp' 'によって与えられた確率で3つのリストからサンプリングしたいです。そして、それぞれのリストからランダムな項目を選択しますか?選択したアイテムを削除する必要がありますか?最後に、 'sample'を実装しようとしましたか? – agold
私はX項目をサンプルしたいです。 100アイテムを言うことができます。私はvpop_itemsから0.5チャンスで上記のすべてのリストから100項目をサンプリングしたいと思います。 pop_itemsから0.35チャンス。そしてreg_itemsから0.15チャンス –
あなたはまだ何か試しましたか? vpopから 'p <0.5'を引き出す場合は0から1までの乱数' p'を、それ以外の場合は 'p <0.85'をpopから引き出し、そうでなければregから引き出します。 'X '回繰り返す。 – Julien