【问题标题】:How do you create a logit-normal distribution in Python?如何在 Python 中创建 logit 正态分布?
【发布时间】:2020-06-25 09:33:33
【问题描述】:

this post 之后,我尝试通过创建LogitNormal 类来创建logit 正态分布:

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import logit
from scipy.stats import norm, rv_continuous


class LogitNormal(rv_continuous):
    def _pdf(self, x, **kwargs):
        return norm.pdf(logit(x), **kwargs)/(x*(1-x))


class OtherLogitNormal:
    def pdf(self, x, **kwargs):
        return norm.pdf(logit(x), **kwargs)/(x*(1-x))


fig, ax = plt.subplots()
values = np.linspace(10e-10, 1-10e-10, 1000)
sigma, mu = 1.78, 0
ax.plot(
    values, LogitNormal().pdf(values, loc=mu, scale=sigma), label='subclassed'
)
ax.plot(
    values, OtherLogitNormal().pdf(values, loc=mu, scale=sigma),
    label='not subclassed'
)
ax.legend()
fig.show()

但是,LogitNormal 类不会产生预期的结果。当我不继承 rv_continuous 时,它可以工作。这是为什么?我需要子类化才能工作,因为我还需要它附带的其他方法,例如rvs

顺便说一句,我在 Python 中创建自己的 logit 正态分布的唯一原因是因为我能找到的该分布的唯一实现来自 PyMC3 packageTensorFlow package,两者都很重/ 如果你只需要它们来完成那一项功能,那就大材小用了。我已经尝试过PyMC3,但显然它不适用于scipy,我想,它总是让我崩溃。但这是一个完全不同的故事。

【问题讨论】:

  • 你为什么打电话给LogitNormal().pdf?我想你应该打电话给LogitNormal()._pdf。因为_pdf 是您在LogitNormal 类中调用唯一方法的方式。
  • 因为重新定义 _pdf_cdf 是您根据文档 docs.scipy.org/doc/scipy/reference/generated/… 以及我在问题中链接的帖子对 rv_continuous 进行子类化的方式。
  • 根据源码rv_continuous.pdf方法使用locscale参数对x值进行转换。我猜你会得到与默认值相同的结果:sigma, mu = 1, 0.
  • 我愿意。我糊涂了。这是什么意思?
  • 假设问题源于双重计算。 rv_continuous.pdf 计算概率密度函数。 scipy.stats.norm.pdf 计算概率密度函数。我想这就是我能说的全部,因为我不熟悉这些功能。祝你好运。

标签: python scipy statistics distribution


【解决方案1】:

如果您查看source code of the pdf method,您会注意到在调用_pdf 时没有scaleloc 关键字参数。

   if np.any(cond):
        goodargs = argsreduce(cond, *((x,)+args+(scale,)))
        scale, goodargs = goodargs[-1], goodargs[:-1]
        place(output, cond, self._pdf(*goodargs) / scale)

这会导致覆盖 _pdf 方法中的 kwargs 始终是一个空字典。

如果您仔细查看代码,您还会注意到缩放和位置由pdf 处理,而不是_pdf

在您的情况下,_pdf 方法调用norm.pdf,因此locscale 参数必须以某种方式在LogitNormal._pdf 中可用。

例如,您可以在创建LogitNormal 的实例时传递scaleloc 并将值存储为类属性:

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import logit
from scipy.stats import norm, rv_continuous


class LogitNormal(rv_continuous):
    def __init__(self, scale=1, loc=0):
        super().__init__(self)
        self.scale = scale
        self.loc = loc

    def _pdf(self, x):
        return norm.pdf(logit(x), loc=self.loc, scale=self.scale)/(x*(1-x))


fig, ax = plt.subplots()
values = np.linspace(10e-10, 1-10e-10, 1000)
sigma, mu = 1.78, 0
ax.plot(
    values, LogitNormal(scale=sigma, loc=mu).pdf(values), label='subclassed'
)
ax.legend()
fig.show()

【讨论】:

  • 谢谢,这行得通!我知道这是一个不同类型的问题,但您是否也知道逆 cdf / ppf 如果实施会是什么样子?因为,根据文档:“默认方法 _rvs 依赖于 cdf 的倒数,_ppf,应用于统一随机变量。为了有效地生成随机变量,需要覆盖默认的 _ppf(例如,如果cdf 可以用显式形式表示)或者需要在自定义 _rvs 方法中实现采样方法。”
  • 我不知道逆 cdf / pdf 抱歉,对统计不太了解。也许在math.stackexchange.com 上提问会有所帮助?
  • 好的,这是一件很奇怪的事情。我发现了如何做到这一点,并想相应地编辑你的答案,但界面不会让我,声称代码格式不正确。但是,所谓的错误不在我的编辑中,而是在您的报价中。这个怎么可能?如果您从字面上打开编辑并尝试按原样保存它,它将不起作用,除非您删除引用。
  • 奇怪,也许只是将其发布为您的答案。回答你的问题没有错!
猜你喜欢
  • 1970-01-01
  • 2018-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 2021-11-12
  • 2021-04-16
  • 2020-03-19
相关资源
最近更新 更多