【发布时间】:2014-07-25 06:46:04
【问题描述】:
这个问题源于一个音乐训练游戏,我必须从 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 个权重 [5,3,2] 生成 5000 个随机对 输出记录每个权重出现的次数 应该是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] -> ln(weight[i])' 或类似的东西,这样可以得到正确的结果?
如何获得正确的结果? (我更关心代码的清晰度而不是最佳效率)
【问题讨论】:
标签: python random probability combinatorics weighted