ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 17.04.2021

Просмотров: 3757

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Introduction to Python for Science, Release 0.9.23

t, N, dN

=

np

.

loadtxt(

"betaDecay.txt"

, skiprows

=

2

, unpack

=

True

)

########## Code to tranform & fit data starts here ##########

# Transform data and parameters to linear form: Y = A + B*X

X

=

t

# transform t data for fitting (trivial)

Y

=

np

.

log(N)

# transform N data for fitting

dY

=

dN

/

N

# transform uncertainties for fitting

# Fit transformed data X, Y, dY to obtain fitting parameters A & B

# Also returns uncertainties in A and B

B, A, dB, dA

=

LineFitWt(X, Y, dY)

# Return reduced chi-squared

redchisqr

=

redchisq(X, Y, dY, B, A)

# Determine fitting parameters for original exponential function

# N = N0 exp(-t/tau) ...

N0

=

np

.

exp(A)

tau

= -

1.0

/

B

# ... and their uncertainties

dN0

=

N0

*

dA

dtau

=

tau

**

2

*

dB

####### Code to plot transformed data and fit starts here #######

# Create line corresponding to fit using fitting parameters

# Only two points are needed to specify a straight line

Xext

=

0.05

*

(X

.

max()

-

X

.

min())

Xfit

=

np

.

array([X

.

min()

-

Xext, X

.

max()

+

Xext])

Yfit

=

A

+

B

*

Xfit

plt

.

errorbar(X, Y, dY, fmt

=

"bo"

)

plt

.

plot(Xfit, Yfit,

"r-"

, zorder

=-

1

)

plt

.

xlim(

0

,

100

)

plt

.

ylim(

1.5

,

7

)

plt

.

title(

"$\mathrm{Fit

\\

to:}

\\

\ln N = -t/

\\

tau + \ln N_0$"

)

plt

.

xlabel(

"t"

)

plt

.

ylabel(

"ln(N)"

)

plt

.

text(

50

,

6.6

,

"A = ln N0 = {0:0.2f} $\pm$ {1:0.2f}"

.

format(A, dA))

plt

.

text(

50

,

6.3

,

"B = -1/tau = {0:0.4f} $\pm$ {1:0.4f}"

.

format(

-

B, dB))

plt

.

text(

50

,

6.0

,

"$\chi_r^2$ = {0:0.3f}"

.

format(redchisqr))

8.1. Using linear regression for fitting non-linear functions

145


background image

Introduction to Python for Science, Release 0.9.23

plt

.

text(

50

,

5.7

,

"N0 = {0:0.0f} $\pm$ {1:0.0f}"

.

format(N0, dN0))

plt

.

text(

50

,

5.4

,

"tau = {0:0.1f} $\pm$ {1:0.1f} days"

.

format(tau, dtau))

plt

.

show()

8.1.2 Linear regression for fitting a power-law function

You can use a similar approach to the one outlined above to fit experimental data to a
power law fitting function of the form

P

(

s

) =

P

0

s

α

.

(8.7)

We follow the same approach we used for the exponential fitting function and first take
the logarithm of both sides of (

8.7

)

ln

P

= ln

P

0

+

α

ln

s .

(8.8)

We recast this in the form of a linear equation

y

=

a

+

bx

with the following identifica-

tions:

x

= ln

s

y

= ln

P

a

= ln

P

0

b

=

α

(8.9)

Following a procedure similar to that used to fit using an exponential fitting function, you
can use the tranformations given by (

8.9

as the basis for a program to fit a power-law

fitting function such as (

8.8

to experimental data.

8.2 Nonlinear fitting

The method introduced in the previous section for fitting nonlinear fitting functions can
be used only if the fitting function can be transformed into a fitting function that is linear
in the fitting parameters

a

,

b

,

c

... When we have a nonlinear fitting function that cannot

be transformed into a linear form, we need another approach.

The problem of finding values of the fitting parameters that minimize

χ

2

is a nonlinear op-

timization problem to which there is quite generally no analytical solution (in contrast to

146

Chapter 8. Curve Fitting


background image

Introduction to Python for Science, Release 0.9.23

the linear optimization problem). We can gain some insight into this nonlinear optimiza-
tion problem, namely the fitting of a nonlinear fitting function to a data set, by considering
a fitting function with only two fitting parameters. That is, we are trying to fit some data
set

{

x

i

, y

i

}

, with uncertainties in

{

y

i

}

of

{

σ

i

}

, to a fitting function is

f

(

x

;

a, b

)

where

a

and

b

are the two fitting parameters. To do so, we look for the minimum in

χ

2

(

a, b

) =

X

i

y

i

f

(

x

i

)

σ

i

2

.

Note that once the data set, uncertainties, and fitting function are specified,

χ

2

(

a, b

)

is

simply a function of

a

and

b

. We can picture the function

χ

2

(

a, b

)

as a of landscape with

peaks and valleys: as we vary

a

and

b

,

χ

2

(

a, b

)

rises and falls. The basic idea of all

nonlinear fitting routines is to start with some initial guesses for the fitting parameters,
here

a

and

b

, and by scanning the

χ

2

(

a, b

)

landscape, find values of

a

and

b

that minimize

χ

2

(

a, b

)

.

There are a number of different methods for trying to find the minimum in

χ

2

for non-

linear fitting problems. Nevertheless, the method that is most widely used goes by the
name of the

Levenberg-Marquardt

method. Actually the Levenberg-Marquardt method

is a combination of two other methods, the

steepest descent

(or gradient) method and

parabolic extrapolation

. Roughly speaking, when the values of

a

and

b

are not too near

their optimal values, the gradient descent method determines in which direction in

(

a, b

)

-

space the function

χ

2

(

a, b

)

decreases most quickly—the direction of steepest descent—

and then changes

a

and

b

accordingly to move in that direction. This method is very

efficient unless

a

and

b

are very near their optimal values. Near the optimal values of

a

and

b

, parabolic extrapolation is more efficient. Therefore, as

a

and

b

approach their

optimal values, the Levenberg-Marquardt method gradually changes to the parabolic ex-
trapolation method, which approximates

χ

2

(

a, b

)

by a Taylor series second order in

a

and

b

and then computes directly the analytical minimum of the Taylor series approximation

of

χ

2

(

a, b

)

. This method is only good if the second order Taylor series provides a good

approximation of

χ

2

(

a, b

)

. That is why parabolic extrapolation only works well very near

the minimum in

χ

2

(

a, b

)

.

Before illustrating the Levenberg-Marquardt method, we make one important cautionary
remark: the Levenberg-Marquardt method can fail if the initial guesses of the fitting pa-
rameters are too far away from the desired solution. This problem becomes more serious
the greater the number of fitting parameters. Thus it is important to provide reasonable
initial guesses for the fitting parameters. Usually, this is not a problem, as it is clear from
the physical situation of a particular experiment what reasonable values of the fitting pa-
rameters are. But beware!

The

scipy.optimize

module provides routines that implement the Levenberg-

Marquardt non-linear fitting method. One is called

scipy.optimize.leastsq

.

8.2. Nonlinear fitting

147


background image

Introduction to Python for Science, Release 0.9.23

A

somewhat

more

user-friendly

version

of

the

same

method

is

accessed

through another routine in the same

scipy.optimize

module:

it’s called

scipy.optimize.curve_fit

and it is the one we demonstrate here.

The

function call is

import scipy.optimize

[... insert code here ...]

scipy.optimize.curve_fit(f, xdata, ydata, p0=None, sigma=None,

**kwargs)

The arguments of

curve_fit

are

f(xdata, a, b, ...)

: is the fitting function where

xdata

is the data for the

independent variable and

a, b, ...

are the fitting parameters, however many

there are, listed as separate arguments. Obviously,

f(xdata, a, b, ...)

should return the

y

value of the fitting function.

xdata

: is the array containing the

x

data.

ydata

: is the array containing the

y

data.

p0

: is a tuple containing the initial guesses for the fitting parameters. The guesses

for the fitting parameters are set equal to 1 if they are left unspecified. It is almost
always a good idea to specify the initial guesses for the fitting parameters.

sigma

: is the array containing the uncertainties in the

y

data.

**kwargs

: are keyword arguments that can be passed to the fitting routine

scipy.optimize.leastsq

that

curve_fit

calls. These are usually left

unspecified.

We demonstrate the use of

curve_fit

to fit the data plotted in the figure below:

We model the data with the fitting function that consists of a quadratic polynomial back-
ground with a Gaussian peak:

A

(

f

) =

a

+

bf

+

cf

2

+

P e

1
2

[(

f

f

p

)

/f

w

]

2

.

Lines 7 and 8 define the fitting functions. Note that the independent variable

f

is the first

argument, which is followed by the six fitting parameters

a

,

b

,

c

,

P

,

f

p

, and

f

w

.

To fit the data with

A

(

f

)

, we need good estimates of the fitting parameters. Setting

f

= 0

,

we see that

a

60

. An estimate of the slope of the baseline gives

b

≈ −

60

/

20 =

3

.

The curvature in the baseline is small so we take

c

0

. The amplitude of the peak above

the baseline is

P

80

. The peak is centered at

f

p

11

, while width of peak is about

f

w

2

. We use these estimates to set the initial guesses of the fitting parameters in lines

14 and 15 in the code below.

148

Chapter 8. Curve Fitting


background image

Introduction to Python for Science, Release 0.9.23

0

5

10

15

20

25

frequency (THz)

0

20

40

60

80

100

120

absorption (arb units)

The function that performs the Levenverg-Marquardt algorithm,

scipy.optimize.curve_fit

,

is called in lines 19-20 with the output set equal to the one and two-dimensional arrays

nlfit

and

nlpcov

, respectively. The array

nlfit

, which gives the optimal values of

the fitting parameters, is unpacked in line 23. The square root of the diagonal of the two-
dimensional array

nlpcov

, which gives the estimates of the uncertainties in the fitting

parameters, is unpacked in lines 26-27 using a list comprehension.

The rest of the code plots the data, the fitting function using the optimal values of the
fitting parameters found by

scipy.optimize.curve_fit

, and the values of the

fitting parameters and their uncertainties.

1

import

numpy

as

np

2

import

matplotlib.pyplot

as

plt

3

import

matplotlib.gridspec

as

gridspec

# for unequal plot boxes

4

import

scipy.optimize

5

6

# define fitting function

7

def

GaussPolyBase

(f, a, b, c, P, fp, fw):

8

return

a

+

b

*

f

+

c

*

f

*

f

+

P

*

np

.

exp(

-

0.5

*

((f

-

fp)

/

fw)

**

2

)

9

10

# read in spectrum from data file

11

# f=frequency, s=signal, ds=s uncertainty

12

f, s, ds

=

np

.

loadtxt(

"Spectrum.txt"

, skiprows

=

4

, unpack

=

True

)

13

8.2. Nonlinear fitting

149