我想使用scipy(在我的情况下,使用weibull_min)来分配我的数据。给定直方图,而不是数据点,是否可以这样做?在我的情况下,因为直方图具有大小为1的整数二进制位,我知道我可以通过以下方式推断我的数据:
import numpy as np
orig_hist = np.array([10, 5, 3, 2, 1])
ext_data = reduce(lambda x,y: x+y, [[i]*x for i, x in enumerate(orig_hist)])
在这种情况下,ext_data会保留这个:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]
使用以下方法构建直方图:
np.histogram(ext_data, bins=5)
等同于orig_hist
然而,鉴于我已经建立了直方图,我想避免外推数据并使用orig_hist来拟合分布,但我不知道是否可以在拟合程序中直接使用它。另外,是否有一个numpy函数可以用来执行类似于我展示的推断的东西?
答案 0 :(得分:3)
我可能会误解某些东西,但我认为适合直方图正是你应该做的:你试图近似概率密度。并且直方图尽可能接近基础概率密度。您只需将其标准化以使积分为1,或允许拟合模型包含任意前因子。
import numpy as np
import scipy.stats as stats
import scipy.optimize as opt
import matplotlib.pyplot as plt
orig_hist = np.array([10, 5, 3, 2, 1])
norm_hist = orig_hist/float(sum(orig_hist))
popt,pcov = opt.curve_fit(lambda x,c: stats.weibull_min.pdf(x,c), np.arange(len(norm_hist)),norm_hist)
plt.figure()
plt.plot(norm_hist,'o-',label='norm_hist')
plt.plot(stats.weibull_min.pdf(np.arange(len(norm_hist)),popt),'s-',label='Weibull_min fit')
plt.legend()
当然,对于您的输入,Weibull拟合将远非令人满意:
正如我上面提到的,Weibull_min不适合您的样本输入。更大的问题是它也不适合您的实际数据:
orig_hist = np.array([ 23., 14., 13., 12., 12., 12., 11., 11., 11., 11., 10., 10., 10., 9., 9., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6.], dtype=np.float32)
此直方图存在两个主要问题。第一个,正如我所说的,它不太可能对应于Weibull_min分布:它最接近于零且具有长尾,所以它需要一个非平凡的Weibull参数组合。此外,您的直方图显然只包含分布的一部分。这意味着我的上述规范化建议可以保证失败。你不能避免在你的拟合中使用任意比例参数。
我手动定义了一个缩放的Weibull拟合函数according to the formula on Wikipedia:
my_weibull = lambda x,l,c,A: A*float(c)/l*(x/float(l))**(c-1)*np.exp(-(x/float(l))**c)
在此函数中,x
是自变量,l
是lambda
(缩放参数),c
是k
(形状参数)和A
是缩放前因。引入A
的微弱优势在于您不必对直方图进行标准化。
现在,当我把这个函数放到scipy.optimize.curve_fit
时,我发现你做了什么:它没有实际执行拟合,但坚持使用初始拟合参数,无论你设置什么(使用{{ 1}}参数;每个参数的默认猜测都是1)。 和 p0
似乎认为拟合汇合了。
经过一个多小时的与墙有关的头撞事后,我意识到问题是curve_fit
处的奇异行为抛弃了非线性最小二乘算法。通过排除第一个数据点,您可以真正适合您的数据。我怀疑,如果我们设置x=0
并且不允许它适合,那么这个问题可能会消失,但是允许这样做可能会提供更多信息(所以我没有检查)。
以下是相应的代码:
c=1
结果:
import numpy as np
import scipy.optimize as opt
import matplotlib.pyplot as plt
orig_hist = np.array([ 23., 14., 13., 12., 12., 12., 11., 11., 11., 11., 10., 10., 10., 9., 9., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6.], dtype=np.float32)
my_weibull = lambda x,l,c,A: A*float(c)/l*(x/float(l))**(c-1)*np.exp(-(x/float(l))**c)
popt,pcov = opt.curve_fit(my_weibull,np.arange(len(orig_hist))[1:],orig_hist[1:]) #throw away x=0!
plt.figure()
plt.plot(np.arange(len(orig_hist)),orig_hist,'o-',label='orig_hist')
plt.plot(np.arange(len(orig_hist)),my_weibull(np.arange(len(orig_hist)),*popt),'s-',label='Scaled Weibull fit')
plt.legend()
最终拟合参数的顺序为In [631]: popt
Out[631]: array([ 1.10511850e+02, 8.82327822e-01, 1.05206207e+03])
,形状参数约为(l,c,A)
。这对应于发散概率密度,这解释了为什么会出现一些错误
运行时警告:电源中遇到无效值
以及为什么没有来自0.88
的拟合的数据点。但从数据和拟合之间的视觉协议来判断,您可以评估结果是否可接受。
如果你想过度使用它,你可以尝试使用x=0
生成带有这些参数的点,然后将得到的直方图与你自己的直方图进行比较。