使用scipy

时间:2015-11-17 21:38:02

标签: python numpy scipy probability curve-fitting

我想使用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函数可以用来执行类似于我展示的推断的东西?

1 个答案:

答案 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拟合将远非令人满意:

fit to data

更新

正如我上面提到的,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)

new histogram data

此直方图存在两个主要问题。第一个,正如我所说的,它不太可能对应于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是自变量,llambda(缩放参数),ck(形状参数)和A是缩放前因。引入A的微弱优势在于您不必对直方图进行标准化。

现在,当我把这个函数放到scipy.optimize.curve_fit时,我发现你做了什么:它没有实际执行拟合,但坚持使用初始拟合参数,无论你设置什么(使用{{ 1}}参数;每个参数的默认猜测都是1)。 p0似乎认为拟合汇合了。

经过一个多小时的与墙有关的头撞事后,我意识到问题是curve_fit处的奇异行为抛弃了非线性最小二乘算法。通过排除第一个数据点,您可以真正适合您的数据。我怀疑,如果我们设置x=0并且不允许它适合,那么这个问题可能会消失,但是允许这样做可能会提供更多信息(所以我没有检查)。

以下是相应的代码:

c=1

结果:

new fit

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生成带有这些参数的点,然后将得到的直方图与你自己的直方图进行比较。