Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从size-N(概率加权)集生成随机size-k子集_Python_Random_Probability_Combinatorics_Weighted - Fatal编程技术网

Python 从size-N(概率加权)集生成随机size-k子集

Python 从size-N(概率加权)集生成随机size-k子集,python,random,probability,combinatorics,weighted,Python,Random,Probability,Combinatorics,Weighted,这个问题源于一个音乐训练游戏,我必须从12个可用的音调类中随机选择一个3个音符的和弦,但某些音符比其他音符更可能出现(因此用户可以为较弱的音符训练更多) 我认为这个问题很简单:把每一个砝码看作一个线段,把所有的段一个接一个地放在一个长的段上,在这个长段上选取一个随机点,记录它的重量,冲洗和重复,直到我们有K项。< /P> 以下Python代码演示了此技术不会产生正确的结果: # Choose k items from a set of weights # return set of winnin

这个问题源于一个音乐训练游戏,我必须从12个可用的音调类中随机选择一个3个音符的和弦,但某些音符比其他音符更可能出现(因此用户可以为较弱的音符训练更多)

我认为这个问题很简单:把每一个砝码看作一个线段,把所有的段一个接一个地放在一个长的段上,在这个长段上选取一个随机点,记录它的重量,冲洗和重复,直到我们有K项。< /P> 以下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)
约4200对3300对2400 不是5000对3000对2000

有没有一个简单的方法来理解为什么这不起作用

是否有某种方法可以转换权重,可能是'weight[i]>ln(weight[i])或类似的东西,从而给出正确的结果

如何获得正确的结果?(我更关心代码的清晰性,而不是最佳效率)

与p参数一起使用:

np.random.choice(3, size=1000, p=[0.5, 0.3, 0.2])

现在再试一次,看看你得到了什么。

不使用权重替换采样是一个棘手的问题

首先,考虑你的直觉解决方案。生成5000对,其中5000对包含1。这意味着每对必须包含1。我怀疑这不是你想要或期望的。要得到您期望的分布,您可以先选择1,然后分别选择概率为.6或.4的2或3

要做我怀疑你要求的事情,你应该做一些类似条件泊松抽样的事情。我不知道有哪个Python模块可以做到这一点,尽管几乎可以肯定有一个。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))
随机导入
def样本(重量、样本大小):
w=浮动(总和(重量))
normweights=[x*样本大小/w代表x的重量]
samp=[random.random()
而sum(samp)!=样本大小:
samp=[random.random()
返回[i表示枚举(samp)中的i,b,如果b]
打印(示例([5,3,2],2))
编辑:
好的,上面的算法是胡说八道。我会尽量记住如何正确操作。

他似乎想要
np.random.choice(2,size=1000,replace=False,p=[0.5,0.3,0.2])
,即从3个项目中选择两个。谢谢Emre,Numpy充满了惊喜!不幸的是,我将使用不支持numpy的IronPython。是的,我内心的数学家一直在回避我,试图解决抽象问题。你说得对,在我的特殊情况下,我不需要比我所拥有的更精确的东西。不过我很好奇!如果你在一所大学或有机会上大学,你可以看看Yves Tille的“采样算法”。它会告诉你如何计算概率(这并不简单,但会让你内心的数学家感到有趣)
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))