Python 使用scipy truncnorm拟合数据

Python 使用scipy truncnorm拟合数据,python,scipy,Python,Scipy,我有服从高斯分布的数据。然而,数据仅在[xa,xb]的范围内是真正的高斯分布,因此我想使用我知道范围[xa,xb]的事实拟合截断正态分布。我的目标是找到loc和scale 我不知道如何在fit中修复xa和xb。形状参数是‘a’和‘b’,但它们取决于loc和scale,这是我的未知数。此外,似乎不可能对“a”和“b”进行初步猜测(它们只能用fa和fb冻结?)。当我这样做时: par = truncnorm.fit(r, a=a_guess, b=b_guess, scale= scale_gues

我有服从高斯分布的数据。然而,数据仅在[xa,xb]的范围内是真正的高斯分布,因此我想使用我知道范围[xa,xb]的事实拟合截断正态分布。我的目标是找到loc和scale

我不知道如何在fit中修复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.444 6}

而且,我得到的适合是非常不稳定的。下面是一个例子:

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()

我也经常有这样的警告:

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


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

xa = a*scale + loc
xb = b*scale + loc
要修复
xa
xb
,可以使用一个接受等式约束的SciPy最小值。这是我要用的。(您可以使用“综合”功能,其中包括SLSQP解算器作为其选项之一。)

下面是一个脚本,演示如何使用
fmin_slsqp
解决此问题。函数
func
是要最小化的目标函数。它只是负对数似然函数truncnorm.nnlf的包装。函数
约束
返回一个包含两个值的数组。满足约束时,这些值为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
失败并出现“遇到无效值”。我还没有对此进行进一步调查,但您可能会在使用数据时遇到此问题。

谢谢!它在我的一半以上的数据集中起作用。对于另一半,我不幸遇到了“遇到无效值”错误。