【问题标题】:Fitting data using scipy truncnorm使用 scipy truncnorm 拟合数据
【发布时间】:2019-04-07 02:28:57
【问题描述】:

我有遵循高斯分布的数据。但是,数据仅对于值范围 [xa,xb] 才是真正的高斯分布,因此我想使用 scipy.stats.truncnorm 拟合截断的正态分布,同时使用我知道范围 [xa,xb] 的事实。我的目标是找到位置和比例。

我不明白如何适当地修复 xa 和 xb。形状参数是“a”和“b”,但它们取决于 loc 和 scale,这是我的未知数。此外,似乎不可能对“a”和“b”进行初步猜测(它们只能用 fa 和 fb 冻结?)。当我这样做时:

par = truncnorm.fit(r, a=a_guess, b=b_guess, scale= scale_guess, loc = loc_guess)

我明白了

未知参数:{'a': 0.0, 'b': 2.4444444444444446}。

另外,我得到的配合非常不稳定。这是一个例子:

from scipy.stats import truncnorm
import matplotlib.pyplot as plt

xa, xb = 30,250 
loc, loc_guess = 50, 30
scale, scale_guess = 75, 90
a,b = (xa-loc)/scale, (xb-loc)/scale

fig, ax = plt.subplots(1, 1)
x = np.linspace(xa,xb,10000)    
ax.plot(x, truncnorm.pdf(x, a, b, loc=loc, scale=scale),
        'r-', lw=5, alpha=0.6, label='truncnorm pdf')

r = truncnorm.rvs(a, b, loc=loc, scale=scale, size=10000)
par = truncnorm.fit(r, scale= scale_guess, loc = loc_guess)
ax.plot(x, truncnorm.pdf(x, *par),
        'b-', lw=1, alpha=0.6, label='truncnorm fit')
ax.hist(r, density=True, histtype='stepfilled', alpha=0.3)
plt.legend()
plt.show()

1st example 2nd example

我也经常有这样的警告:

/home/elie/anaconda2/envs/py36/lib/python3.6/site-packages/scipy/stats/_continuous_distns.py:5823:RuntimeWarning:在日志中遇到除以零 self._logdelta = np.log(self._delta)

【问题讨论】:

    标签: python scipy


    【解决方案1】:

    正如您所发现的,问题在于您要保持固定的参数xaxb 不是truncnorm 的本机参数。 truncnorm 具有形状参数ab,它们通过设置标准 正态分布的x 区间来确定形状。然后通过locscale 参数移动和缩放此形状。关系是

    xa = a*scale + loc
    xb = b*scale + loc
    

    要修复 xaxb,您可以使用接受等式约束的 SciPy 最小化程序之一。这里我将使用scipy.optimize.fmin_slsqp。 (您可以改为使用“omnibus”函数scipy.optmize.minimize,其中包括 SLSQP 求解器作为其选项之一。)

    这是一个演示如何使用fmin_slsqp 解决此问题的脚本。函数func 是要最小化的目标函数。它只是 truncnorm.nnlf 的包装,负对数似然函数。函数constraint 返回一个包含两个值的数组。满足约束时,这些值为 0。

    import numpy as np
    from scipy.stats import truncnorm
    from scipy.optimize import fmin_slsqp
    
    import matplotlib.pyplot as plt
    
    
    def func(p, r, xa, xb):
        return truncnorm.nnlf(p, r)
    
    
    def constraint(p, r, xa, xb):
        a, b, loc, scale = p
        return np.array([a*scale + loc - xa, b*scale + loc - xb])
    
    
    xa, xb = 30, 250 
    loc = 50
    scale = 75
    
    a = (xa - loc)/scale
    b = (xb - loc)/scale
    
    # Generate some data to work with.
    r = truncnorm.rvs(a, b, loc=loc, scale=scale, size=10000)
    
    loc_guess = 30
    scale_guess = 90
    a_guess = (xa - loc_guess)/scale_guess
    b_guess = (xb - loc_guess)/scale_guess
    p0 = [a_guess, b_guess, loc_guess, scale_guess]
    
    par = fmin_slsqp(func, p0, f_eqcons=constraint, args=(r, xa, xb),
                     iprint=False, iter=1000)
    
    xmin = 0
    xmax = 300
    x = np.linspace(xmin, xmax, 1000)
    
    fig, ax = plt.subplots(1, 1)
    ax.plot(x, truncnorm.pdf(x, a, b, loc=loc, scale=scale),
            'r-', lw=3, alpha=0.4, label='truncnorm pdf')
    ax.plot(x, truncnorm.pdf(x, *par),
            'k--', lw=1, alpha=1.0, label='truncnorm fit')
    ax.hist(r, bins=15, density=True, histtype='stepfilled', alpha=0.3)
    ax.legend(shadow=True)
    plt.xlim(xmin, xmax)
    plt.grid(True)
    
    plt.show()
    

    这是它生成的情节。样本数据是随机的,因此每次运行的图都会不同。

    注意:偶尔会生成一个随机数据集,在计算过程中fmin_slsqp 失败并出现“遇到无效值”。我尚未对此进行进一步调查,但您的数据可能会遇到这种情况。

    【讨论】:

    • 谢谢!它适用于我一半以上的数据集。对于另一半,不幸的是,我遇到了“遇到无效值”错误。
    • +1 很有帮助,虽然我也遇到过收敛问题。最后我决定使用par = truncnorm.fit(r, loc=loc_guess, scale=scale_guess),因为在我的情况下,保持间隔的边界固定并不重要。
    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 2018-03-07
    • 2013-07-28
    • 2016-01-14
    • 1970-01-01
    • 2013-07-03
    • 1970-01-01
    • 2020-04-05
    相关资源
    最近更新 更多