指数曲线拟合的置信区间

时间:2014-07-08 13:53:23

标签: python numpy scipy confidence-interval

我正在尝试获得某些x,y数据的指数拟合的置信区间(可用here)。这是MWE,我必须找到最适合数据的指数:

from pylab import *
from scipy.optimize import curve_fit

# Read data.
x, y = np.loadtxt('exponential_data.dat', unpack=True)

def func(x, a, b, c):
    '''Exponential 3-param function.'''
    return a * np.exp(b * x) + c

# Find best fit.
popt, pcov = curve_fit(func, x, y)
print popt

# Plot data and best fit curve.
scatter(x, y)
x = linspace(11, 23, 100)
plot(x, func(x, *popt), c='r')
show()

产生:

enter image description here

如何使用纯pythonnumpyscipy(我已经拥有的包)获得此拟合的95%(或其他一些值)置信区间安装)?

5 个答案:

答案 0 :(得分:6)

您可以使用uncertainties模块进行不确定性计算。 uncertainties跟踪不确定性和相关性。您可以直接从uncertainties.ufloat的输出中创建相关的curve_fit

为了能够对exp等非内置操作进行计算,您需要使用uncertainties.unumpy中的函数。

您还应该避免from pylab import *导入。这甚至会覆盖python内置函数,例如sum

一个完整的例子:

import numpy as np
from scipy.optimize import curve_fit
import uncertainties as unc
import matplotlib.pyplot as plt
import uncertainties.unumpy as unp


def func(x, a, b, c):
    '''Exponential 3-param function.'''
    return a * np.exp(b * x) + c

x, y = np.genfromtxt('data.txt', unpack=True)

popt, pcov = curve_fit(func, x, y)

a, b, c = unc.correlated_values(popt, pcov)

# Plot data and best fit curve.
plt.scatter(x, y, s=3, linewidth=0, alpha=0.3)

px = np.linspace(11, 23, 100)
# use unumpy.exp
py = a * unp.exp(b * px) + c

nom = unp.nominal_values(py)
std = unp.std_devs(py)

# plot the nominal value
plt.plot(px, nom, c='r')

# And the 2sigma uncertaintie lines
plt.plot(px, nom - 2 * std, c='c')
plt.plot(px, nom + 2 * std, c='c')
plt.savefig('fit.png', dpi=300)

结果: result

答案 1 :(得分:5)

注意:获得拟合曲线置信区间的实际答案由Ulrich here给出。


经过一些研究(见herehere1.96)后,我提出了自己的解决方案。

它接受任意X%置信区间并绘制上下曲线。

enter image description here

这是MWE:

from pylab import *
from scipy.optimize import curve_fit
from scipy import stats


def func(x, a, b, c):
    '''Exponential 3-param function.'''
    return a * np.exp(b * x) + c


# Read data.
x, y = np.loadtxt('exponential_data.dat', unpack=True)

# Define confidence interval.
ci = 0.95
# Convert to percentile point of the normal distribution.
# See: https://en.wikipedia.org/wiki/Standard_score
pp = (1. + ci) / 2.
# Convert to number of standard deviations.
nstd = stats.norm.ppf(pp)
print nstd

# Find best fit.
popt, pcov = curve_fit(func, x, y)
# Standard deviation errors on the parameters.
perr = np.sqrt(np.diag(pcov))
# Add nstd standard deviations to parameters to obtain the upper confidence
# interval.
popt_up = popt + nstd * perr
popt_dw = popt - nstd * perr

# Plot data and best fit curve.
scatter(x, y)
x = linspace(11, 23, 100)
plot(x, func(x, *popt), c='g', lw=2.)
plot(x, func(x, *popt_up), c='r', lw=2.)
plot(x, func(x, *popt_dw), c='r', lw=2.)
text(12, 0.5, '{}% confidence interval'.format(ci * 100.))    

show()

答案 2 :(得分:5)

加布里埃尔answer不正确。在这里用红色显示他的数据的95%置信区间,由GraphPad Prism计算: Prism confidence and prediction bands

背景:拟合曲线的置信区间"通常称为置信区。对于95%置信区间,可以95%确信它包含真实曲线。 (这与预测频段不同,如上所示为灰色。预测频段与未来数据点有关。有关详细信息,请参阅例如GraphPad曲线拟合指南的page。)

在Python中,kmpfit可以计算非线性最小二乘的置信带。这里是加布里埃尔的例子:

from pylab import *
from kapteyn import kmpfit

x, y = np.loadtxt('_exp_fit.txt', unpack=True)

def model(p, x):
  a, b, c = p
  return a*np.exp(b*x)+c

f = kmpfit.simplefit(model, [.1, .1, .1], x, y)
print f.params

# confidence band
a, b, c = f.params
dfdp = [np.exp(b*x), a*x*np.exp(b*x), 1]
yhat, upper, lower = f.confidence_band(x, dfdp, 0.95, model)

scatter(x, y, marker='.', s=10, color='#0000ba')
ix = np.argsort(x)
for i, l in enumerate((upper, lower, yhat)):
  plot(x[ix], l[ix], c='g' if i == 2 else 'r', lw=2)
show()

dfdp是关于每个参数p(即a,b和c)的模型f = a * e ^(b * x)+ c的偏导数∂f/∂p 。有关背景信息,请参阅GraphPad曲线拟合指南的kmpfit Tutorial或此page。 (与我的示例代码不同,kmpfit教程不使用库中的confidence_band(),而是使用它自己的略有不同的实现。)

最后,Python绘图与Prism one匹配:

kmpfit confidence bands

答案 3 :(得分:2)

curve_fit()返回协方差矩阵 - pcov - 其中包含估计的不确定性(1 sigma)。这假设错误是正常分布的,这有时是有问题的。

你也可以考虑使用lmfit包(纯粹的python,建立在scipy之上),它提供了一个围绕scipy.optimize拟合例程的包装器(包括leastsq(),这就是curve_fit()使用的)除其他外,还可以明确地计算置信区间。

答案 4 :(得分:1)

我一直都是简单引导的粉丝,以获得置信区间。如果您有n个数据点,请使用random包从您的数据中选择n点进行重新计算(即允许您的程序多次获得相同的点数,如果有的话)它想做什么 - 非常重要。完成后,绘制重新采样的点并获得最佳拟合。这样做10,000次,每次都有新的生产线。然后你的95%置信区间是包含95%最佳拟合线的一对线。

在Python中编程是一种非常简单的方法,但从统计的角度来看,这有点不清楚。有关您为什么要这样做的更多信息可能会为您的任务提供更合适的答案。