scipy 如何在Python中用Mu和Sigma得到对数正态分布?

mspsb9vt  于 2022-11-09  发布在  Python
关注(0)|答案(7)|浏览(348)

我一直在尝试使用Scipy得到lognormal发行版的结果。我已经有了Mu和Sigma,所以我不需要做任何其他的准备工作。如果我需要更具体的(我正努力用我有限的统计知识),我会说我在寻找累积函数(Scipy下的cdf)。问题是,我不知道如何仅使用0-1范围内的平均值和标准差来实现这一点(即返回的答案应该是0-1)。我也不确定应该使用dist中的哪个方法来获得答案。我已经尝试阅读文档并查看了SO,但是相关的问题(如thisthis)似乎没有提供我想要的答案。
这是一个我正在使用的代码示例。谢谢。

from scipy.stats import lognorm
stddev = 0.859455801705594
mean = 0.418749176686875
total = 37
dist = lognorm.cdf(total,mean,stddev)

更新日期:

经过一番努力和研究,我又前进了一步。但我还是得到了错误的答案。新的代码如下。根据R和Excel,结果应该是 .7434,但显然不是这样。是不是我遗漏了什么逻辑缺陷?

dist = lognorm([1.744],loc=2.0785)
dist.cdf(25)  # yields=0.96374596, expected=0.7434

更新2:运行lognorm实现,生成正确的0.7434结果。

def lognorm(self,x,mu=0,sigma=1):
   a = (math.log(x) - mu)/math.sqrt(2*sigma**2)
   p = 0.5 + 0.5*math.erf(a)
   return p
lognorm(25,1.744,2.0785)
> 0.7434
bgtovc5b

bgtovc5b1#

我知道现在说有点晚了(快一年了!)但是我一直在scipy. stats中对lognorm函数做一些研究。很多人似乎对输入参数感到困惑,所以我希望能帮助这些人。上面的例子几乎是正确的,但我觉得把平均值设定为(“loc”)参数-这表示cdf或pdf不会“起飞”,直到值大于平均值。此外,平均值和标准偏差参数的形式应为exp(Ln(平均值))和Ln(标准差)。
简单地说,参数为(x、shape、loc、scale),参数定义如下:
loc -没有等价项,它将从数据中减去,因此0将成为数据范围的下确界。
scale - exp μ,其中μ是变量对数的均值。(拟合时,通常使用数据对数的样本均值。)
shape -变量对数的标准差。
我和大多数使用这个功能的人一样经历了同样的挫折,所以我分享了我的解决方案。只是要小心,因为如果没有一个资源纲要,解释是不是很清楚。
有关更多信息,我发现以下来源很有帮助:

这里有一个例子,摘自@serv-inc的回答,张贴在这个页面here:

import math
from scipy import stats

# standard deviation of normal distribution

sigma = 0.859455801705594

# mean of normal distribution

mu = 0.418749176686875

# hopefully, total is the value where you need the cdf

total = 37

frozen_lognorm = stats.lognorm(s=sigma, scale=math.exp(mu))
frozen_lognorm.cdf(total) # use whatever function and value you need here
qmb5sa22

qmb5sa222#

听起来你想从已知参数示例化一个“冻结”的分布。在你的例子中,你可以这样做:

from scipy.stats import lognorm
stddev = 0.859455801705594
mean = 0.418749176686875
dist=lognorm([stddev],loc=mean)

这将给予你一个lognorm分布对象,其中包含你指定的均值和标准差。然后你可以得到pdf或cdf,如下所示:

import numpy as np
import pylab as pl
x=np.linspace(0,6,200)
pl.plot(x,dist.pdf(x))
pl.plot(x,dist.cdf(x))

这就是你想要的吗?

72qzrwbm

72qzrwbm3#

from math import exp
from scipy import stats

def lognorm_cdf(x, mu, sigma):
    shape  = sigma
    loc    = 0
    scale  = exp(mu)
    return stats.lognorm.cdf(x, shape, loc, scale)

x      = 25
mu     = 2.0785
sigma  = 1.744
p      = lognorm_cdf(x, mu, sigma)  #yields the expected 0.74341

与Excel和R类似,上述lognorm_cdf函数使用 musigma 将对数正态分布的CDF参数化。
虽然SciPy使用 shapelocscale 参数来表征其概率分布,但对于对数正态分布,我发现在变量层面上考虑这些参数比在分布层面上考虑要稍微容易一些。
对数正态变量 X 与正态变量 Z 的关系如下:

X = exp(mu + sigma * Z)              #Equation 1

其与以下内容相同:

X = exp(mu) * exp(Z)**sigma          #Equation 2

这可以偷偷地重写如下:

X = exp(mu) * exp(Z-Z0)**sigma       #Equation 3

其中 * Z 0 * = 0。该等式的形式为:

f(x) = a * ( (x-x0)**b )           #Equation 4

如果您可以在头脑中可视化方程式,则应清楚方程式4中的比例、形状和位置参数为:这意味着在等式3中,比例、形状和位置参数是:exp(μ)、* σ * 和零。
如果你不能很清楚地看到这一点,让我们将公式2改写为一个函数:

f(Z) = exp(mu) * exp(Z)**sigma      #(same as Equation 2)

然后看看 musigmaf(Z) 的影响。下图保持 sigma 不变,改变 mu。你应该看到 mu 垂直缩放 f(Z)。然而,它是以非线性方式进行的;将 mu 从0改变为1的影响小于将 mu 从1改变为2的影响。从等式2中我们看到 exp(mu) 实际上是线性缩放因子。因此SciPy的“尺度”是 exp(mu)

下一张图中,mu 保持不变,而 sigma 变化,你会看到 f(Z) 的形状发生了变化,也就是说,当 Z=0时,f(Z) 是一个常量,而 sigma 会影响 f(Z) 曲线远离水平轴的速度,因此SciPy的“形状”是 sigma

ippsafx7

ippsafx74#

更晚了,但以防对其他人有帮助:我发现Excel的

LOGNORM.DIST(x,Ln(mean),standard_dev,TRUE)

提供了与python相同的结果

from scipy.stats import lognorm
lognorm.cdf(x,sigma,0,mean)

同样,Excel的

LOGNORM.DIST(x,Ln(mean),standard_dev,FALSE)

似乎与Python的

from scipy.stats import lognorm
lognorm.pdf(x,sigma,0,mean).
qxgroojn

qxgroojn5#

@lucas的答案的用法很简单。

import math
from scipy import stats

# standard deviation of normal distribution

sigma = 0.859455801705594

# mean of normal distribution

mu = 0.418749176686875

# hopefully, total is the value where you need the cdf

total = 37

frozen_lognorm = stats.lognorm(s=sigma, scale=math.exp(mu))
frozen_lognorm.cdf(total) # use whatever function and value you need here
vecaoik1

vecaoik16#

对数正态分布的已知均值和标准差

如果已知对数正态分布的平均值mu和标准差sigma,我们可以通过以下方法求出scipy.stats.lognorm分布。在这种情况下,我们需要根据已知的musigma计算stats.lognorm参数:

import numpy as np
from scipy import stats

mu = 10
sigma = 3

a = 1 + (sigma / mu)**2
s = np.sqrt(np.log(a))
scale = mu / np.sqrt(a)

这是通过研究stats.lognorm.stats方法中方差和平均值计算的实现,并从本质上逆转它(求解输入)而获得的。
然后我们可以初始化冻结的分发示例

distr = stats.lognorm(s, 0, scale)

# generate some randomvals

randomvals = distr.rvs(1_000_000)

# calculate mean and variance using the dedicated method

mu_stats, var_stats = distr.stats("mv")

比较来自distr.stats的输入、随机变量和分析解的平均值和标准差:

print(f"""
                 Mean    Std
----------------------------
Input:         {mu:6.2f} {sigma:6.2f}
Randomvals:    {randomvals.mean():6.2f} {randomvals.std():6.2f}
lognorm.stats: {mu_stats:6.2f} {np.sqrt(var_stats):6.2f}
""")

                 Mean    Std
----------------------------
Input:          10.00   3.00
Randomvals:     10.00   3.00
lognorm.stats:  10.00   3.00

根据stats.lognorm和随机值直方图绘制PDF:

import holoviews as hv
hv.extension('bokeh')

x = np.linspace(0, 30, 301)
counts, _ = np.histogram(randomvals, bins=x)
counts = counts / counts.sum() / (x[1] - x[0])

(hv.Histogram((counts, x)) 

* hv.Curve((x, distr.pdf(x))).opts(color="r").opts(width=900))

ljo96ir5

ljo96ir57#

如果你读到这篇文章,只是想得到一个行为类似于R中lnorm的函数。那么,把你自己从愤怒中解脱出来,使用numpy的numpy.random.lognormal

相关问题