【问题标题】:How do I get a lognormal distribution in Python with Mu and Sigma?如何使用 Mu 和 Sigma 在 Python 中获得对数正态分布?
【发布时间】:2012-02-10 20:40:16
【问题描述】:

我一直在尝试使用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: 产生正确 0.7434 结果的工作 lognorm 实现。

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

【问题讨论】:

  • 您能解释一下您对“分配的结果”的理解吗?
  • @joaquin 我添加了一个代码示例,显示了我所拥有的以及我期望它产生的结果。
  • @EricLubow:我认为您可能误解了在这种情况下 mean 和 stddev 的含义。对于对数正态分布,它们是变量的对数的平均值和标准差 。如果一个变量是对数正态分布的,则意味着该变量的对数是正态分布的。
  • @talonmies 我知道使用平均值和标准差意味着使用变量日志的平均值和标准差。我在 Python 中手动编写了 lognorm 函数(见上文),并且能够得到正确的答案。这就是让我相信 SciPy 的实现可能会有所不同的原因,因为我在 R 和 Excel 中得到了正确的答案。如果我的实施有误,我肯定想知道。
  • @EricLubow:您几乎重新实现了what scipy uses internally Lucas 的答案似乎是正确的。有关使用示例,请参阅 my answer

标签: python statistics scipy


【解决方案1】:

听起来您想从已知参数实例化“冻结”分布。在您的示例中,您可以执行以下操作:

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

这将为您提供具有您指定的均值和标准差的对数范数分布对象。然后,您可以像这样获取 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))

这是你的想法吗?

【讨论】:

  • 错字:必须用“np.linspace”代替“np.inspace”
  • 不应该是“dist=lognorm([stddev**2],loc=mean)”,即方差而不是标准差作为参数吗?我在 scipy 文档中没有找到参数说明,你知道吗?
  • 我原本以为是我自己(见我贴的答案的第一版)——但从计算来看,参数似乎是“形状参数”,而不是方差,所以标准差是在这种情况下正确的论点。
  • 方差也可以称为“形状”。在概率论中,甚至称为形状的峰态(4阶矩),但是,它们确实使用标准差(我已经进行了一些检查)。这是我的 +1
  • 所以根据下面卢卡斯的回答,这是错的吧?平均值不应该在分布的最左边,它应该在峰值的右边,对吧?
【解决方案2】:

我知道这有点晚了(差不多一年!),但我一直在对 scipy.stats 中的 lognorm 函数进行一些研究。很多人似乎对输入参数感到困惑,所以我希望能帮助这些人。上面的例子几乎是正确的,但我发现将平均值设置为位置(“loc”)参数很奇怪——这表明 cdf 或 pdf 在值大于平均值之前不会“起飞”。此外,均值和标准差参数应分别采用 exp(Ln(mean)) 和 Ln(StdDev) 的形式。

简单来说,参数就是(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

【讨论】:

  • 如果我猜对了:在数学符号中,如果 X 是 N(mu,sigma),那么 Y=exp(X) 是 LogN(mu,sigma)。要在 scipy 中获得 X,我会使用 norm(mu,sigma),但要获得 Y,我会使用 lognorm(sigma, 0, exp(mu))。这很尴尬......
  • 顺便说一句:我发现你的帖子很有帮助,但不是 scipy 帮助。对于每一个分布,您确实必须尝试参数的含义可能是什么(例如,对于均匀分布 U(a,b),其中 [a,b] 是您需要的区间 uniform(loc=a, scale =ba),这里的 loc 不是平均数,也不是标准差...)
  • @ElmarZander:你可以使用lognorm(s=sigma, scale=math.exp(mu)。见stackoverflow.com/a/36714419/1587329
  • @Lucas 迟到总比不到好 ;) 非常感谢您。非常有用的总结。
【解决方案3】:

更晚了,但万一它对其他人有帮助:我发现 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).

【讨论】:

  • 对于第一种情况,他们没有为我返回相同的结果,其中 x=2039.9337873, mean=7.6901, std_dev=0.6772
  • 啊,我忘了在我的 excel 公式中添加 Ln(mean)。已在答案中更正。
【解决方案4】:

@lucas' answer 的用法向下拍。作为代码示例,您可以使用

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

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:
      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。 p>

      虽然 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
      

      其中 Z0 = 0。这个方程的形式为:

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

      如果您可以在脑海中可视化方程式,则应该清楚方程式 4 中的比例、形状和位置参数是:abx0 ,分别。这意味着在等式 3 中,比例、形状和位置参数分别为:exp(mu)sigma 和零。

      如果你不能很清楚地看到它,让我们将公式 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 并且 sigma 影响 f(Z) 的速度时,f(Z) 有一个常数值em> 曲线远离水平轴。因此 SciPy 的“形状”是 sigma

      【讨论】:

      • 想解释一下为什么这是问题的答案?
      • 我发现这与 Excel 函数 LOGNORM.DIST(x, Mu, Sigma, TRUE) 1:1 映射
      猜你喜欢
      • 1970-01-01
      • 2016-05-02
      • 2013-09-15
      • 1970-01-01
      • 2015-02-06
      • 2020-05-20
      • 1970-01-01
      • 2021-03-14
      • 2016-05-02
      相关资源
      最近更新 更多