如何在 Python 中创建对数正态分布?
How do you create a logit-normal distribution in Python?
在 this post 之后,我尝试通过创建 LogitNormal
class:
来创建对数正态分布
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
class 没有产生预期的结果。当我不使用 subclass rv_continuous
时,它会起作用。这是为什么?我需要 subclassing 才能工作,因为我还需要它附带的其他方法,例如 rvs
。
顺便说一句,我在 Python 中创建自己的对数正态分布的唯一原因是因为我能找到的该分布的唯一实现来自 PyMC3 package and from the TensorFlow package,两者都是如果您只需要它们来实现一个功能,那么它会很重/矫枉过正。我已经尝试过 PyMC3
,但显然它与 scipy
的效果不佳,我认为它总是崩溃。但那是完全不同的故事。
如果您查看 source code of the pdf
method,您会注意到调用 _pdf
时没有 scale
和 loc
关键字参数。
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
,因此 loc
和 scale
参数必须以某种方式在 LogitNormal._pdf
.[=30 中可用=]
例如,您可以在创建 LogitNormal
的实例时传递 scale
和 loc
,并将值存储为 class 属性:
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()
在 this post 之后,我尝试通过创建 LogitNormal
class:
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
class 没有产生预期的结果。当我不使用 subclass rv_continuous
时,它会起作用。这是为什么?我需要 subclassing 才能工作,因为我还需要它附带的其他方法,例如 rvs
。
顺便说一句,我在 Python 中创建自己的对数正态分布的唯一原因是因为我能找到的该分布的唯一实现来自 PyMC3 package and from the TensorFlow package,两者都是如果您只需要它们来实现一个功能,那么它会很重/矫枉过正。我已经尝试过 PyMC3
,但显然它与 scipy
的效果不佳,我认为它总是崩溃。但那是完全不同的故事。
如果您查看 source code of the pdf
method,您会注意到调用 _pdf
时没有 scale
和 loc
关键字参数。
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
,因此 loc
和 scale
参数必须以某种方式在 LogitNormal._pdf
.[=30 中可用=]
例如,您可以在创建 LogitNormal
的实例时传递 scale
和 loc
,并将值存储为 class 属性:
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()