我需要从Python中的对数正态分布生成伪随机数。问题是我从模式和 lognormal 分布的标准偏差开始。我没有对数正态分布的均值或中位数,也没有基础正态分布的任何参数。
numpy.random.lognormal
取基础正态分布的均值和标准差。我试图从我的参数计算这些,但最后用四次函数。它有一个解决方案,但我希望有一个更简单的方法来做到这一点。
scipy.stats.lognorm
采用我不了解的参数。我不是母语为英语的人,文档也没有意义。
答案 0 :(得分:8)
您具有对数正态分布的模式和标准差。要使用scipy rvs()
的{{1}}方法,您必须根据形状参数lognorm
对分布进行参数化,这是基础正态分布的标准差s
,以及sigma
,即scale
,其中exp(mu)
是基础分布的平均值。
您指出进行此重新参数化需要求解四次多项式。为此,我们可以使用mu
类。该类的实例具有numpy.poly1d
属性。
一个小代数表明roots
是多项式的唯一正实根
exp(sigma**2)
其中x**4 - x**3 - (stddev/mode)**2 = 0
和stddev
是对数正态分布的给定标准差和模式,对于该解决方案,mode
(即scale
)< / p>
exp(mu)
这是一个将模式和标准偏差转换为形状和比例的函数:
scale = mode*x
例如,
def lognorm_params(mode, stddev):
"""
Given the mode and std. dev. of the log-normal distribution, this function
returns the shape and scale parameters for scipy's parameterization of the
distribution.
"""
p = np.poly1d([1, -1, 0, 0, -(stddev/mode)**2])
r = p.roots
sol = r[(r.imag == 0) & (r.real > 0)].real
shape = np.sqrt(np.log(sol))
scale = mode * sol
return shape, scale
使用计算出的参数生成样本:
In [155]: mode = 123
In [156]: stddev = 99
In [157]: sigma, scale = lognorm_params(mode, stddev)
以下是样本的标准偏差:
In [158]: from scipy.stats import lognorm
In [159]: sample = lognorm.rvs(sigma, 0, scale, size=1000000)
这里有一些matplotlib代码用于绘制样本的直方图,并在绘制样本的分布模式下绘制垂直线:
In [160]: np.std(sample)
Out[160]: 99.12048952171304
直方图:
如果您想使用In [176]: tmp = plt.hist(sample, normed=True, bins=1000, alpha=0.6, color='c', ec='c')
In [177]: plt.xlim(0, 600)
Out[177]: (0, 600)
In [178]: plt.axvline(mode)
Out[178]: <matplotlib.lines.Line2D at 0x12c5a12e8>
代替numpy.random.lognormal()
生成示例,则可以执行以下操作:
scipy.stats.lognorm.rvs()
我没有研究过In [200]: sigma, scale = lognorm_params(mode, stddev)
In [201]: mu = np.log(scale)
In [202]: sample = np.random.lognormal(mu, sigma, size=1000000)
In [203]: np.std(sample)
Out[203]: 99.078297384090902
poly1d
算法的稳健性,因此请务必测试各种可能的输入值。或者,您可以使用scipy中的求解器来求解roots
的上述多项式。您可以使用以下方法绑定解决方案:
x
答案 1 :(得分:1)
5. How to use Multi-touch in Android 2: Part 2, Building the Touch example [zdnet.com](令人困惑)将指数函数应用于正态分布的结果。维基百科给出了参数之间的关系
其中μ和σ是您称之为“基础正态分布”的平均值和标准差,以及 m 和 v 是对数正态分布的均值和方差。
现在,您所说的是对数正态分布的模式和标准差。方差 v 只是标准差的平方。从模式转到 m 比较棘手:再次引用维基百科文章,如果均值为,则模式为。从这一点,以及上面,我们可以推断出
其中 n 是对数正态分布的模式, v , m 如上所述。这减少到四分之一,
或
其中 u = m 2 。我怀疑这是你在问题中提到的那个四分之一。它可以解决,但像大多数四分相一样,解决方案的根本形式是log-normal distribution。最实用的方法可能是将 n 和 v 的数值插入上面,然后使用 numeric 求解器查找正根。
抱歉,我无法提供更多帮助。这实际上是一个数学问题,而不是一个编程问题;您可以在giant hairball上获得更多有用的答案。
答案 2 :(得分:0)
为@WarrenWeckesser提供了一个很好的答案,以下函数提供了确切的返回值,以根据模式和SD重新设置对数正态分布:
import numpy as np
def lognorm_params(mode, stddev):
a = stddev**2 / mode**2
x = 1/4*np.sqrt(-(16*(2/3)**(1/3)*a)/(np.sqrt(3)*np.sqrt(256*a**3+27*a**2)-9*a)**(1/3) +
2*(2/3)**(2/3)*(np.sqrt(3)*np.sqrt(256*a**3+27*a**2)-9*a)**(1/3)+1) + \
1/2*np.sqrt((4*(2/3)**(1/3)*a)/(np.sqrt(3)*np.sqrt(256*a**3+27*a**2)-9*a)**(1/3) -
(np.sqrt(3)*np.sqrt(256*a**3+27*a**2)-9*a)**(1/3)/(2**(1/3)*3**(2/3)) +
1/(2*np.sqrt(-(16*(2/3)**(1/3)*a)/(np.sqrt(3)*np.sqrt(256*a**3+27*a**2)-9*a)**(1/3) +
2*(2/3)**(2/3)*(np.sqrt(3)*np.sqrt(256*a**3+27*a**2)-9*a)**(1/3)+1))+1/2) + \
1/4
shape = np.sqrt(np.log(x))
scale = mode * x
return shape, scale
本质上,我只是计算了四次方程的精确解。优点是该解决方案是a)精确,b)更快和c)可矢量化的。就像@WarrenWeckesser的回答一样,对于给定的模式和SD,此函数返回scipy函数scipy.stats.lognormal()使用的参数形状和比例。