Bootstrap方法和置信区间

4

我目前正在尝试使用自助法(bootstrap method)在一些参数上实现置信区间,但是我遇到了一个小问题。即使我使用了3000个样本,我的置信区间也变化很大。

这是情况:

我有一个数据集,约有300个点,以传统的y=f(x)方式定义。我知道适合数据的模型。因此我使用curve_fit找到参数,并尝试为每个参数建立置信区间。我尝试混合描述如下方法:

confidence interval with leastsq fit in scipy python

和这里:

http://www.variousconsequences.com/2010/02/visualizing-confidence-intervals.html

这是我使用的代码:

def model(t, Vs, Vi, k):

    """
    Fitting model, following a Burst kinetics.
    t is the time
    Vs is the steady velocity
    Vi is the initial velocity
    k is the Burst rate constant
    """

    y = Vs * t - ((Vs - Vi) * (1 - np.exp(-k * t)) / k)

    return y



[some code]

bootindex = np.random.random_integers
nboot = 3000


local_t = np.array(local_t)
local_fluo = np.array(local_fluo)
concentration = np.array(concentration)

#Initializing time values in hours
local_scaled_t = [ index /3600 for index in local_t ]
local_scaled_t = np.array(local_scaled_t)

conc_produit = [ concentration[0] - value_conc for value_conc in concentration ]
conc_produit = np.array(conc_produit)

popt, pcov = curve_fit(model, local_scaled_t, conc_produit, maxfev=3000)
popt = [ popt[0] / 3600, popt[1] / 3600 , popt[2] / 3600 ]

ymod = list()
for each in local_t:
        ymod.append(model(each, popt[0], popt[1], popt[2]))
ymod = np.array(ymod)

r = conc_produit - ymod

list_para = list()

# loop over n bootstrap samples from the resids 
for i in range(nboot): 

    pc, pout = curve_fit(model, local_scaled_t, ymod + r[bootindex(0, len(r)-1, len(r))], maxfev=3000) 
    pc = [ pc[0] / 3600, pc[1] / 3600 , pc[2] / 3600 ]

    list_para.append(pc)

    ymod = list()
    for each in local_t:
            ymod.append(model(each, pc[0], pc[1], pc[2]))
    ymod = np.array(ymod)

list_para = np.array(list_para)

mean_params = np.mean(list_para,0)
std_params = np.std(list_para,0)

print(popt)
for true_para, para, std in zip(popt, mean_params, std_params):
    print("{0} between {1} and {2}".format(round(true_para, 6), round(para - std * 1.95996, 6), round(para + std * 1.95996, 6)))
    print("{0} between {1} and {2}".format(round(true_para, 6), round(para - std * 1.95996, 6), round(para + std * 1.95996, 6)))

这里没有什么复杂的,只是需要注意我重新调整了时间以标准化我的数据,并获得更好的参数。

最后,这是同一段代码的两个输出:

[1.9023455671995163e-05, 0.01275941716148471, 0.026540319119773129]
1.9e-05 between 1.6e-05 and 2.1e-05
0.012759 between -0.042697 and 0.092152
0.02654 between -0.073456 and 0.159983

[1.9023455671995163e-05, 0.01275941716148471, 0.026540319119773129]
1.9e-05 between 1.5e-05 and 2.9e-05
0.012759 between -0.116499 and 0.17112
0.02654 between -0.186011 and 0.27797

如您所见,差异非常大。这是否符合预期或者我做错了什么?例如,我不太明白为什么要将标准偏差乘以1.95996。


只是好奇,为什么要引导误差而不使用协方差矩阵? - reptilicus
1
因为我不知道自己在做什么?哈哈,开个玩笑。不过说真的,我确实不理解。协方差不是应该提供关于变量相互独立程度的指示吗?你怎么能从中获取置信区间呢? - JPFrancoia
1
严格来说,协方差指示参数估计之间的相关性。简而言之,如果您只需要每个参数的CI,则只需要vcov矩阵的对角线元素。除非您想要多维置信区域:http://en.wikipedia.org/wiki/Confidence_region - CT Zhu
不,没关系。但是最后一个问题,如果您检查我的代码,我重新调整了时间,使其以小时为单位。这样,拟合效果更好,因为我的计算值很小(约为1)。然后,我通过除以3600将参数转换回正确的单位。但是我必须用相同的方法处理协方差对吧?问题是,当单位为小时时,置信区间大约是参数值的5%。当单位为秒时,即使在将它们除以3600之后,置信区间也大约是参数值的100%。那么我该如何像参数一样,在秒钟内获得置信区间呢? - JPFrancoia
1个回答

2
您的curve_fit已经为您提供了协方差矩阵,即pout。您第i个参数的95%置信区间为:pc[i]-1.95596*sqrt(pout[i,i])pc[i]+1.95596*sqrt(pout[i,i])。1.95596是满足标准正态分布累积分布函数F(x)=0.975的x值。您可以使用scipy.stats.norm.ppf获得其他置信水平的置信区间。请参见维基百科:http://en.wikipedia.org/wiki/1.96 引导法(bootstrap)不会每次运行都给出相同的(或者有时甚至接近的)答案。对于您特定的函数,最初的很少的数据点对拟合结果有很大的影响。解方程。我不确定引导法是否是正确的方法,因为如果未采样到最初的很少的数据点,则拟合结果将与原始数据的拟合结果非常不同。这也解释了为什么您的引导法区间之间存在如此大的差异。

但是pout是3x3矩阵。我不能直接这样做。我应该执行np.diag(pcov)吗? - JPFrancoia
是的,抱歉我错过了那个。或者 pcov[i,i]。非对角线元素是协方差。回答已更正。 - CT Zhu
好的。但是我已经问过@reptilicus了,协方差不是应该给出变量独立性的指示吗?你怎么能从中得到置信区间呢? - JPFrancoia
1
你也可以这样想:对角线元素是每个参数与自身的协方差,即方差。对这些值进行sqrt运算可以得到标准误差。 - CT Zhu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接