你有对数正态分布的模式和标准偏差。要使用scipy的rvs()方法,必须根据形状参数s参数化分布,这是基本正态分布的标准差sigma,而{},即{},其中{}是基础分布的平均值。在
您指出,进行这种重新参数化需要求解四次多项式。为此,我们可以使用numpy.poly1d类。该类的实例有一个roots属性。在
一个小代数表明exp(sigma**2)是多项式唯一的正实根x**4 - x**3 - (stddev/mode)**2 = 0
其中stddev和{}是对数正态分布的给定标准差和模式,对于该解,scale(即exp(mu))是
^{pr2}$
下面是一个将模式和标准偏差转换为形状和比例的函数: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)
这是样品的标准偏差:In [160]: np.std(sample)
Out[160]: 99.12048952171304
下面是一些matplotlib代码来绘制样本的柱状图,在绘制样本的分布模式下绘制一条垂直线: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]:
柱状图:
如果要使用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的roots算法的健壮性,所以一定要测试各种可能的输入值。或者,您可以使用scipy的解算器来求解x的上述多项式。可以使用以下方法绑定解决方案:max(sqrt(stddev/mode), 1) <= x <= sqrt(stddev/mode) + 1