Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
| Download
Project: Computational Tutorials
Path: fitting.py
Views: 3Visibility: Unlisted (only visible to those who know the link)
Image: ubuntu2204# DO NOT CHANGE THIS FILE!1#2# This file contains the functions linear_fit for fitting a straight3# line to data and general_fit for fitting any user-defined funciton4# to data. To use either of them, the first line of your program5# should be "from fitting import *".67from __future__ import print_function # in case Python 2 is used89from math import sqrt10from scipy import odr11121314def linear_fit(xdata, ydata, sigmay=None, sigmax=None):15"""16Performs a linear fit to data.1718Parameters19----------20xdata : An array of length N.21ydata : An array of length N.2223sigmay : None or an array of length N.24sigmax : None or an array of length N.25If one is provided, it is the standard deviation of ydata. Analytical linear regression used.26If both are provided, they are the standard deviations of ydata and xdata, respectively. ODR is used.2728Returns29-------30a, b : Optimal parameter of linear fit (y = a*x + b)31sa, sb : Uncertainties of the parameters32"""3334def lin_func(p, x):35a, b = p36return a*x + b3738dof = len(ydata) - 23940if sigmax is None:41if sigmay is None:42w = ones(len(ydata)) # Each point is equally weighted.43else:44w=1.0/(sigmay**2)4546sw = sum(w)47wx = w*xdata # this product gets used to calculate swxy and swx248swx = sum(wx)49swy = sum(w*ydata)50swxy = sum(wx*ydata)51swx2 = sum(wx*xdata)5253a = (sw*swxy - swx*swy)/(sw*swx2 - swx*swx)54b = (swy*swx2 - swx*swxy)/(sw*swx2 - swx*swx)55sa = sqrt(sw/(sw*swx2 - swx*swx))56sb = sqrt(swx2/(sw*swx2 - swx*swx))5758if sigmay is None:59chi2 = sum(((a*xdata + b)-ydata)**2)60else:61chi2 = sum((((a*xdata + b)-ydata)/sigmay)**2)62rchi2 = chi2/dof6364else:65# make the initial guess a line passing through first and last points66a0 = (ydata[-1]-ydata[0])/(xdata[-1]-xdata[0])67b0 = ydata[0]-xdata[0]*a068model = odr.Model(lin_func)69data = odr.RealData(x=xdata, y=ydata, sx=sigmax, sy=sigmay)70od = odr.ODR(data, model, [a0,b0])71out = od.run()72a,b = out.beta73sa,sb = out.sd_beta74rchi2 = out.res_var7576# From: https://www.physics.utoronto.ca/~phy326/python/odr_fit_to_data.py77# scipy.odr scales the parameter uncertainties by the reduced chi78# square (out.res_var). If the fit is poor, i.e. reduced chisq is79# large, the uncertainties are scaled up, which makes sense. If the80# fit is "too good", i.e. reduced chisq << 1, it suggests that the81# uncertainties may have been overestimated, but it seems risky to82# scale down the uncertainties.83if rchi2 < 1.0 :84sa = sa/sqrt(rchi2)85sb = sb/sqrt(rchi2)8687if sigmay is None:88print('results of linear_fit: no uncertainties provided, so use with caution')89else:90print('results of linear_fit:')9192# print(' chi squared = ', chi2)93print(' reduced chi squared = ', rchi2)94print(' degrees of freedom = ', dof)959697return a, b, sa, sb, rchi2, dof9899100from scipy.optimize import curve_fit101from pylab import * # for array, zeros, arange102103104#def general_fit(f, xdata, ydata, p0=None, sigma=None, **kw):105def general_fit(f, xdata, ydata, p0=None, sigmay=None, sigmax=None):106107"""108Pass all arguments to curve_fit, which uses non-linear least squares109to fit a function, f, to data. Calculate the uncertaities in the110fit parameters from the covariance matrix.111"""112113dof = len(ydata) - len(p0)114115if sigmax is None:116popt, pcov = curve_fit(f, xdata, ydata, p0, sigmay)117118if sigmay is None:119chi2 = sum(((f(xdata,*popt)-ydata))**2)120else:121chi2 = sum(((f(xdata,*popt)-ydata)/sigmay)**2)122# dof = len(ydata) - len(popt)123rchi2 = chi2/dof124# The uncertainties are the square roots of the diagonal elements125punc = zeros(len(popt))126for i in arange(0,len(popt)):127punc[i] = sqrt(pcov[i,i])128else:129# ODR expects a funciton with parameters, then x130def f_fixed(p,x):131return f(x,*p)132133model = odr.Model(f_fixed)134data = odr.RealData(x=xdata, y=ydata, sx=sigmax, sy=sigmay)135od = odr.ODR(data, model, p0)136out = od.run()137popt = out.beta138punc = out.sd_beta139rchi2 = out.res_var140141# From: https://www.physics.utoronto.ca/~phy326/python/odr_fit_to_data.py142# scipy.odr scales the parameter uncertainties by the reduced chi143# square (out.res_var). If the fit is poor, i.e. reduced chisq is144# large, the uncertainties are scaled up, which makes sense. If the145# fit is "too good", i.e. reduced chisq << 1, it suggests that the146# uncertainties may have been overestimated, but it seems risky to147# scale down the uncertainties.148if rchi2 < 1.0 :149punc = punc/sqrt(rchi2)150if sigmay is None:151print('results of general_fit: no uncertainties provided, so use with caution')152else:153print('results of general_fit:')154# print(' chi squared = ', chi2)155print(' degrees of freedom = ', dof)156print(' reduced chi squared = ', rchi2)157158return popt, punc, rchi2, dof159160