这个问题源于一个音乐训练游戏,我必须从12个可用的音高等级中选择一个随机的3音符和弦,但某些音符比其他音符更可能(这样用户可以为较弱的音符训练更多)。
我认为这个问题很简单:将每个重量视为一个线段,将所有线段一个接一个地放置成一个长段,在这个长段上选择一个随机点,记录它所在的重量,冲洗并重复,直到我们有k个项目。
以下Python代码演示了此技术无法产生正确的结果:
# Choose k items from a set of weights
# return set of winning indices
def Choose(W,k):
import random
cumulative = [ sum(W[:i+1]) for i in xrange(len(W)) ]
totalWeight = cumulative[-1]
winners = set()
while len(winners) < k:
rnd = random.uniform(0.0, totalWeight)
# Returns first element of cumulative that is >= rnd
w = next( i for i in xrange(len(cumulative)) if cumulative[i] >= rnd )
winners.add( w )
return winners
def Test(N):
x = [ list(Choose( [5,3,2], 2 )) for i in xrange(int(N/2))]
y = sum(x, [])
z = [y.count(i) for i in (0,1,2) ]
print z
for i in range(10):
Test(10000)
我从3个权重生成5000个随机对[5,3,2] 输出记录每个重量出现的次数 它应该是5000,3000,2000
为了更好的衡量,我进行了10次实验:
python test.py
[4173, 3331, 2496]
[4180, 3367, 2453]
[4193, 3393, 2414]
[4228, 3375, 2397]
[4207, 3388, 2405]
[4217, 3377, 2406]
[4173, 3438, 2389]
[4172, 3378, 2450]
[4174, 3371, 2455]
[4208, 3322, 2470]
所以~4200 vs 3300 vs 2400 不是5000 vs 3000 vs 2000
有没有一种简单的方法可以理解为什么这不起作用?
是否有某种方法可以改变权重,可能是'weight [i] - &gt; ln(weight [i])'或类似的东西会产生正确的结果吗?
如何获得正确的结果? (我更关心代码的清晰度而不是最佳效率)
答案 0 :(得分:2)
答案 1 :(得分:1)
没有用重物替换是一个棘手的问题。
首先,考虑您的直观解决方案。您生成5000对,并且您希望这些对中的5000对包含1.这意味着每对必须包含1.我怀疑这不是您想要或期望的。要获得您期望的分布,您可以先选择1,然后分别选择概率为.6或.4的2或3。
要做我怀疑你要求的事情,你应该做一些像条件泊松采样这样的事情。我不知道有一个Python模块可以做到这一点,尽管几乎肯定有一个。 &#39;采样&#39; R中的包就可以了。我知道网上没有温和的介绍。
从实际的角度来看,只需做你正在做的事情并调整权重,使概率接近你想要的。对于你想要做的事情,似乎没有必要采用精确的概率。
如果你想要一个简单的方法(效率非常低效)来实现你想要的东西:
1)标准化权重,使所有权重的总和加起来为所需的样本大小。用你的例子.5 + .3 + .2 = 2,因此标准化权重将是[1.,.6,.4]。
2)让p_i为第i个权重视为概率(它们都必须小于或等于1或问题是不可能的。通过选择具有概率p_i的第i个元素来选择样本
3)如果绘制的样本的大小正确输出,否则再次绘制
这是一个快速代码示例
import random
def sample(weights, sample_size):
w = float(sum(weights))
normweights = [x * sample_size / w for x in weights]
samp = [random.random() < pi for pi in normweights]
while sum(samp) != sample_size:
samp = [random.random() < pi for pi in normweights]
return [i for i,b in enumerate(samp) if b]
print(sample([.5,.3,.2], 2))
编辑: 好的,上面的算法很糟糕。我会尝试记住如何正确地做到这一点。