我有一系列实验值和概率密度函数,据说可以描述它们的分布:
def bekkers(x, a, m, d):
p = a*np.exp((-1*(x**(1/3) - m)**2)/(2*d**2))*x**(-2/3)
return(p)
我使用scipy.optimize.curve_fit估算了我的函数的参数,现在我需要以某种方式测试拟合的好坏。我找到了一个scipy.stats.kstest函数,它完全按照我的需要进行,但它需要一个连续的分布函数。我该如何处理我的任务?
答案 0 :(得分:4)
注意:我不确定您的可能x值的范围是什么,以及您对a,m和d的估计是什么,所以我试图将这些值尽可能地保持开放。
KS测试的CDF是指累积分发,而不是连续分发功能(您已经获得)。我们将为此构建一个函数,因为我不确定是否有一个封闭的形式来表示你提供的等式的积分,我们只是用scipy.integrate来做。 / p>
为了将它与其他numpy / scipy工具一起使用,我们希望它能够接收并返回一个数组(可能有一种更漂亮的方法可以做到这一点,但下面仍然有效)。另请注意,您必须对cdf进行标准化,因为至少对于我选择的值和范围,整个可能值范围内的积分不等于1.这就是它看起来像是:
def bekkers_cdf(x,a,m,d,range_start,range_end):
values = []
for value in x:
integral = integrate.quad(lambda k: bekkers(k,a,m,d),range_start,value)[0]
normalized = integral/integrate.quad(lambda k: bekkers(k,a,m,d),range_start,range_end)[0]
values.append(normalized)
return np.array(values)
一旦我们有了这个,我们现在可以评估我们的ks.test(使用我为范围,a,m和d组成的一些值):
my_start,my_end = 1,10
my_a,my_m,my_d = 1,1,1
my_data = [1.5,1.6,1.8,2.1,2.2,3.3,4,6,8,9]
stats.kstest(my_data,lambda x: bekkers_cdf(x,my_a,my_m,my_d,my_start,my_end))
返回:
(0.17609125905568074, 0.9157727421346824)
第一个值是统计量,第二个值是p值。有了这么高的p值,我们绝对不能拒绝这个数据来自这个分布。
代码摘要:
import numpy as np
import scipy as sp
from scipy import integrate,stats
def bekkers(x, a, m, d):
p = a*np.exp((-1*(x**(1/3) - m)**2)/(2*d**2))*x**(-2/3)
return(p)
def bekkers_cdf(x,a,m,d,range_start,range_end):
values = []
for value in x:
integral = integrate.quad(lambda k: bekkers(k,a,m,d),range_start,value)[0]
normalized = integral/integrate.quad(lambda k: bekkers(k,a,m,d),range_start,range_end)[0]
values.append(normalized)
return np.array(values)
my_start = 1
my_end = 10
my_a,my_m,my_d = 1,1,1
my_data = [1.5,1.6,1.8,2.1,2.2,3.3,4,6,8,9]
stats.kstest(my_data,lambda x: bekkers_cdf(x,my_a,my_m,my_d,my_start,my_end))
为了获得一点乐趣,我们可以看看ks-test正在看什么。为此,我们将我们的数据中的理论cdf与拟议函数的理论cdf进行比较。 (注意下面我在数据的cdf中硬编码,但这很容易编程)使用matplotlib这是:
import matplotlib.pyplot as plt
xs = np.linspace(1, 10)
ys = bekkers_cdf(xs,my_a,my_m,my_d,my_start,my_end)
theoretical, =plt.plot(xs,ys,linewidth=2)
x2s = [1,1.5,1.6,1.8,2.1,2.2,3.3,4,6,8,9,10]
y2s = [0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1,1]
data, =plt.plot(x2s,y2s,linewidth=2)
plt.legend([theoretical,data],['theoretical','data'])
哪个收益率:
我们看到数据的cdf类似于建议的分布所建议的,所以我们的测试没有拒绝null,而样本数据来自这个分布。