I have applied the elegant solution to piecewise linear fitting as given in How to apply piecewise linear fit in Python?.
As shown in the figure (source code is given below), I do get as a result the orange line, whereas I expect something like the green one. The sum of squarred errors results to 3918 (orange) vs. 377 (green). This is a difference of factor 10 and should be far above any default tolerance values or any machine precision. Strangely, I do have similar data points, which are approximately shifted up or down with respect to the blue points. With these, the regression behaves very well. I mean could twigle the kwgargs of the curve_fit
function since I do have some more information about the problem. But why is the "free" regression with the default values so bad? Are there any numerical instabilities during the iterative solving process, leading to far of local minima? I would be very pleased if someone comes up with an explaination and a solution.
from numpy import array, linspace, piecewise
from scipy import optimize
import matplotlib.pyplot as plt
def piecewise_linear(x, x0, y0, k1, k2):
return piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])
x = array([130., 125., 115., 110., 105., 95., 85., 75., 65., 55., 45., 35., 25., 15., 5., 0.])
y = array([ 5., 35., 70., 90., 100., 115., 125., 135., 145., 155., 165., 175., 189., 199., 209., 213.])
xs = linspace(min(x), max(x), num=100)
ps = optimize.curve_fit(piecewise_linear, x, y)
# result: ps = array([-124.37010926, 393.31034095, -90.9686379 , -1.35547041])
# i.e. x_0 is supposed to be in the second quadrant
# OptimizeWarning: Covariance of the parameters could not be estimated
fig, ax = plt.subplots()
ax.plot(x, y, marker='o', linestyle='None')
ax.plot(xs, piecewise_linear(xs, *ps[0]), label='calculated')
# quick guess / approximate expectation
expected_ps = array([110, 90, -1.1, -4])
ax.plot(xs, piecewise_linear(xs, *expected_ps), label='approx. expected')
ax.legend()
plt.show()
sum_of_squared_errors = lambda params: sum((piecewise_linear(x, *params) - y)**2)
print('errors estimate:', sum_of_squared_errors(ps[0])) # 3918
print('errors expected', sum_of_squared_errors(expected_ps)) # 377