def model(A, x, mu, sigma):
return A*exp(-((x-mu)**2)/(2*sigma**2))
from scipy.optimize import curve_fit
mu=np.mean(d_spacing_2)
sigma=np.std(d_spacing_2)
f=intensity_2
x=d_spacing_2
popt, pcov = curve_fit(model, A, x, mu, sigma)
TypeError: model() missing 2 required positional arguments: 'mu' and 'sigma'
You are using curve_fit totally wrong. Here is working example from the help of curve_fit and some additional plotting:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def func(x, a, b, c):
return a * np.exp(-b * x) + c
xdata = np.linspace(0, 4, 50)
y = func(xdata, 2.5, 1.3, 0.5)
ydata = y + 0.2 * np.random.normal(size=len(xdata))
popt, pcov = curve_fit(func, xdata, ydata,p0=[2,1,1])
plt.ion()
plt.plot(xdata,ydata,'o')
xplot = np.linspace(0,4,100)
plt.plot(xplot,func(xplot,*popt))
The first input argument of curve_fit is the function the second the x values of the data and the third the y values. You should normally also use the optional input argument p0, which is an initial guess for the solution.
Related
I am trying to find the best values for my model y = aX +b by using optimization.curve_fit but keep getting the following error:
func() missing 1 required positional argument: 'b'
My code is as follows:
def func(x, y, a, b):
return y == a*x + b
xdata = np.array(time1_list)
ydata = np.array(phi1_list)
# Initial guess.
x0 = np.array([0.0, 0.0])
print(optimization.curve_fit(func, xdata, ydata, x0))
I have tried using this optimization method but cannot seem to get past this error. The data consists of 2 lists, xdata and ydata. My model is y = ax+b.
Eventually I will be using a least squares fit to find the optimum values of a and b.
Need to change the definition of your function like this:
def func(x, a, b):
y = a*x + b
return y
Here is full exemple:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def func(x, a, b):
y = a*x + b
return y
xdata = np.linspace(1, 10, 100)
y = func(xdata, 2, 5)
rng = np.random.default_rng()
y_noise = rng.normal(size=xdata.size) *0.2
ydata = y + y_noise
# Initial guess.
x0 = np.array([0.0, 0.0])
# print(optimization.curve_fit(func, xdata, ydata, x0))
popt, pcov = curve_fit(func, xdata, ydata, x0)
plt.figure()
plt.plot(xdata, ydata, 'b-', label='data')
plt.plot(xdata, func(xdata, *popt), 'r-',label='fit: a=%5.3f, b=%5.3f' % tuple(popt))
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
You will get the figure :
I can't figure out why my curve_fit is not following the data?
import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio
import math
from scipy.stats import binom, poisson, norm
from scipy.optimize import curve_fit
AD1 = sio.loadmat('ATLAS_DATA1' ,squeeze_me=True,mat_dtype = True)
locals().update({k :AD1[k]for k in ['n','e']})
xData = e
yData = n
yErr = 0
plt.xlabel("e (GeV)")
plt.ylabel("Number of events (n)")
plt.errorbar(xData,yData,yErr,marker = '.',linestyle = '')
plt.show()
def func(e, a, b):
return a * np.exp(-b * e)
xDat = e
yDat = func(xDat, 2, 1)
popt, pcov = curve_fit(func, xDat, yDat)
plt.plot(xDat, func(xDat, *popt))
plt.show()
Below is my data for n at the top and e at the bottom.
Data for n and e
Graph for the data that i want to fit
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as optimize
from scipy.optimize import curve_fit
Write your xData and yData as numpy arrays as follows:
I used a sample from it
xData =np.array([383,358,326,366,335,331,308,299,303,325,306,299,270,282,253,265,248,256,220,208,252,215,220,237,204,213,224,212])
yData = np.array([101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,124,128])
plt.xlabel("e (GeV)")
plt.ylabel("Number of events (n)")
plt.scatter(xData,yData)
plt.show()
Heres the original data
Its bettter to use plt.scatter than plt.errorbar
i found this equation better for your curve
def func(x, a, c, d):
return a*np.exp(-c*x)+d
Same thing goes for xDat (write it as np.array)
xDat = xData
yDat = func(xDat, 2, 1)
plt.scatter(xDat,yDat)
popt, pcov = curve_fit(func, xData, yData,p = (10, 1e-6, 100))
plt.plot(xDat, func(xDat, *popt))
plt.show()
Tip: Dont use lower case e as a variable, because most of the time e represents the exponential constant e=2.77
UPDATE :
if you want to use your original function heres the code:
def func(e, a, b):
return a * np.exp(-b * e)
popt, pcov = curve_fit(func, xData, yData,p0 = [10,-0.00001])
I am trying to fit a data generated using formula-1 by formula-2. The former has 3 parameters, whereas the later has 5 fitting parameters. But now I get error in plotting the fitted curve due to shape mismatch.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def func(x, a, b, c, d, e):
return (((a/e) * (2*x)**b) + (d * (2*x)**c))
y = []
x = []
A = 6.7
B = 2.0
C = 0.115
for N in np.logspace(1, 9., 100, base = 10.):
x.append(int(N))
y.append(np.exp((A-np.log(int(N)))/B)+C)
plt.loglog(x, y, 'b:*', label='data')
popt, pcov = curve_fit(func, x, y)
print(popt)
plt.loglog(x, func(x, *popt))
I would like to see the fitted curve, but there s a dimension error in the last line '''plt.loglog(x, func(x, *popt))'''
One way to do this is to create a list y_model in which you add the element y corresponding to each x.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def func(x, a, b, c, d, e):
return (((a/e) * (2*x)**b) + (d * (2*x)**c))
y = []
x = []
A = 6.7
B = 2.0
C = 0.115
for N in np.logspace(1, 9., 100, base = 10.):
x.append(int(N))
y.append(np.exp((A-np.log(int(N)))/B)+C)
popt, pcov = curve_fit(func, x, y)
y_model = []
for e in x:
y_model.append(func(e, *popt))
plt.loglog(x, y, 'b:*', label='data')
plt.loglog(x, y_model)
Result:
I'm using scipy.optimize.curve_fit to approximate peaks in my data with Gaussian functions. This works well for strong peaks, but it is more difficult with weaker peaks. However, I think fixing a parameter (say, width of the Gaussian) would help with this. I know I can set initial "estimates" but is there a way that I can easily define a single parameter without changing the function I'm fitting to?
If you want to "fix" a parameter of your fit function, you can just define a new fit function which makes use of the original fit function, yet setting one argument to a fixed value:
custom_gaussian = lambda x, mu: gaussian(x, mu, 0.05)
Here's a complete example of fixing sigma of a Gaussian function to 0.05 (instead of optimal value 0.1). Of course, this doesn't really make sense here because the algorithm has no problem in finding optimal values. Yet, you can see how mu is still found despite the fixed sigma.
import matplotlib.pyplot as plt
import numpy as np
import scipy.optimize
def gaussian(x, mu, sigma):
return 1 / sigma / np.sqrt(2 * np.pi) * np.exp(-(x - mu)**2 / 2 / sigma**2)
# Create sample data
x = np.linspace(0, 2, 200)
y = gaussian(x, 1, 0.1) + np.random.rand(*x.shape) - 0.5
plt.plot(x, y, label="sample data")
# Fit with original fit function
popt, _ = scipy.optimize.curve_fit(gaussian, x, y)
plt.plot(x, gaussian(x, *popt), label="gaussian")
# Fit with custom fit function with fixed `sigma`
custom_gaussian = lambda x, mu: gaussian(x, mu, 0.05)
popt, _ = scipy.optimize.curve_fit(custom_gaussian, x, y)
plt.plot(x, custom_gaussian(x, *popt), label="custom_gaussian")
plt.legend()
plt.show()
Hopefully this is helpful. Had to use hax. Curve_fit is pretty strict about what it takes.
import numpy as np
from numpy import random
import scipy as sp
from scipy.optimize import curve_fit
import matplotlib.pyplot as pl
def exp1(t,a1,tau1):
#A1*exp(-t/t1)
val=0.
val=(a1*np.exp(-t/tau1))*np.heaviside(t,0)
return val
def wrapper(t,*args):
global hold
global p0
wrapperName='exp1(t,'
for i in range(0, len(hold)):
if hold[i]:
wrapperName+=str(p0[i])
else:
if i%2==0:
wrapperName+='args['+str(i)+']'
else:
wrapperName+='args'+str(i)+']'
if i<len(hold):
wrapperName+=','
wrapperName+=')'
return eval(wrapperName)
p0=np.array([1.5,500.])
hold=np.array([0,1])
p1=np.delete(p0,1)
timepoints = np.arange(0.,2000.,20.)
y=exp1(timepoints,1,1000)+np.random.normal(0, .1, size=len(timepoints))
popt, pcov = curve_fit(exp1, timepoints, y, p0=p0)
print 'unheld parameters:', popt, pcov
popt, pcov = curve_fit(wrapper, timepoints, y, p0=p1)
for i in range(0, len(hold)):
if hold[i]:
popt=np.insert(popt,i,p0[i])
yfit=exp1(timepoints,popt[0],popt[1])
pl.plot(timepoints,y,timepoints,yfit)
pl.show()
print 'hold parameters:', popt, pcov
I have been working on fitting a negatively sloped sigmoidal trendline for a set of data. I have only been working on python for a week, sorry for the sloppy code. I have two sets of code which produce the data, however, I cannot get the sigmoid curve output as well.
from numpy import *
from matplotlib.pyplot import *
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def sigmoid(x, x0, k):
y = 1 / (1 + np.exp(-(-k*(x-x0))))
return y
x = [0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001]
y = [0.649097038, 0.682633434, 0.705470344, 0.749350609, 0.989377822, 0.972679201]
coefficients = np.polyfit(x, y, 2)
polynomial = poly1d(coefficients)
xs = arange(0.000001, 0, 0.1)
ys = polynomial(xs)
curve_fit(sigmoid, x, y)
semilogx()
np.polyfit(x, y, 3, rcond=None, full=False, w=None, cov=False)
plot(x, y, 'o')
plot(xs, ys)
ylabel('Cell Viability')
xlabel('Concentration mM')
show()
.
import numpy as np
import pylab
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def sigmoid(x, x0, k):
y = 1 / (1 + np.exp(-(-k*(x-x0))))
return y
xdata = np.array([0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001])
ydata = np.array([0.649097038, 0.682633434, 0.705470344, 0.749350609, 0.989377822, 0.972679201])
popt, pcov = curve_fit(sigmoid, xdata, ydata)
print popt
x = np.linspace(-10, 1, 50)
y = sigmoid(x, *popt)
semilogx()
pylab.plot(xdata, ydata, 'o', label='data')
pylab.plot(x,y, label='fit')
pylab.ylim(0, 1.05)
pylab.legend(loc='best')
pylab.show()
There are a number of issues with your two code pieces - some of which Ajean has hinted at. Let's carefully review what there is and what problems that causes.
1st Code Block
Discard the first two lines and use only:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
Now, instead of poly1d, you'll have to call np.poly1d; instead of semilogx() it's plt.semilogx(); plot, xlabel, ylabel and show become plt.plot, etc.
Next, your use of arange returns an empty array. Instead, try this:
np.arange(0.000001, 0.1, 0.000001)
From curvefit you should actually store the returns, as your second code does:
popt, pcov = curve_fit(sigmoid, x, y)
Next, use sigmoid to generate new y-values:
ysig = sigmoid(x,*popt)
If now you include an additional plot statement at the bottom, e.g.:
plt.plot(x,ysig,'g')
the output will be something like this:
2nd Code Block
It is sufficient to import matplotlib.pyplot as plt. Now, replace the pylab. occurrences with plt.
However, all that does not really work, is the linspace command. If you try
x = np.arange(0.000001, 0.1, 0.000001)
instead, you'll get this output
However, both approaches indicate that your fit does not really suit the data. But that may be a different question.
This is what I have for code block 1.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def sigmoid(x, x0, k):
y = 1 / (1 + np.exp(-(-k*(x-x0))))
return y
x = [0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001]
y = [0.649097038, 0.682633434, 0.705470344, 0.749350609, 0.989377822, 0.972679201]
coefficients = np.polyfit(x, y, 3)
polynomial = np.poly1d(coefficients)
popt, pcov = curve_fit(sigmoid, x, y)
ysig = sigmoid(x, *popt)
plt.semilogx()
np.arange(0.000001, 0.1, 0.000001)
np.polyfit(x, y, 3, rcond=None, full=False, w=None, cov=False)
plt.plot(x, y, 'o')
plt.plot(x, ysig, 'g')
plt.ylabel('Cell Viability')
plt.xlabel('Concentration mM')
plt. show()