这是我的版本。由于线性函数应该连续连接,因此参数实际上更少。因此,偏移量b2
和b3
没有拟合,而是重新获取线性函数以在过渡处相遇的结果。此外,有人可能会争辩说,数据并不能证明开始或结束时的斜率是合理的。这可以通过减少卡方或其他统计方法来证明/检查。
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
XX=np.linspace( 7.5, 9.5, 16 )
YY=np.asarray( [
7, 7, 7, 7.1, 7.3, 7.5, 8.4, 9, 9.3, 9.6,
10.3, 10.2, 10.4, 10.5, 10.5, 10.5
])
yy0 = np.median( YY )
xx0 = np.median( XX )
h0 = 0.8 * min( XX ) + 0.2 * max( XX )
h1 = 0.8 * max( XX ) + 0.2 * min( XX )
def transition( x, x0, s ):
return ( 0.5 * np.pi + np.arctan( ( x - x0 ) * s ) ) / np.pi
def box( x, x0, x1, s ):
return transition( x, x0, s ) * transition( -x, -x1, s )
def my_piecewise( x, a1, a2, a3, b1, x0, x1 ):
S = 100
b2 = ( a1 - a2 ) * x0 + b1 ### due to continuity
b3 = ( a2 - a3 ) * x1 + b2 ### due to continuity
out = transition( -x , -x0, S ) * ( a1 * x + b1 )
out += box( x , x0, x1 , S ) * ( a2 * x + b2 )
out += transition( x , x1, S ) * ( a3 * x + b3 )
return out
def parameter_reduced( x, a2, b1, x0, x1 ):
return my_piecewise(x, 0, a2, 0, b1, x0, x1 )
def alternative( x, x0, a, s, p, y0 ):
out = np.arctan( np.abs( ( s * ( x - x0 ) ) )**p )**( 1.0 / p )
out *= a * (x - x0 ) / np.abs( x - x0 )
out += y0
return out
xl=np.linspace( 7.2, 10, 150 )
sol, _ = curve_fit(
my_piecewise, XX, YY, p0=[ 0, 1, 0, min( YY ), h0, h1 ]
)
fl = np.fromiter( ( my_piecewise(x, *sol ) for x in xl ), np.float )
rcp = np.fromiter( ( y - my_piecewise(x, *sol ) for x,y in zip( XX, YY ) ), np.float )
rcp = sum( rcp**2 )
solr, _ = curve_fit(
parameter_reduced, XX, YY, p0=[ 1, min(YY), h0, h1 ]
)
rl = np.fromiter( ( parameter_reduced( x, *solr ) for x in xl ), np.float )
rcpr = np.fromiter( ( y - parameter_reduced(x, *solr ) for x, y in zip( XX, YY ) ), np.float )
rcpr = sum( rcpr**2 )
guessa = [ xx0, max(YY)-min(YY), 1, 1, yy0 ]
sola, _ = curve_fit( alternative, XX, YY, p0=guessa)
al = np.fromiter( ( alternative( x, *sola ) for x in xl ), np.float )
rca = np.fromiter( ( y - alternative(x, *sola ) for x, y in zip( XX, YY ) ), np.float )
rca = sum( rca**2 )
print rcp, rcp / ( len(XX) - 6 )
print rcpr, rcpr / ( len(XX) - 4 )
print rca, rca / ( len(XX) - 5 )
fig = plt.figure( figsize=( 12, 8 ) )
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( XX, YY , ls='', marker='o')
ax.plot( xl, fl )
ax.plot( xl, rl )
ax.plot( xl, al )
plt.show()
结果对我来说看起来不错。