生成二项分布的混合

时间:2013-03-14 15:13:57

标签: python statistics distribution random-sample discretization

我想生成二项分布的混合。为什么我需要它是因为 我希望得到高斯分布的正常离散混合。有没有 scipy库可用,或者请你指导我的算法。

我一般都知道预定义的发行版可以使用ppf。但为此 功能我认为没有任何直接使用ppf的方法。

每次采样并混合它们似乎也有问题,因为我不知道如何 我必须从不同的发行版中选择许多实例。

最后我想拥有的是这样的: enter image description here

3 个答案:

答案 0 :(得分:3)

这是一种生成二项式(和其他)分布的任意混合的简单方法。 它依赖于一个事实,如果你想从混合物中获取样品(Nsamp) P(x)= sum(w [i] * P_i(x),i = 1..Nmix),那么你可以通过抽样来做到这一点 每个P_i(x)的Nsamp。然后以概率w [i]得到另一个等于i的随机变量的另一个Nsamp样本。该随机变量可用于选择给定样本中的哪一个P_i(x):

import numpy as np,numpy.random, matplotlib.pyplot as plt

#parameters of the binomial distributions: pairs of (n,p)
binomsP = np.array([.5, .5, .5])
binomsCen = np.array([15, 45, 95]) # centers of binomial distributions
binomsN = (binomsCen/binomsP).astype(int)

fractions = [0.2, 0.3, 0.5]
#mixing fractions of the binomials
assert(sum(fractions)==1)

nbinoms = len(binomsN)
npoints = 10000
cumfractions = np.cumsum(fractions)
def mapper(x):
    # convert the random number between 0 and 1 to
    # the ID of the distribution according to the mixing fractions
    return np.digitize(x, cumfractions)

x0 = np.random.binomial(binomsN[None, :],
        binomsP[None, :], size=(npoints, nbinoms))

x = x0[:, mapper(np.random.uniform(size=npoints))]
plt.hist(x, bin=150, range=(0, 150))

enter image description here

答案 1 :(得分:1)

除非您找到一种计算逆cdf的智能方法(在这种情况下请告诉我们!),否则拒绝采样是一种可靠的方法。 wikipedia entry给出了一般性描述。我在实践中发现的,你需要对“工具”有点小心。分配:特别是它不应该比目标分布快得多地衰减 - 如果确实如此,你可能会失去尾巴的贡献。

我这样做的方式,我从一个扁平的乐器发行开始:生成一对统一的随机数xy,其中y来自[0,1],x来自[0, L),其中L足够大。然后比较ycdf(x),重复直到收敛。如果有效,那么你就完全了。如果这还不够好,请使用非平坦的乐器分布:如果混合物的尾部是高斯分布的,那么你最好使用高斯分布。

作为旁注,如果您正在处理二项分布,则需要注意上溢/下溢 - 根据参数,您可能需要使用高斯近似。

答案 2 :(得分:0)

感谢@ sega_sai,@ askewchan和@Zhenya, 我自己制作了代码,而且由于实现这一点,我认为这是最多的 高效的。有两个函数,第一个使“binoNumber”二项分布的混合都具有相同的N =最大 - 最小参数且相同的p = 0.5但是根据我为它们生成的随机中心移位。

global binoInitiated
binoInitiated=False;
def binoMixture(minimum,maximum,sampleSize):
    global centers
    binoNumber=10;
    if (not binoInitiated):
        centers=np.random.randint(minimum,maximum+1,binoNumber)
    sigma=maximum-minimum-2
    sam=np.array([]);
    while sam.size<sampleSize:
        i=np.random.choice(binoNumber);
        temp=np.random.binomial(sigma, 0.5,1)+centers[i]-sigma/2+1
        sam=np.append(sam,temp)
    return sam

此功能用于绘制预先制作的分布的近似PDF。 感谢@EnricoGiampieri,我使用他的代码来完成这一部分。

def binoMixtureDrawer(minimum,maximum):
    global binoInitiated
    global centers
    sam=binoMixture(minimum,maximum,50000)    
    # this create the kernel, given an array it will estimate the probability over that values
    kde = gaussian_kde( sam )
    # these are the values over wich your kernel will be evaluated
    dist_space = linspace( min(sam), max(sam), 500 )
    # plot the results
    fig.plot( dist_space, kde(dist_space),'g')