Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scipy curvefit RuntimeError:Optimal parameters not found: Number of calls to function has reached maxfev = 1000

I want to make an logharitmic fit. But I keep getting the a runtime error:

Optimal parameters not found: Number of calls to function has reached maxfev = 1000

I use the following script. Can anyone tell me where I go wrong? I use Spyder an am still a beginner.

import math
import matplotlib as mpl
from scipy.optimize import curve_fit
import numpy as np

#data
F1=[735.0,696.0,690.0,683.0,680.0,678.0,679.0,675.0,671.0,669.0,668.0,664.0,664.0]
t1=[1,90000.0,178200.0,421200.0,505800.0,592200.0,768600.0,1036800.0,1371600.0,1630800.0,1715400.0,2345400.0,2409012.0]

F1n=np.array(F1)
t1n=np.array(t1)

plt.plot(t1,F1,'ro',label="original data")

# curvefit
def func(t,a,b):
    return a+b*np.log(t)

t=np.linspace(0,3600*24*28,13)

popt, pcov = curve_fit(func, t, F1n, maxfev=1000)    

plt.plot(t, func(t, *popt), label="Fitted Curve")

plt.legend(loc='upper left')
plt.show()
like image 214
Tjitze Avatar asked Apr 05 '13 10:04

Tjitze


4 Answers

Scipy's

     curve_fit() 

uses iterations to search for optimal parameters. If the number of iterations exceeds the default number of 800, but the optimal parameters are still not found, then this error will be raised.

    Optimal parameters not found: Number of calls to function has reached maxfev = 800

You can provide some initial guess parameters for curve_fit(), then try again. Or, you can increase the allowable iterations. Or do both!

Here is an example:

    popt, pcov = curve_fit(exponenial_func, x, y, p0=[1,0,1], maxfev=5000)

p0 is the guess

maxfev is the max number of iterations

You can also try setting bounds which will help the function find the solution. However, you cannot set bounds and a max_nfev at the same time.

    popt, pcov = curve_fit(exponenial_func, x, y, p0=[1,0,1], bounds=(1,3))

Source1: https://github.com/scipy/scipy/issues/6340

Source2: My own testing and finding that the about github is not 100% accurate

Also, other recommendations about not using 0 as an 'x' value are great recommendations. Start your 'x' array with 1 to avoid divide by zero errors.

like image 195
embulldogs99 Avatar answered Oct 21 '22 05:10

embulldogs99


Your original data is t1 and F1. Therefore curve_fit should be given t1 as its second argument, not t.

popt, pcov = curve_fit(func, t1, F1, maxfev=1000)

Now once you obtain fitted parameters, popt, you can evaluate func at the points in t to obtain a fitted curve:

t = np.linspace(1, 3600 * 24 * 28, 13)
plt.plot(t, func(t, *popt), label="Fitted Curve")

(I removed zero from t (per StuGrey's answer) to avoid the Warning: divide by zero encountered in log.)


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

# data
F1 = np.array([
    735.0, 696.0, 690.0, 683.0, 680.0, 678.0, 679.0, 675.0, 671.0, 669.0, 668.0,
    664.0, 664.0])
t1 = np.array([
    1, 90000.0, 178200.0, 421200.0, 505800.0, 592200.0, 768600.0, 1036800.0,
    1371600.0, 1630800.0, 1715400.0, 2345400.0, 2409012.0])

plt.plot(t1, F1, 'ro', label="original data")

# curvefit

def func(t, a, b):
    return a + b * np.log(t)

popt, pcov = optimize.curve_fit(func, t1, F1, maxfev=1000)
t = np.linspace(1, 3600 * 24 * 28, 13)
plt.plot(t, func(t, *popt), label="Fitted Curve")
plt.legend(loc='upper left')
plt.show()

enter image description here

like image 34
unutbu Avatar answered Oct 21 '22 05:10

unutbu


Curve_fit() uses iterations to search for optimal parameters. If the number of iterations exceeds the set number of 1000, but the optimal parameters are still not available, then this error will be raised. You can provide some initial guess parameters for curve_fit(), then try again.

like image 3
Hanrong Zheng Avatar answered Oct 21 '22 05:10

Hanrong Zheng


After fixing your import statements:

#import matplotlib as mpl
import matplotlib.pyplot as plt

your code produced the following error:

RuntimeWarning: divide by zero encountered in log

changing:

#t=np.linspace(0,3600*24*28,13)
t=np.linspace(1,3600*24*28,13)

produced the following output:

enter image description here

like image 2
StuGrey Avatar answered Oct 21 '22 04:10

StuGrey