我有数据,其中我有一个变量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中生成此发行版吗?
答案 0 :(得分:9)
如果您想要引导,可以在观察到的系列节目上使用random.choice()
。
在这里,我假设你想要平滑一点,你并不关心产生新的极端值。
使用pandas.Series.quantile()
和统一[0,1]随机数生成器,如下所示。
培训
S
生产
u
,例如,
random.random()
S.quantile(u)
如果你宁愿使用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()
答案 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)之前可能需要多次迭代。