import numpy as np
from scipy.stats import norm, rv_continuous
from scipy.special import erf
import scipy.integrate as integrate
class normal_ratio_wiki(rv_continuous):
def _pdf(self, z, mu_x, mu_y, sigma_x, sigma_y):
a_z = np.sqrt(((1/(sigma_x**2))*(np.power(z,2))) + (1/(sigma_y**2)))
b_z = ((mu_x/(sigma_x**2)) * z) + (mu_y/sigma_y**2)
c = ((mu_x**2)/(sigma_x**2)) + ((mu_y**2)/(sigma_y**2))
d_z = np.exp(((b_z**2)-((c*a_z**2))) / (2*(a_z**2)))
pdf_z = ((b_z * d_z) / (a_z**3)) * (1/(np.sqrt(2*math.pi)*sigma_x*sigma_y)) * \
(norm.cdf(b_z/a_z) - norm.cdf(-b_z/a_z)) + ((1/((a_z**2) * math.pi * sigma_x * sigma_y))*np.exp(-c/2))
return pdf_z
def _cdf(self, z, mu_x, mu_y, sigma_x, sigma_y):
cdf_z = integrate.quad(self._pdf, -np.inf, np.inf, args=(mu_x, mu_y, sigma_x, sigma_y))[0]
return cdf_z
rng1 = np.random.default_rng(99)
rng2 = np.random.default_rng(88)
# Sample Data 1
x = rng1.normal(141739.951, 1.223808e+06, 1000)
y = rng2.normal(333.91, 64.494571, 1000)
# Sample Data 2
# x = rng1.normal(500, 20, 1000)
# y = rng2.normal(400, 10, 1000)
z = x / y
# 1st approach with normal_ratio_wiki
mu_x = x.mean()
mu_y = y.mean()
sigma_x = x.std()
sigma_y = y.std()
rng3 = np.random.default_rng(11)
nr_wiki_inst = normal_ratio_wiki(name='normal_ratio_wiki', seed=rng3)
nr_wiki_vars = nr_wiki_inst.rvs(mu_x, mu_y, sigma_x, sigma_y, size = 100)
nr_wiki_params = nr_wiki_vars.fit(nr_wiki_vars)
字符串
你好,我正在通过使用scipy
定义自定义分布来模拟两个不相关的正态分布的比率分布。
从这里进入。
在使用上述两种方法从自定义分布调用scipy.dist.rvs
或fit
方法时,我分别得到以下错误RuntimeError: Failed to converge after 100 iterations.
和IntegrationWarning: The integral is probably divergent, or slowly convergent.
。如果我们注解_cdf(...)
,则该过程将花费大量时间来运行scipy.dist.rvs
,但在调用fit
时失败。尝试了不同的有界间隔,但没有成功。
我相信实现自定义_rvs
,_ppf
和/或_fit
方法可能有助于解决这个问题。我们应该如何定义基于上述_pdf
和_cdf
方法?请提供建议。
请注意,示例integrate.quad(nr_wiki_inst.pdf, -np.inf, np.inf, args=(mu_x, mu_y, sigma_x, sigma_y))
可以单独工作,没有任何问题。
1条答案
按热度按时间w7t8yxp51#
_cdf
方法本质上与泛型实现相同,因此其余部分假设它被删除。我还假设_pdf
实现是正确的,我还没有看到任何其他建议。当mu
s为0且sigma
s为1时,它简化为柯西分布,即使参数改变,它似乎也会积分为1,PDF似乎与随机变量一致(见下文)。使用
quad
集成PDF以获得CDF肯定会非常慢,但有一件事会让它更快,那就是在PDF中使用scipy.special.ndtr
代替scipy.stats.norm.cdf
。SciPy分布有很多开销,但特殊函数直接跳转到评估正态分布的CDF。字符串
这将使您的分发的CDF加速10倍至20倍。
提高RVS的速度也很容易。
_rvs
的通用实现将CDF(数字)反转以获得PPF,并传入均匀分布的随机数以获得每个观察值(逆变换采样)。我们重写_rvs
以仅生成两个正态随机变量并取比值。型
要检查此RVS实现与PDF之间的一致性,请执行以下操作:
型
x1c 0d1x的数据
这从分布中生成了100_000个随机变量(以8 ms为单位),使我们能够直观地将直方图与PDF进行比较。一致性很好,直方图的明显过量可以解释为直方图在范围[-10,10]上归一化,而不是整个真实的线。
你可以使用
scipy.stats.sampling.NumericalInversePolynomial
得到一个快速(但近似)的PPF方法。更容易描述NumericalInverseHermite
的作用:在多个点上计算CDF,并使用这些数据插值PPF。NumericalInversePolynomial
也可以使用插值,但更高级,它只需要PDF。型
我认为
fit
有问题,部分原因是它不知道sigma_x
和sigma_y
必须为正。为此,您需要定义_argcheck
:型
但是还有其他问题,我想我现在不会调试它,相反,我们可以定义
_shape_info
,这样我们就可以在这个发行版中使用scipy.stats.fit
函数,而不是发行版的fit
方法。型
现在可以使用
fit
函数:型
一起来:
型