#python #numpy #curve-fitting #data-fitting #atan
#python #numpy #подгонка кривой #подгонка данных #atan
Вопрос:
Я пытаюсь подогнать функцию double broken profile, которая состоит из функции arctangent. Похоже, мой код не работает:
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])
def func_arc(x,a1,a2,a3,b1,b2,b3,H1,H2):
beta=0.001
w1=np.zeros(len(x))
w2=np.zeros(len(x))
for i in np.arange(0,len(x)):
w1[i]=(((math.pi/2) atan((x[i]-H1)/beta))/math.pi)
w2[i]=(((math.pi/2) atan((x[i]-H2)/beta))/math.pi)
y=(a1*x[i] b1)*(1-w1[i]) (a2*x[i] b2)*w1[i]*(1-w2[i]) (a3*x b3)*w2[i]
return(y)
Где a
и b
термины представляют собой значения наклона и нулевой точки линейных регрессий.
w
Термины используются для переключения домена.
Я принимаю во внимание следующие ограничения для непрерывности (H1 y H2) и ограничиваю параметры:
mask=(XX<=8.2)
mask2=(XX>8.2) amp; (XX<9)
mask3=(XX>=9)
l1=np.polyfit(XX[mask], YY[mask], 1)
l2=np.polyfit(XX[mask2], YY[mask2], 1)
l3=np.polyfit(XX[mask3], YY[mask3], 1)
H1=(l2[1]-l1[1])/(l1[0]-l2[0])
H2=(l3[1]-l2[1])/(l2[0]-l3[0])
p0=[l1[0],l2[0],l3[0],l1[1],l2[1],l3[1],H1,H2]
popt_arc1, pcov_arc1 =curve_fit(func_arc, XX, YY,p0)
Я получаю одну строку вместо разорванного профиля (S-образной формы).
Что я получаю:
Комментарии:
1. Сначала я хотел бы сказать, что вы, вероятно, полностью переопределяете свои данные. Это не похоже на данные с двумя доменами линейного поведения. Это больше похоже на
arctan
само по себе. Итак, какова здесь мотивация? Можете ли вы дать некоторое представление?2. Спасибо @mikuszefski; на самом деле, я работаю с большой базой данных, и я намеревался проиллюстрировать общее поведение только с дюжиной, пытаясь воспроизвести два плато, и я использовал это математическое выражение для воспроизведения научной статьи.
3. Привет. Хотя технически говоря, SO не дает советов по вашей модели-функции, я думаю, вы сделали это слишком сложным. Если вы можете более точно указать, что вам действительно нужно, я уверен, что эта часть также может быть улучшена.
Ответ №1:
Вот моя версия. Из-за того, что линейные функции должны соединяться непрерывно, параметры на самом деле меньше. Смещения 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()
Результаты выглядят нормально для меня.