我已阅读此article中的erf
函数。
我也尝试过实现此thread中提供的代码。
但考虑到erf
函数的定义,我不了解如何实现对以下数据的拟合:
X Y
33 21.09
35 21.14
37 21.21
39 21.32
41 21.46
43 23
45 27
47 31
49 36
51 40
53 45
55 49
57 53
59 57
61 61
63 65
65 69
67 73
69 77
71 78
73 79
75 79
编辑:
我更改了数据,使其不再是步骤。数据图看起来像:
此图应该适合sigmoid,tanh等功能。但是使用下面评论中的代码我并不合适。
答案 0 :(得分:1)
你很容易适应erf
。上面评论中的解决方案不能像修改后的问题一样工作,数据已经改变,提供的起始值不起作用。然而,从斜坡到水平时的曲率非常大,即过渡非常尖锐,使得erf
,tanh
和sigmoid
都不起作用。下面我将展示拟合以及一些更适合数据的替代/修改函数。
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import erf
from scipy.optimize import curve_fit
data = np.array( [
33, 21.09,
35, 21.14,
37, 21.21,
39, 21.32,
41, 21.46,
43, 23,
45, 27,
47, 31,
49, 36,
51, 40,
53, 45,
55, 49,
57, 53,
59, 57,
61, 61,
63, 65,
65, 69,
67, 73,
69, 77,
71, 78,
73, 79,
75, 79 ] )
xData = data[ ::2 ]
yData = data[ 1::2 ]
def sign_pow( x, p):
return np.copysign( abs( x )**p, x )
guessErf = [ 32., 55., 10., 20. ]
solErf , pcov = curve_fit( lambda x, a, b, c, d: a * (1 + erf( ( x- b ) / c ) ) + d , xData, yData, p0=guessErf )
print solErf
guessTh = [ 32., 55., 10., 20. ]
solTh , pcov = curve_fit( lambda x, a, b, c, d: a * (1 + np.tanh( ( x- b ) / c ) ) + d , xData, yData, p0=guessTh )
print solTh
guessThP = [ 32., 55., 10., 20., 1 ]
solThP , pcov = curve_fit( lambda x, a, b, c, d, p: a * (1 + sign_pow( np.tanh( sign_pow( ( x- b ) / c , p ) ) , (1./p) ) ) + d , xData, yData, p0=guessThP )
print solThP
guessLz = [ 32., 55., 10., 20.]
solLz , pcov = curve_fit( lambda x, a, b, c, d: a * ( 1 + (x - b) / np.sqrt( 1 + ( x - b )**2 / c ) )+ d , xData, yData, p0=guessLz )
print solLz
guessLzP = [ 2., 55., 200., 47., 2]
solLzP , pcov = curve_fit( lambda x, a, b, c, d, p: a * ( 1 + (x - b) / ( 1 + abs( ( x - b ) / c )**p )**( 1. / p ) ) + d , xData, yData, p0=guessLzP, maxfev=5000 )
print solLzP
#~ solLzP=guessLzP
testX = np.linspace( 30, 80, 150 )
erfList = [ solErf[0] * ( 1 + erf( ( x - solErf[1] ) / solErf[2] ) ) + solErf[3] for x in testX ]
thList = [ solTh[0] * ( 1 + np.tanh( ( x - solTh[1] ) / solTh[2] ) ) + solTh[3] for x in testX ]
thPList = [ solThP[0] * ( 1 + sign_pow( np.tanh( sign_pow( ( x - solThP[1] ) / solThP[2] , solThP[4] ) ) , 1. / solThP[4] ) ) + solThP[3] for x in testX ]
lzList = [ solLz[0] * ( 1 + (x - solLz[1] ) / np.sqrt( 1 + ( x - solLz[1] )**2 / solLz[2] ) ) + solLz[3] for x in testX ]
lzPList = [ solLzP[0] * ( 1 + (x - solLzP[1] ) / ( 1 + abs( ( x - solLzP[1] ) / solLzP[2] )**solLzP[4] )**( 1. / solLzP[4] ) ) + solLzP[3] for x in testX ]
fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( xData, yData , ls='', marker='d', label='data')
ax.plot( testX, erfList, label='erf')
ax.plot( testX, thList, label='tanh' )
ax.plot( testX, thPList, label= 'tanh power' )
ax.plot( testX, lzList, label= 'x/1+x^2' )
ax.plot( testX, lzPList, label= 'x/1+x^P' , ls='--')
ax.legend( loc=0 )
plt.show()
提供:
>> [31.57905297 55.87319052 14.64143581 18.66393531]
>> [33.34190267 55.90472589 13.54119241 16.97367616]
>> [28.77092734 55.75011551 13.6999564 21.16422056 7.22849049]
>> [ 2.49108137 55.93839349 232.504463 47.90421787]
>> [ 2.09892962 55.75526439 -13.72758215 47.8461409 17.7915103 ]
可以很容易地看到曲率问题。修改后的tanh
和x/(1+x**p)**(1/p)
同样适用。