Optimization 使用scipy.curve_拟合的参数错误

Optimization 使用scipy.curve_拟合的参数错误,optimization,scipy,curve-fitting,Optimization,Scipy,Curve Fitting,我正在拟合以下函数(变量A、D、μ和τ),x和E是固定的: 我用这个公式创建了一些示例数据,并添加了一些噪声。拟合看起来很好,卡方误差很低,但是协方差矩阵的误差是奇数;有些非常大,而另一些则较小。我做错了什么 import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit # Constants E_field = 1 x = 1 def function(t, A, D, μ,

我正在拟合以下函数(变量A、D、μ和τ),x和E是固定的:

我用这个公式创建了一些示例数据,并添加了一些噪声。拟合看起来很好,卡方误差很低,但是协方差矩阵的误差是奇数;有些非常大,而另一些则较小。我做错了什么

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

# Constants
E_field = 1
x = 1

def function(t, A, D, μ, τ):
  return A/np.sqrt(4*np.pi*D*t) * np.exp(-pow(x-μ*E_field*t, 2)/(4*D*t) - t/τ)

def chi(E, O):
  return np.sum(np.ma.masked_invalid(pow(O-E, 2)/E))

def fit(t, n, m, p0):
  ddof = n.size - m
  popt, pcov = curve_fit(function, t, n, p0=p0)
  fitted_n = function(t, *popt)
  reduced_χ_squared = chi(n, fitted_n) / ddof
  σ = np.sqrt(np.diag(pcov))
  return popt, σ, reduced_χ_squared

# Choose random variables to generate data
x, t = 1, np.linspace(0.01, 5, num=100)
A, D, μ, τ = 1, 0.2, 1, 1
n = function(t, A, D, μ, τ)

n_noise = n + 0.005 * np.random.normal(size=n.size)
n_noise += abs(min(n_noise)) # Shift data to lie on y = 0

p0 = [1, 0.25, 1, 1]
vars, σ, reduced_χ_squared = fit(t, n_noise, 4, p0)
fitted_A, fitted_D, fitted_μ, fitted_τ = vars
σ_A, σ_D, σ_μ, σ_τ = σ
fitted_n = function(t, *vars)

fig, ax = plt.subplots()

ax.plot(t, n_noise)
ax.plot(t, fitted_n)
#ax.text(0.82, 0.75, "χᵣ²={:.4f}".format(reduced_χ_squared), transform = ax.transAxes)
ax.legend(["Observed n", "Expected n"])
print("Fitted parameters: A = {:.4f}, D = {:.4f}, μ = {:.4f}, τ = {:.4f}".format(*vars))
print("Fitted parameter errors: σ_A = {:.4f}, σ_D = {:.4f}, σ_μ = {:.4f}, σ_τ = {:.4f}".format(*σ))
print("Reduced χ² = {:.4f}".format(reduced_χ_squared))
运行此代码将提供以下输出

正如我在上面的评论中提到的,相关性在这里是一个大问题。不过,最大的问题是,您要适应的参数比需要的多

让我们转变:

A=exp(alpha)即alpha=log(A)
δ=4*D
ε=mu*E
然后我们得到:

1/sqrt(pi*delta)*exp(-(x**2+ε**2*t**2-2*x*εt)/(delta*t)-t/tau+α)
=1/sqrt(π*delta)*exp(-(x**2+ε**2*t**2-2*x*εt)/(δ*t)-delta/tau*t**2/(δ*t)+δ*alpha*t/(δ*t))
=1/sqrt(π*δ)*exp(-(x**2+ε**2*t**2-2*x*εt+δ/τ*t**2-δ*α*t)/(δ*t))
=1/sqrt(π*δ)*exp(-(x**2+(ε**2+δ/tau)*t**2-x*(2*ε+δ*α)*t)/(δ*t))
现在重命名:

(ε**2+δ/tau)->γ**2
(2*ε+δ*α)->eta
我们得到

=1/sqrt(pi*delta)*exp(-(x**2+γ**2*t**2-x*eta*t)/(delta*t))
因此,实际上只有3个参数需要拟合,如下所示:


将numpy作为np导入
将matplotlib.pyplot作为plt导入
从scipy.optimize导入曲线\u拟合
#常数
E_字段=1
x=1
def函数(t,A,D,μ,τ):
返回A/np.sqrt(4*np.pi*D*t)*np.exp(-pow(x-μ*E_字段*t,2)/(4*D*t)-t/τ)
def alt_func(t、伽马、eta、增量):
返回np.exp(-x**2+gamma**2*t**2-eta*t)/(delta*t))/np.sqrt(np.pi*delta*t)
#选择随机变量以生成数据
x、 t=1,np.linspace(0.01,5,num=100)
A、 D,μ,τ=1,0.2,1,1
n=函数(t,A,D,μ,τ)
n_噪声=n+0.005*np.随机.正常(尺寸=n.尺寸)
n_noise+=abs(最小值(n_noise))#将数据移动到y=0
猜测=[1.34,2,8]
palt,covalt=曲线拟合(alt\U func,t,n\U噪声)
打印(covalt)
打印(palt)
yt=alt_func(t,*palt)
yg=alt_func(t,*猜测)
yorg=函数(t,A,D,μ,τ)
图,ax=plt.子批次()
ax.图(t,n_噪声)
ax.绘图(t,yg)
ax.绘图(t,yt,ls=“--”)
ax.绘图(t,yorg,ls=“:”)
plt.show()
这有一个合理的协方差矩阵。通过误差传播可以很容易地得到原始参数

altzernative,它应该足以修复
A=1
,并且只适合原始函数中的三个左参数


关于转换和反算,必须记住,这当然是从R³到R³⁴, 所以它自然也不是独一无二的。同样,可以只固定一个值,或者尝试在参数之间均匀分布误差,或者谁知道……

我认为这些对于非参数曲线拟合没有意义。我不会注意他们。合身的质量看起来不错。@Piterberg感谢您提供的信息。你知道我将如何计算拟合参数的误差吗?我将对每个拟合使用不同的随机数进行一系列拟合(即不要为
随机
调用固定种子),并计算拟合参数的标准偏差。但是坦白地说,我不完全确定计算这些误差的目的是什么。@Piterberg我在实验室实验中使用了这一点,但只是想测试scipy.curve_拟合对这个方程是否有效。你是说噪音的种子吗?在这种情况下,我将无法用真实的数据和一些想法做到这一点。第一,拟合似乎适合于你的合成数据。只要你的真实数据和你的合成数据相似,它就可以正常工作。如果不是,那么显然没有保证。第二,是的,我的意思是使用不同的种子。是的,这只会告诉您合成数据的参数错误。如果你的真实数据是相似的,你应该从这个实验中得到一些安慰。如果没有,你就不会。但是,这些曲线拟合的计算结果并不能告诉你我所建议的实验的更多信息(事实上,我不确定它们能告诉你任何事情)!