I'm trying to make a piecewise linear fit consisting of 3 pieces whereof the first and last pieces are constant. As you can see in this figure

don't get the expected fit, since the fit doesn't capture the 3 linear pieces clearly visual from the original data points.
CodePudding user response:
This i consider a funny non-linear approach that works quite well:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
def pwl( x, m, b, a1, a2 ):
if x < a1:
out = pwl( a1, m, b, a1, a2 )
elif x > a2:
out = pwl( a2, m, b, a1, a2 )
else:
out = m * x b
return out
def func( x, m, b, a1, a2, p ):
out = b np.log(
1 / ( 1 np.exp( m *( x - a1 ) )**p )
) / p - np.log(
1 / ( 1 np.exp( m * ( x - a2 ) )**p )
) / p
return out
nn = 36
xdata = np.linspace( -5, 19, nn )
ydata = np.fromiter( (pwl( x, -2.1, 11.6, -1.1, 12.7 ) for x in xdata ), float)
ydata = np.random.normal( size=nn, scale=0.2)
xth = np.linspace( -5, 19, 150 )
popt, cov = curve_fit( func, xdata, ydata, p0=[2, 11, -1, 10, 1])
print( popt )
fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( xdata, ydata, ls='', marker=' ' )
ax.plot( xth, func( xth, 2, 11, -1, 10, 1 ) )
ax.plot( xth, func( xth, *popt ) )
plt.show()
Only the constant offset needs some extra treatment to get the true offset of the linear term.


