I have data provided in the code which have negative and positive slopes as shown in figure:
Using the code applied in this post Fit a curve for data made up of two distinct regimes, I created this code. It works for same slopes either both positive or both negative, but when one is positive and other negative, it is not able to fit the lines properly.
from scipy import optimize
from scipy import optimize, interpolate
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy as np
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
y = np.array([4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4])
def two_lines(x, a, b, c, d):
one = a*x + b
two = c*x + d
return np.maximum(one, two)
'''Compute approximate slope and intercept of the two lines'''
poly_low = np.polyfit(x[0:int(0.5*(len(x) + 1))], y[0:int(0.5*(len(x) + 1))], deg=1)
poly_high = np.polyfit(x[int(0.5*(len(x) + 1)):len(x)], y[int(0.5*(len(x) + 1)):len(x)], deg=1)
# This part of the code credit goes to askewchan
pw0 = (poly_low[0], poly_low[1], poly_high[0], poly_high[1]) # a guess for slope, intercept, slope, intercept
pw, cov = curve_fit(two_lines, x, y, pw0)
crossover = (pw[3] - pw[1]) / (pw[0] - pw[2])
figure = plt.figure(figsize=(5.15, 5.15))
figure.clf()
plot = plt.subplot(111)
plt.plot(x, y, 'o', x, two_lines(x, *pw), '-')
plot.set_ylabel('Y', labelpad = 6)
plot.set_xlabel('X', labelpad = 6)
plt.show()
Output
For different slopes:
For same slope both negative (works fine for positive slopes also):
I have two questions:
- How to apply piecewise linear fits for such cases in Python?
- How to extend it to three or more regimes?