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:
enter image description here
what I want to get:
enter image description here

Data

my second attempt give me this one:
But still not the one that I need.
enter image description here

Asked By: Ali AlCapone

||

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]

piece fit plot

Answered By: Reinderien
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.