0

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

Ali AlCapone
  • 121
  • 7
  • 4
    What exactly does not work? What is the expected result. How can we reproduce your issue without any data? – jlandercy Dec 04 '22 at 22:54
  • Data are added as CSV – Ali AlCapone Dec 04 '22 at 23:41
  • 2
    As the breakpoint is exogenous, you could do just two separate regressions. It is a much more exciting problem if the breakpoint is endogenous. – Erwin Kalvelagen Dec 05 '22 at 05:10
  • 1
    Adding data is a good point toward MCVE, now can you complete the question. What exactly doesn't work? What do you expect as a correct output? – jlandercy Dec 05 '22 at 06:33
  • 1
    What are we supposed to do with the flat line at the beginning? How do you know there is two distinct slope while the first part is very bumpy? That's a lot of complexity to cope with in addition of the parameter regression. Why splitting the signal by hand before regression is not an option as suggested by Erwin? Those questions are important to drive the solution. – jlandercy Dec 05 '22 at 06:43
  • I just ignored the flat line at the beginning because it is not interesting for me. I also added what I get now and what I need to get. Thank you for your answer. @jlandercy – Ali AlCapone Dec 05 '22 at 09:55
  • 2
    Code and data don't make any sense. I presume that the CSV has one row for each of x and y but the row lengths are mismatched. No explanation as to the difference between `sensor_array` and `sensor_array__`. No illustration of how you load the data. – Reinderien Dec 05 '22 at 14:25
  • And no answer to important questions raised in comment which will prevent other to produce code that suits needs. Simply because needs are not defined properly. – jlandercy Dec 05 '22 at 14:27
  • @Reinderien They were exactly the same and should now be corrected. – Ali AlCapone Dec 05 '22 at 16:37
  • @Reinderien the data comes from other functions, it is part of a larger program. and tries to reproduce what makes a problem! – Ali AlCapone Dec 05 '22 at 16:42
  • Just trying to help here. I like to investigate fitting problems but I misses answers to questions I raised. I don't speak German. Would you mind update your post with some important information. See my question above. Writing a good question takes time. Cheers. – jlandercy Dec 05 '22 at 17:44
  • 1
    At least can you tell what are x and y in term of variables and units. – jlandercy Dec 05 '22 at 20:17
  • @jlandercy The first row in Data is sensor_array__[0] and is the x-axis and the second row in Data is sensor_array__[1] and it is the y-axis. To answer your question, I want to extrapolate with this function, and I need the slope of the second part of the function for this extrapolation. For the first part, I just want to make a linear fit. The bumpy errors you see don't really have anything to do with my calculation. The flat part does not matter, and as you can see, I have defined my variable from 0.1 to 1200. – Ali AlCapone Dec 05 '22 at 20:46
  • It is a bit rude to read a free code posted by someone who was kind to try to answer does not work properly meanwhile your question is still poorly phrased and you haven't answer to important questions raised in comments. I am pretty sure that if you address all questions raised here and take time to reformulate your problem you will see things for a different angle and then solution will appear. Good question take times to write. – jlandercy Dec 10 '22 at 21:27
  • @jlandercy I am very grateful to everyone for all their help, no one should help but we are all here to help each other. I don't understand your questions. It's simple, I wrote what I want and need, I entered data, I entered my codes, I tried 3 times and put the results here and I think there is nothing more I can write. But as you can see others are trying to help instead of blocking. I tried his code and I have the +1 for his help. I do not know what you are looking for here, except to criticize my behavior. – Ali AlCapone Dec 11 '22 at 10:16
  • What I am highlighting here is the difficulty to help you because your problem is I'll defined and need precision and answer to legitimate question to go further. You may ignore the question if you feel so (they are in the comment above with +1). So at the end, it is your problem if you feel you have done the maximum. The only reasonable question left is how this data will reasonably fit 2 slopes when we see how bumpy it is. Good question takes time to write. Have a good day – jlandercy Dec 11 '22 at 17:57
  • @jlandercy because I am working on this data for more than 1 year and I know every fluctuation on it and I know what happens at every point. it is just one of my dataset and I have 39 set of data and in all of them on day 180 is this slope change that has a chemical cause. I know that every other point is irrelevant to my calculations and I want to have that slope to extrapolate and integrate. There is so much information that I can not explain here, but I know what I am doing. – Ali AlCapone Dec 11 '22 at 18:29
  • Read [MCVE] and [ask]. – jlandercy Dec 11 '22 at 18:44

1 Answers1

1

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

Reinderien
  • 11,755
  • 5
  • 49
  • 77