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

The*_*tor 14 python random numpy

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

在此输入图像描述

现在我需要生成一个随机变量,调用它random_z应该复制上面的分布.

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

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

Pau*_*aul 9

如果你想引导你可以使用random.choice()你观察到的系列.

在这里,我假设你想要比平滑更多,你不关心产生新的极值.

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

训练

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

生产

  1. u以通常的方式生成介于0.0和1.0之间的随机数,例如, random.random()
  2. 返回 S.quantile(u)

如果你想用numpypandas,从快速阅读,它看起来像您可以替换numpy.percentile()在步骤2中.

工作原理:

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

简单的示例代码

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

设S是预先存在的样本.

你将是新的统一随机数

newR将是从S-like分布中提取的新randoms.

>>> import numpy as np
Run Code Online (Sandbox Code Playgroud)

我需要一个可以复制的随机数的样本S.

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

在您的应用程序中,您需要执行其他操作(可能是读取文件)来创建S包含要复制其分布的数据样本的numpy数组.

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

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

>>> S.mean()
0.25296623781420458 # OK
Run Code Online (Sandbox Code Playgroud)

得到最小值和最大值只是为了说明np.percentile是如何工作的

>>> S.min()
6.1091277680105382e-10
>>> S.max()
0.99608676594692624
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

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

>>> u = np.random.random(100)
Run Code Online (Sandbox Code Playgroud)

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

这将有效:

>>> newR = np.percentile(S, (100*u).tolist()) 
Run Code Online (Sandbox Code Playgroud)

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

>>> type(newR)
<type 'list'>

>>> newR = np.array(newR)
Run Code Online (Sandbox Code Playgroud)

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

>>> newR.mean()
0.25549728059744525 # close enough
Run Code Online (Sandbox Code Playgroud)


Ffi*_*ydd 6

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

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()
Run Code Online (Sandbox Code Playgroud)

情节


Joh*_*all 5

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

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

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