I am trying to fit some data using the following code:
import numpy as np
import scipy.optimize
import matplotlib.pyplot as plt
def fseries(x, a0, a1, b1, w):
f = a0 + (a1 * np.cos(w * x)) + (b1 * np.sin(w * x))
return f
x = np.arange(0, 10)
y = [-45.0, -17.0, -33.0, 50.0, 48.0, -3.0, -1.0, 2.0, 84.0, 71.0]
res = scipy.optimize.curve_fit(fseries, x, y, maxfev=10000)
xt = np.linspace(0, 10, 100)
yt = fseries(xt, res[0][0], res[0][1], res[0][2], res[0][3])
plt.plot(x,y)
plt.plot(xt, yt, 'r')
plt.show()
Which makes this plot:
Any thoughts on what I am not understanding or doing wrong?
First of all, curve fitting is not a magical device that creates a good curve for any given data set. You can't fit an exponential curve well to a logarithmic data set. If you look at your data, does it look like it is well described by the function you define? Doesn't it rather look like an overlay of a linear and a sine function?
Then curve fitting is an iterative process, that is highly dependent on start values. From the scipy manual :
p0 : None, scalar, or N-length sequence, optional Initial guess for the parameters. If None, then the initial values will all be 1
Why not provide a better guess for p0
?
Last but not least, you get back two arrays. I would read out both, even if you only need one. It simplifies your code. Try
p0 = (10, 20, 20, 1.5)
res, _popcv = scipy.optimize.curve_fit(fseries, x, y, p0, maxfev=10000)
xt = np.linspace(0, 10, 100)
yt = fseries(xt, *res)
and you get already a better fit.
You can improve the fit further, when you define a better fit function with
def fseries(x, a0, a1, b1, w):
f = a0 * x + (a1 * np.cos(w * x)) + (b1 * np.sin(w * x))
return f
Whether this function is useful, you have to decide. Just because it fits better the data set, doesn't mean it is the right descriptor in your situation.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.