简体   繁体   English

如何使用 scipy.optimize.least_squares 计算标准偏差误差

[英]How to compute standard deviation errors with scipy.optimize.least_squares

I compare fitting with optimize.curve_fit and optimize.least_squares.我将拟合与 optimize.curve_fit 和 optimize.least_squares 进行比较。 With curve_fit I get the covariance matrix pcov as an output and I can calculate the standard deviation errors for my fitted variables by that:使用曲线拟合,我将协方差矩阵 pcov 作为输出,我可以通过以下方式计算拟合变量的标准偏差误差:

perr = np.sqrt(np.diag(pcov))

If I do the fitting with least_squares, I do not get any covariance matrix output and I am not able to calculate the standard deviation errors for my variables.如果我使用least_squares 进行拟合,则不会得到任何协方差矩阵输出,并且无法计算变量的标准偏差误差。

Here's my example:这是我的例子:

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

noise = 0.5
N = 100
t = np.linspace(0, 4*np.pi, N)

# generate data
def generate_data(t, freq, amplitude, phase, offset, noise=0, n_outliers=0, random_state=0):
    #formula for data generation with noise and outliers
    y = np.sin(t * freq + phase) * amplitude + offset
    rnd = np.random.RandomState(random_state)
    error = noise * rnd.randn(t.size)
    outliers = rnd.randint(0, t.size, n_outliers)
    error[outliers] *= 10
    return y + error

#generate data
data = generate_data(t, 1, 3, 0.001, 0.5, noise, n_outliers=10)

#initial guesses
p0=np.ones(4)
x0=np.ones(4)

# create the function we want to fit
def my_sin(x, freq, amplitude, phase, offset):
    return np.sin(x * freq + phase) * amplitude + offset

# create the function we want to fit for least-square
def my_sin_lsq(x, t, y):
    # freq=x[0]
    # phase=x[1]
    # amplitude=x[2]
    # offset=x[3]
    return (np.sin(t*x[0]+x[2])*x[1]+ x[3]) - y

# now do the fit for curve_fit
fit = curve_fit(my_sin, t, data, p0=p0)
print 'Curve fit output:'+str(fit[0])

#now do the fit for least_square
res_lsq = least_squares(my_sin_lsq, x0, args=(t, data))
print 'Least_squares output:'+str(res_lsq.x)


# we'll use this to plot our first estimate. This might already be good enough for you
data_first_guess = my_sin(t, *p0)

#data_first_guess_lsq = x0[2]*np.sin(t*x0[0]+x0[1])+x0[3]
data_first_guess_lsq = my_sin(t, *x0)

# recreate the fitted curve using the optimized parameters
data_fit = my_sin(t, *fit[0])
data_fit_lsq = my_sin(t, *res_lsq.x)

#calculation of residuals
residuals = data - data_fit
residuals_lsq = data - data_fit_lsq
ss_res = np.sum(residuals**2)
ss_tot = np.sum((data-np.mean(data))**2)
ss_res_lsq = np.sum(residuals_lsq**2)
ss_tot_lsq = np.sum((data-np.mean(data))**2)

#R squared
r_squared = 1 - (ss_res/ss_tot)
r_squared_lsq = 1 - (ss_res_lsq/ss_tot_lsq)
print 'R squared curve_fit is:'+str(r_squared)
print 'R squared least_squares is:'+str(r_squared_lsq)

plt.figure()
plt.plot(t, data)
plt.title('curve_fit')
plt.plot(t, data_first_guess)
plt.plot(t, data_fit)
plt.plot(t, residuals)

plt.figure()
plt.plot(t, data)
plt.title('lsq')
plt.plot(t, data_first_guess_lsq)
plt.plot(t, data_fit_lsq)
plt.plot(t, residuals_lsq)

#error
perr = np.sqrt(np.diag(fit[1]))
print 'The standard deviation errors for curve_fit are:' +str(perr)

I would be very thankful for any help, best wishes我将非常感谢任何帮助,最良好的祝愿

ps: I got a lot of input from this source and used part of the code Robust regression ps:我从这个来源得到了很多输入,并使用了部分代码稳健回归

The result of optimize.least_squares has a parameter inside of it called jac. optimize.least_squares 的结果内部有一个名为 jac 的参数。 From the documentation :文档

jac : ndarray, sparse matrix or LinearOperator, shape (m, n) jac : ndarray, 稀疏矩阵或 LinearOperator, 形状 (m, n)

Modified Jacobian matrix at the solution, in the sense that J^TJ is a Gauss-Newton approximation of the Hessian of the cost function.解决方案处的修正雅可比矩阵,从某种意义上说,J^TJ 是成本函数 Hessian 的高斯-牛顿近似。 The type is the same as the one used by the algorithm.类型与算法使用的类型相同。

This can be used to estimate the Covariance Matrix of the parameters using the following formula: Sigma = (J'J)^-1.这可用于使用以下公式估计参数的协方差矩阵:Sigma = (J'J)^-1。

J = res_lsq.jac
cov = np.linalg.inv(J.T.dot(J))

To find the variance of the parameters one can then use:要找到参数的方差,然后可以使用:

var = np.sqrt(np.diagonal(cov))

The SciPy program optimize.least_squares requires the user to provide in input a function fun(...) which returns a vector of residuals. SciPy 程序optimize.least_squares要求用户在输入中提供一个函数fun(...) ,该函数返回一个残差向量。 This is typically defined as这通常定义为

residuals = (data - model)/sigma

where data and model are vectors with the data to fit and the corresponding model predictions for each data point, while sigma is the 1σ uncertainty in each data value.其中datamodel是向量,其中包含要拟合的数据和每个数据点的相应模型预测,而sigma是每个data值的 1σ 不确定性。

In this situation, and assuming one can trust the input sigma uncertainties, one can use the output Jacobian matrix jac returned by least_squares to estimate the covariance matrix.在这种情况下,假设一个可以信任的输入sigma的不确定性,可以使用输出雅可比矩阵jac由归国least_squares来估计协方差矩阵。 Moreover, assuming the covariance matrix is diagonal, or simply ignoring non-diagonal terms, one can also obtain the 1σ uncertainty perr in the model parameters (often called "formal errors") as follows (see Section 15.4.2 of Numerical Recipes 3rd ed. )此外,假设协方差矩阵是对角的,或者简单地忽略非对角项,还可以得到模型参数中的 1σ 不确定性perr (通常称为“形式误差”)如下(参见第3 版 Numerical Recipes 的第 15.4.2 节) . )

import numpy as np
from scipy import linalg, optimize

res = optimize.least_squares(...)

U, s, Vh = linalg.svd(res.jac, full_matrices=False)
tol = np.finfo(float).eps*s[0]*max(res.jac.shape)
w = s > tol
cov = (Vh[w].T/s[w]**2) @ Vh[w]  # robust covariance matrix
perr = np.sqrt(np.diag(cov))     # 1sigma uncertainty on fitted parameters

The above code to obtain the covariance matrix is formally the same as the following simpler one (as suggested by Alex), but the above has the major advantage that it works even when the Jacobian is close to degenerate, which is a common occurrence in real-world least-squares fits上面获取协方差矩阵的代码形式上与下面的简单代码相同(如 Alex 所建议的),但上面的主要优点是即使雅可比矩阵接近退化时也能工作,这在现实中很常见-世界最小二乘拟合

cov = linalg.inv(res.jac.T @ res.jac)  # covariance matrix when jac not degenerate

If one does not trust the input uncertainties sigma , one can still assume that the fit is good, to estimate the data uncertainties from the fit itself.如果不相信输入的不确定性sigma ,仍然可以假设拟合良好,从拟合本身估计数据的不确定性。 This corresponds to assuming chi**2/DOF=1 , where DOF is the number of degrees of freedom.这对应于假设chi**2/DOF=1 ,其中DOFDOF数。 In this case, one can use the following lines to rescale the covariance matrix before computing the uncertainties在这种情况下,可以使用以下几行在计算不确定性之前重新调整协方差矩阵

chi2dof = np.sum(res.fun**2)/(res.fun.size - res.x.size)
cov *= chi2dof
perr = np.sqrt(np.diag(cov))    # 1sigma uncertainty on fitted parameters

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM