在this post之后,我尝试通过创建LogitNormal
类来创建一个对数正态分布:
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中创建自己的对数正态分布的唯一原因是,我能找到的该分布的唯一实现来自PyMC 3包和TensorFlow包,如果你只需要一个函数,这两个包都相当繁重/矫枉过正。我已经尝试过PyMC3
,但显然它在scipy
中做得不好,我认为,但那是完全不同的故事。
2条答案
按热度按时间svgewumm1#
前言
这个星期我遇到了这个问题,我发现唯一相关的问题就是这个帖子。我和楼主的要求几乎一样:
但我还需要:
scipy
随机变量接口兼容。正如
@Jacques Gaudin
所指出的,rv_continous
的接口(详细信息请参见发行版体系结构)在继承此类时无法确保loc
和scale
参数的后续操作。这在某种程度上是误导性的和不幸的。当然,实现
__init__
方法允许创建缺少的绑定,但代价是:它破坏了当前用于实现随机变量的patternx 1 m6n1x(参见对数正态分布的实现示例)。因此,我花时间深入研究了
scipy
代码,并为这个发行版创建了一个MCVE。虽然它不是完全完整的(它主要是错过了时刻覆盖),但它符合OP和我的目的,同时具有令人满意的准确性和性能。MCVE公司
该随机变量的符合接口的实现可以是:
此实现释放了大多数
scipy
随机变量的潜力。由于它依赖于
scipy
正态分布,我们可以假设底层函数与正态随机变量对象具有相同的精度和性能,但它可能确实受到浮点运算不准确性的影响,尤其是在处理支持边界上的高度偏斜分布时。测试次数
为了检验它的表现,我们画出一些兴趣分布并进行检验。让我们创建一些固定装置:
并对相关分布和样本进行检查:
使用
n=1000, seed=789
进行的一些调整(此示例非常正常)如下所示:第一页第二页
e1xvtsh32#
如果您查看
pdf
方法的源代码,您会注意到调用_pdf
时没有使用scale
和loc
关键字参数。这会导致您覆写的
_pdf
方法中的kwargs
永远是空字典。如果您更仔细地查看代码,您还会注意到缩放和位置是由
pdf
处理的,而不是_pdf
。在本例中,
_pdf
方法调用norm.pdf
,因此loc
和scale
参数必须在LogitNormal._pdf
中可用。例如,在创建
LogitNormal
的示例时,可以传递scale
和loc
,并将这些值存储为类属性: