Reputation: 17
I'm trying to fit some data that i have to a model that is inversely proportional to x to some power. I've looked through a few similar threads and I think the problem might have to do with scaling my data but I've experimented with that and had no success unfortunately.
import numpy as np
import scipy.optimize as optimize
import matplotlib.pyplot as plt
x = np.array([367.18,411.42,443.76,565.22,689.31,778.94,867.38,963.98,1085.79,1112.01,1212.47,1299.21,1408.08,1458.8,1528.76])
y = np.array([17.21,13.38,9.41,11.40,6.40,6.62,6.11,5.50,5.03,4.52,2.34,3.62,3.84,5.97,1.97])
def f(a,n,x1):
return (a*np.power(x1,-n));
popt, pcov = optimize.curve_fit(f,x,y, diag=(1./x.mean(),1./y.mean()))
x1 = np.linspace(0,1700,num =1700)
plt.plot(x1, f(x1, *popt))
plt.plot(x,y,'ro')
plt.show()
print(popt, pcov)
The result is this: Plot
Upvotes: 0
Views: 2236
Reputation: 4647
I cannot place an image in a comment, and so place it here. I found that shifting the X values gave me a better fit to the data, using the equation "y = a * pow((x-b), c)" with coefficients a = 2.2685718105301993E+02, b = 2.7711446388529180E+02 and c = -5.7863164386558297E-01 yielding R-squared = 0.895 and RMSE = 1.33
Upvotes: 0
Reputation: 6499
You have the arguments to the function f
wrong. As per the documentation of curve_fit
,
The model function, f(x, …). It must take the independent variable as the first argument and the parameters to fit as separate remaining arguments.
So you just need to to change the order of arguments to f
, and put x1
at first:
def f(x1, a,n):
return (a*np.power(x1,-n))
Also, on another note for plotting, to be able to see the fit, use the following for defining the independent variable to plot the curve, so it fits the range of your data:
x1 = np.linspace(min(x),max(x),num =1700)
and then you will get the figure:
Upvotes: 3
Reputation: 659
When you run the line
plt.plot(x1, f(x1, *popt))
you are passing x1 as the first parameter into the function f. The first parameter of your function f is a.
def f(a,n,x1):
return (a*no.power(x1,-n))
Even though you call your first parameter x1, the function cares about the order you pass variables, not the variable names. So since you defined f to take three arguments, a,n, and x1, when you pass in x1, it treats the variable x1 as a.
Reordering your function definition so x1 is the first parameter should fix this.
import numpy as np
import scipy.optimize as optimize
import matplotlib.pyplot as plt
x = np.array([367.18,411.42,443.76,565.22,689.31,778.94,867.38,963.98,1085.79,1112.01,1212.47,1299.21,1408.08,1458.8,1528.76])
y = np.array([17.21,13.38,9.41,11.40,6.40,6.62,6.11,5.50,5.03,4.52,2.34,3.62,3.84,5.97,1.97])
def f(x1,a,n):
return (a*np.power(x1,-n));
popt, pcov = optimize.curve_fit(f,x,y, diag=(1./x.mean(),1./y.mean()))
x1 = np.linspace(0,1700,num =1700)
plt.plot(x1, f(x1, *popt))
plt.plot(x,y,'ro')
plt.show()
print(popt, pcov)
Upvotes: 1