生成复制任意分布的随机数

时间:2014-05-13 08:16:27

标签: python numpy random

我有数据,其中我有一个变量z,其中包含大约4000个值(从0.0到1.0),直方图看起来像这样。

enter image description here

现在我需要生成一个随机变量,称之为random_z,它应该复制上面的分布。

到目前为止,我所尝试的是生成一个以1.0为中心的正态分布,以便我可以删除1.0以上的所有内容以获得类似的分布。我一直在使用numpy.random.normal,但问题是我无法将范围设置为0.0到1.0,因为通常正态分布的均值= 0.0且std dev = 1.0。

还有另一种方法可以在Python中生成此发行版吗?

4 个答案:

答案 0 :(得分:9)

如果您想要引导,可以在观察到的系列节目上使用random.choice()

在这里,我假设你想要平滑一点,你并不关心产生新的极端值。

使用pandas.Series.quantile()和统一[0,1]随机数生成器,如下所示。

培训

  • 将随机样本放入pandas系列,调用此系列S

生产

  1. 以通常的方式生成0.0到1.0之间的随机数u,例如, random.random()
  2. return S.quantile(u)
  3. 如果你宁愿使用numpy而不是pandas,快速阅读看起来你可以在步骤2中替换numpy.percentile()

    操作原理:

    从样本S中,pandas.series.quantile()numpy.percentile()用于计算Inverse transform sampling方法的逆累积分布函数。分位数或百分位函数(相对于S)将均匀的[0,1]伪随机数转换为具有样本S的范围和分布的伪随机数。

    简单示例代码

    如果您需要最小化编码并且不想编写和使用仅返回单个实现的函数,那么numpy.percentile最好pandas.Series.quantile

    设S是预先存在的样本。

    你将成为新的统一随机数

    newR将是从S类分布中提取的新randoms。

    >>> import numpy as np
    

    我需要将要复制的随机数的样本放入S

    为了创建一个例子,我将把一些统一的[0,1]随机数提升到第三个幂并调用样本S。通过选择以这种方式生成示例样本,我将事先知道 - 从平均值等于从0到1评估的(x ^ 3)(dx)的定积分 - S的平均值应该是1/(3+1) = 1/4 = 0.25

    在你的应用程序中,你需要做一些其他事情,也许是读取文件 创建一个numpy数组S,其中包含要复制其分布的数据样本。

    >>> S = pow(np.random.random(1000),3)  # S will be 1000 samples of a power distribution
    

    在这里,我将检查S的平均值是否为0.25,如上所述。

    >>> S.mean()
    0.25296623781420458 # OK
    

    获取最小值和最大值以显示np.percentile如何工作

    >>> S.min()
    6.1091277680105382e-10
    >>> S.max()
    0.99608676594692624
    

    numpy.percentile函数将0-100映射到S的范围。

    >>> np.percentile(S,0)  # this should match the min of S
    6.1091277680105382e-10 # and it does
    
    >>> np.percentile(S,100) # this should match the max of S
    0.99608676594692624 # and it does
    
    >>> np.percentile(S,[0,100])  # this should send back an array with both min, max
    [6.1091277680105382e-10, 0.99608676594692624]  # and it does
    
    >>> np.percentile(S,np.array([0,100])) # but this doesn't.... 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib/python2.7/dist-packages/numpy/lib/function_base.py", line 2803, in percentile
        if q == 0:
    ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
    

    如果我们从制服开始生成100个新值,那么这不是很好:

    >>> u = np.random.random(100)
    

    因为它会出错,并且u的比例为0-1,需要0-100。

    这将有效:

    >>> newR = np.percentile(S, (100*u).tolist()) 
    

    工作正常,但如果你想要一个numpy数组,可能需要调整它的类型

    >>> type(newR)
    <type 'list'>
    
    >>> newR = np.array(newR)
    

    现在我们有一个numpy数组。我们来检查新随机值的平均值。

    >>> newR.mean()
    0.25549728059744525 # close enough
    

答案 1 :(得分:6)

使用numpy.random.normal时,您可以传递关键字参数来设置返回数组的均值和标准差。这些关键字参数为loc(平均值)和scale(标准)。

import numpy as np
import matplotlib.pyplot as plt

N = 4000
mean = 1.0
std = 0.5
x = []

while len(x) < N:
    y = np.random.normal(loc=mean, scale=std, size=1)[0]
    if 0.0 <= y <= 1.0:
        x.append(y)

plt.hist(x)
plt.show()

Plot

答案 2 :(得分:5)

如果您可以近似分布的累积密度函数(例如通过采用直方图的cumsum),则从该分布中取样变得微不足道。

Sample uniformly p in interval [0.0,1.0]
Lookup the value of x at which cdf(x) == p

我想这实际上是熊猫正在做的答案。

答案 3 :(得分:4)

你可以使用拒绝抽样:你生成0(= y&lt; = max(f(z))的对(z,y),直到你得到一个y&lt; = f(z)的对。生成的随机数是z。

该方法的优点是它可以用于任何分布,但是在获得有效对(z,y)之前可能需要多次迭代。