初始化 Python 自定义分发

Initialize Python Custom Distribution

我在 Scipy 中使用自定义对数伽玛分布,我想将它与各种预定义的 Scipy 分布一起使用。我的问题是自定义分发似乎需要与预定义分发有点不同的处理方式。具体来说,似乎我需要先初始化自定义分发才能使用。见下文:

import matplotlib.pyplot as plt
import pandas as pd

import numpy as np
from scipy.stats import gamma
from scipy.special import gamma as gamma_func
from scipy.special import erf, erfinv
from scipy.stats import rv_continuous
from scipy.stats import lognorm, norm

class custom_lgamma(rv_continuous):
    """ 
    pdf defined on page 227 in the book https://www.amazon.com/Loss-Distributions-Wiley-Probability-Statistics/dp/0471879290
    The parameters of this distribution are a and lambdax
    """
    
    dist_name = "Custom_Log_Gamma"
        
    def _pdf(self, x, a, lambdax):
        """ pdf of the log gamma function """
        return (lambdax**(a)*(np.log(x))**(a-1))/(x**(lambdax+1)*gamma_func(a))

    def _cdf(self, x, a, lambdax):
        """ cdf of the log gamma function """
        u = lambdax*np.log(x)
        return gamma.cdf(u, a=a)
    
    def _sf(self, x, a, v):
        """ survivial fuction of the log gamma function. This is 1 - CDF. """
        u = lambdax*np.log(x)
        return 1 - gamma.cdf(u, a=a)
    
    def _ppf(self,x, a, lambdax):
        """ inverse cdf of the log gamma function. This is required to conduct efficient random variable simulation. """
        u = gamma.ppf(x, a=a)
        return np.exp(u/lambdax)
    
    def _argcheck(self, a, lambdax):
        """ check that the fitted parameters fall within the required bounds """
        param1_test = a > 0
        param2_test = lambdax > 0
        return param1_test and param2_test

test_data2 = custom_lgamma().rvs(a=5,lambdax=3,size=1000)

lg = custom_lgamma()
lg.fit(test_data2,floc=0,fscale=1)

custom_lgamma().fit(test_data2,floc=0,fscale=1)

这两种实现都有效,但是,我希望能够使用自定义分布而无需对其进行初始化,类似于预定义分布的使用方式:

norm.fit(test_data2)

预定义分布不需要初始化或可调用。如果我尝试以这种方式使用自定义分发,我会得到结果:

custom_lgamma.fit(test_data2,floc=0,fscale=1)

>>>
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-47-9b87a6428141> in <module>
----> 1 custom_lgamma.fit(test_data2,floc=0,fscale=1)

TypeError: fit() missing 1 required positional argument: 'data'

有没有办法定义自定义 scipy 分布,使其不需要初始化或可调用?我的 scipy 是 1.5.2。谢谢!

您没有初始化您的分发; SciPy 的分发基础设施就是这样构建的。您对 rv_continuous class 和 rv_frozen class.

的实例感到困惑

当您调用您的发行版 class(在您的情况下为 custom_lgamma)时,SciPy 会为用户界面生成文档和代码,从而创建我们从 [= 中看到和使用的发行版14=](例如 normgamma)(这是当您执行 custom_lgamma() 时发生的情况)。此实例包含 pdfcdf 等方法,这些方法使用形状参数 调用 (就像其他 scipy.stats 分布一样)。

再次调用此实例(例如 norm())将创建一个 frozen 分布(rv_frozen class 的一个实例)其形状参数无法更改(如果您再次调用 custom_lgamma 实例或执行 custom_lgamma()() 就会发生这种情况)。此实例具有仅接受分位数参数的 pdf 方法。

这是 SciPy 使用的约定:

class custom_lgamma_gen(rv_continuous):
    # implement your distribution methods here.
    ....

# this is the instance containing user interface of the distribution.
custom_lgamma = custom_lgamma_gen(name="custom_lgamma")


# now, you can call the fit method just like you would
# do with other scipy.stats distributions.
custom_lgamma.fit(test_data2,floc=0,fscale=1)


# to create a frozen distribution, do:
custom_lgamma_frozen = custom_lgamma()


# now you can call the methods without shape parameters
custom_lgamma_frozen.pdf(0.5)