optimization problem with piecewise curve fitting
Question:
I want to fit my data with a piecewise function that I have shown below,
The whole graph is a semilogarithmic graph, and I want to fit it with two different logarithmic functions that I have shown in different colors (purple and red are drawn with my hand). The problem is that it doesn’t work, and I don’t know what I’m doing wrong. I will post the mini-code that I have summarized.
import numpy as np
from scipy.optimize import curve_fit
def func_stuck(t, a, b, c, d, e , f): # x-shifted log
y = np.piecewise(t, [t < 100, t >= 100],
[lambda t:a*np.log(t + b)+c, lambda t:d*np.log(t + e)+f])
return y
plt.semilogx(sensor_array__[0],sensor_array__[1])
popt, pcov = curve_fit(func_stuck,sensor_array__[0], sensor_array__[1],maxfev=100000000)
function_x = np.linspace(0.1 , 1200, 1200)
fitted_y = np.asarray(popt[0]*np.log(function_x + popt[1])+popt[2]+popt[3]*np.log(function_x + popt[4])+popt[5])
plt.semilogx(function_x,fitted_y)
what I get:
what I want to get:
my second attempt give me this one:
But still not the one that I need.
Answers:
Forget about calling the piecewise
function. Slice to the segment of the array you care about, and only fit on that.
import numpy as np
from matplotlib import pyplot as plt
from scipy.optimize import curve_fit
x_mid = 100
def func_stuck(t: np.ndarray, a: float, b: float, c: float, d: float, e: float) -> np.ndarray:
# aln(x_mid + b) + c = dln(x_mid + e) + f
f = a*np.log(x_mid + b) + c - d*np.log(x_mid + e)
y = np.empty_like(t)
m = mid - start
y[:m] = a*np.log(t[:m] + b) + c
y[m:] = d*np.log(t[m:] + e) + f
return y
x, y = np.loadtxt('sample.csv', delimiter=',')
start = np.nonzero(x >= 0.1)[0][0]
mid = np.nonzero(x >= x_mid)[0][0]
popt, _ = curve_fit(
func_stuck, x[start:], y[start:],
bounds=(
# a b c d e
(-np.inf, -x[start: mid].min(), -np.inf, -np.inf, -x[mid:].min()),
(+np.inf, +np.inf, +np.inf, +np.inf, +np.inf ),
),
)
print(popt)
fitted_y = func_stuck(x, *popt)
plt.semilogx(x, y)
plt.semilogx(x[start: mid], fitted_y[start: mid], c='pink')
plt.semilogx(x[mid:], fitted_y[mid:], c='red')
plt.show()
[-1.31250596e+02 1.72352140e-01 -2.47615596e+02 -5.33493810e+01
-6.92009813e+01]
I want to fit my data with a piecewise function that I have shown below,
The whole graph is a semilogarithmic graph, and I want to fit it with two different logarithmic functions that I have shown in different colors (purple and red are drawn with my hand). The problem is that it doesn’t work, and I don’t know what I’m doing wrong. I will post the mini-code that I have summarized.
import numpy as np
from scipy.optimize import curve_fit
def func_stuck(t, a, b, c, d, e , f): # x-shifted log
y = np.piecewise(t, [t < 100, t >= 100],
[lambda t:a*np.log(t + b)+c, lambda t:d*np.log(t + e)+f])
return y
plt.semilogx(sensor_array__[0],sensor_array__[1])
popt, pcov = curve_fit(func_stuck,sensor_array__[0], sensor_array__[1],maxfev=100000000)
function_x = np.linspace(0.1 , 1200, 1200)
fitted_y = np.asarray(popt[0]*np.log(function_x + popt[1])+popt[2]+popt[3]*np.log(function_x + popt[4])+popt[5])
plt.semilogx(function_x,fitted_y)
what I get:
what I want to get:
my second attempt give me this one:
But still not the one that I need.
Forget about calling the piecewise
function. Slice to the segment of the array you care about, and only fit on that.
import numpy as np
from matplotlib import pyplot as plt
from scipy.optimize import curve_fit
x_mid = 100
def func_stuck(t: np.ndarray, a: float, b: float, c: float, d: float, e: float) -> np.ndarray:
# aln(x_mid + b) + c = dln(x_mid + e) + f
f = a*np.log(x_mid + b) + c - d*np.log(x_mid + e)
y = np.empty_like(t)
m = mid - start
y[:m] = a*np.log(t[:m] + b) + c
y[m:] = d*np.log(t[m:] + e) + f
return y
x, y = np.loadtxt('sample.csv', delimiter=',')
start = np.nonzero(x >= 0.1)[0][0]
mid = np.nonzero(x >= x_mid)[0][0]
popt, _ = curve_fit(
func_stuck, x[start:], y[start:],
bounds=(
# a b c d e
(-np.inf, -x[start: mid].min(), -np.inf, -np.inf, -x[mid:].min()),
(+np.inf, +np.inf, +np.inf, +np.inf, +np.inf ),
),
)
print(popt)
fitted_y = func_stuck(x, *popt)
plt.semilogx(x, y)
plt.semilogx(x[start: mid], fitted_y[start: mid], c='pink')
plt.semilogx(x[mid:], fitted_y[mid:], c='red')
plt.show()
[-1.31250596e+02 1.72352140e-01 -2.47615596e+02 -5.33493810e+01
-6.92009813e+01]