I'm trying to fit a multiveriable curve to the function y**2*(y**2/4 - a*y/3 + b/2) - x**2*(x**2/4 - a*x/3 + b/2)
but it seams that curve_fit
doesn't fit to the generated data. The pcov
values are all inf
and the a
and b
outputs remain the same as the guesses.
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def func(X, a, b):
x,y = X
return y**2*(y**2/4 - a*y/3 + b/2) - x**2*(x**2/4 - a*x/3 + b/2)
# some artificially noisy data to fit
x = np.arange(0,5,0.1)
y = np.arange(0,5,0.1)
a = 6
b = 9
z = func((x,y), a, b)
# initial guesses for a,b:
popt, pcov = curve_fit(func, [x,y], z, p0=[10,8])
print(popt)
print(pcov)
print("a = ",popt[0] ," +/- ", np.sqrt(pcov[0,0]))
print("b = ",popt[1] ," +/- ", np.sqrt(pcov[1,1]))
#surface plot
ax = plt.axes(projection="3d")
x_data = np.arange(0,5,0.1)
y_data = np.arange(0,5,0.1)
X, Y = np.meshgrid(x_data,y_data)
Z = func((X,Y), popt[0], popt[1])
ax.scatter(X, Y, Z)
plt.show()
The code works for other functions but not this one.
When you increase the dimensionnality, you also have to sample correctly in all dimension. In your MCVE you are only sampling over a single line instead of sampling in the plane.
The following sampling spreads over the plane:
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize
def model(x, a, b):
return x[1] ** 2 *(x[1] ** 2 / 4 - a * x[1] / 3 + b / 2) - x[0] ** 2 *(x[0] ** 2 / 4 - a * x[0] / 3 + b / 2)
x = np.arange(0, 5, 0.1)
y = np.arange(0, 5, 0.1)
X, Y = np.meshgrid(x, y)
a = 6
b = 9
x = (X.ravel(), Y.ravel())
z = model(x, a, b)
popt, pcov = optimize.curve_fit(model, x, z, p0=[10,8])
#(array([6., 9.]),
# array([[6.78893023e-33, 2.09471226e-32],
# [2.09471226e-32, 6.64942515e-32]]))
And fits properly.
The following figure shows your sampling and the plane sampling with surface:
Also notice, than your original sampling lies exactly on single isopleth: