我有遵循高斯分布的数据。但是,数据仅对于值[xa,xb]的范围才是真正的高斯,因此我想使用scipy.stats.truncnorm来拟合截断的正态分布,同时要使用我知道范围[xa,xb]的事实。我的目标是找到位置和规模。
我不知道如何适当地修复xa和xb。形状参数是“ a”和“ b”,但是这些参数取决于位置和比例,这是我的未知数。而且,似乎不可能对“ 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()
我也经常有这样的警告:
/home/elie/anaconda2/envs/py36/lib/python3.6/site-packages/scipy/stats/_continuous_distns.py:5823:RuntimeWarning:除以日志中遇到的零 self._logdelta = np.log(self._delta)
答案 0 :(得分:1)
您已经发现,问题在于您要保持固定的参数xa
和xb
不是truncnorm
的本机参数。 truncnorm
具有形状参数a
和b
,它们通过为 standard 正态分布设置x间隔来确定形状。然后,通过loc
和scale
参数移动和缩放此形状。关系是
xa = a*scale + loc
xb = b*scale + loc
要修复xa
和xb
,可以使用接受相等约束的SciPy最小化器之一。在这里,我将使用scipy.optimize.fmin_slsqp
。 (您可以改为使用“综合”功能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
在计算期间会失败,并显示“遇到无效值”。我没有对此进行进一步调查,但是您可能会在数据中碰到它。