如何生成具有预定义概率分布的随机数?

时间:2018-06-26 20:07:54

标签: python numpy probability probability-density probability-distribution

我想在python中实现一个函数(使用numpy),该函数采用数学函数(例如下面的p(x) = e^(-x))作为输入并生成随机数,并根据该随机数进行分配数学函数的概率分布。我需要绘制它们,以便我们可以看到分布。

实际上,我确实需要一个随机数生成器函数来将以下两个数学函数作为输入,但是如果可以使用其他函数,为什么不呢?

1)p(x) = e^(-x)
2)g(x) = (1/sqrt(2*pi)) * e^(-(x^2)/2)

有人知道这在python中如何实现吗?

2 个答案:

答案 0 :(得分:4)

NumPy提供了a wide range of probability distributions

第一个功能是带有参数1的exponential distribution

np.random.exponential(1)

第二个是normal distribution,平均值为0,方差为1。

np.random.normal(0, 1)

请注意,在这两种情况下,参数都是可选的,因为这些是这些分布的默认值。

作为旁注,您还可以在random模块中分别以random.expovariaterandom.gauss的形式找到这些分布。

更多一般分布

尽管NumPy可能满足您的所有需求,但请记住,您始终可以计算分布的倒数cumulative distribution function并从uniform distribution输入值。

inverse_cdf(np.random.uniform())

例如,如果NumPy不提供指数分布,则可以执行此操作。

exponential = lambda: -np.log(-np.random.uniform())

如果遇到不容易计算CDF的分布,请考虑filippo's great answer

答案 1 :(得分:2)

对于简单的分布(如所需的分布),或者如果您易于转换为封闭形式的CDF,则可以按照Olivier的答案正确指出的那样,在NumPy中找到大量采样器。

对于任意分布,可以使用马尔可夫链蒙特卡洛采样方法。

这些算法中最简单且可能更容易理解的变量是Metropolis采样。

基本思想如下:

  • 从随机点x开始并采取随机步骤xnew = x + delta
  • 在起点p(x)和新的p(xnew)中评估所需的概率分布
  • 如果新点更有可能p(xnew)/p(x) >= 1接受此举
  • 如果新点的可能性较小,则根据新点的可能性 1 随机决定接受还是拒绝
  • 从这一点开始的新步骤并重复循环

可以显示,例如Sokal 2 ,该方法采样的点遵循接受概率分布。

可以在PyMC3包中找到Python中Montecarlo方法的广泛实现。

示例实现

这里只是一个玩具示例,目的只是向您展示基本思想,而不以任何方式作为参考实现。请认真阅读成熟的软件包。

def uniform_proposal(x, delta=2.0):
    return np.random.uniform(x - delta, x + delta)

def metropolis_sampler(p, nsamples, proposal=uniform_proposal):
    x = 1 # start somewhere

    for i in range(nsamples):
        trial = proposal(x) # random neighbour from the proposal distribution
        acceptance = p(trial)/p(x)

        # accept the move conditionally
        if np.random.uniform() < acceptance:
            x = trial

        yield x

让我们看看它是否适用于一些简单的发行版

高斯混合

def gaussian(x, mu, sigma):
    return 1./sigma/np.sqrt(2*np.pi)*np.exp(-((x-mu)**2)/2./sigma/sigma)

p = lambda x: gaussian(x, 1, 0.3) + gaussian(x, -1, 0.1) + gaussian(x, 3, 0.2)
samples = list(metropolis_sampler(p, 100000))

metropolis gaussians sum

可爱

def cauchy(x, mu, gamma):
    return 1./(np.pi*gamma*(1.+((x-mu)/gamma)**2))

p = lambda x: cauchy(x, -2, 0.5)
samples = list(metropolis_sampler(p, 100000))

metropolis cauchy

任意函数

您实际上不必从适当的概率分布中采样。您可能只需要强制执行一个有限的域,即可在其中采样随机步骤 3

p = lambda x: np.sqrt(x)
samples = list(metropolis_sampler(p, 100000, domain=(0, 10)))

metropolis sqrt

p = lambda x: (np.sin(x)/x)**2
samples = list(metropolis_sampler(p, 100000, domain=(-4*np.pi, 4*np.pi)))

metropolis sinc

结论

关于提案的分布,收敛,相关性,效率,应用,贝叶斯形式主义,其他MCMC采样器等,还有很多话要说。 我认为这不是合适的地方,而且有很多资料比我在网上可以找到的更好。


  1. 此处的想法是倾向于概率较高的勘探,但仍会关注低概率区域,因为它们可能导致其他峰值。基本是建议提案分布的选择,即如何选择要探索的新点。步长太小可能会限制您到发行版的有限区域,步长太大可能会导致效率非常低下。

  2. 面向物理。如今,贝叶斯形式主义(Metropolis-Hastings)受到人们的青睐,但是恕我直言,对于初学者而言,它有点难掌握。在线上有很多教程,请参见例如this one来自杜克大学。

  3. 未显示实现不会增加太多混乱,但是很简单,您只需要将试验步骤包装在域边缘或使所需函数在域外变为零即可。