scipy 如何在python中设置一个step函数

qlfbtfca  于 8个月前  发布在  Python
关注(0)|答案(3)|浏览(86)

我有一个关于使用scipy例程(如curve_fit)拟合阶跃函数的问题。我很难将其矢量化,例如:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

xobs=np.linspace(0,10,100)
yl=np.random.rand(50); yr=np.random.rand(50)+100
yobs=np.concatenate((yl,yr),axis=0)

def model(x,rf,T1,T2):
#1:   x=np.vectorize(x)
    if x<rf:
        ret= T1
    else:
        ret= T2
    return ret
#2: model=np.vectorize(model)
popt, pcov = curve_fit(model, xobs, yobs, [40.,0.,100.])

它说

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

如果我添加#1或#2,它会运行,但并不真正适合数据:

OptimizeWarning: Covariance of the parameters could not be estimated     category=OptimizeWarning)
[ 40.          50.51182064  50.51182064] [[ inf  inf  inf]
[ inf  inf  inf]
[ inf  inf  inf]]

有人知道怎么修吗?THX

r1zhe5dt

r1zhe5dt1#

我是这么做的我保留了xobsyobs

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

xobs=np.linspace(0,10,100)
yl=np.random.rand(50); yr=np.random.rand(50)+100
yobs=np.concatenate((yl,yr),axis=0)

现在,必须生成Heaviside函数。为了给予这个函数的概述,考虑Heaviside函数的半最大约定:

在Python中,这相当于:def f(x): return 0.5 * (np.sign(x) + 1)
样地为:

xval = sorted(np.concatenate([np.linspace(-5,5,100),[0]])) # includes x = 0
yval = f(xval)
plt.plot(xval,yval,'ko-')
plt.ylim(-0.1,1.1)
plt.xlabel('x',size=18)
plt.ylabel('H(x)',size=20)

现在,绘制xobsyobs得到:

plt.plot(xobs,yobs,'ko-')
plt.ylim(-10,110)
plt.xlabel('xobs',size=18)
plt.ylabel('yobs',size=20)

请注意,比较这两个图,第二个图移动了5个单位,最大值从1.0增加到100。我推断第二个图的函数可以表示如下:

在Python中:(0.5 * (np.sign(x-5) + 1) * 100 = 50 * (np.sign(x-5) + 1)
组合这些图可以得到(其中Fit表示上述拟合函数)

情节证实了我的猜测是正确的。现在,假设你不知道这个正确的拟合函数是如何产生的,那么就创建了一个广义拟合函数:def f(x,a,b,c): return a * (np.sign(x-b) + c),其中理论上,a = 50b = 5c = 1
进行估算:
popt,pcov=curve_fit(f,xobs,yobs,bounds=([49,4.75,0],[50,5,2]))
现在,bounds = ([lower bound of each parameter (a,b,c)],[upper bound of each parameter])。从技术上讲,这意味着49 < a < 50,4.75 < b < 5,0 < c < 2。
以下是我对poptpcov的搜索结果:

pcov表示popt的估计协方差。对角线提供参数估计值Source(https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.curve_fit.html)的方差。
结果表明,参数估计值pcov与理论值接近.
基本上,广义Heaviside函数可以表示为:a * (np.sign(x-b) + c)
下面是生成参数估计值和相应协方差的代码:

import numpy as np
from scipy.optimize import curve_fit

xobs = np.linspace(0,10,100)
yl = np.random.rand(50); yr=np.random.rand(50)+100
yobs = np.concatenate((yl,yr),axis=0)

def f(x,a,b,c): return a * (np.sign(x-b) + c) # Heaviside fitting function

popt, pcov = curve_fit(f,xobs,yobs,bounds=([49,4.75,0],[50,5,2]))
print 'popt = %s' % popt
print 'pcov = \n %s' % pcov

最后,请注意poptpcov的估计值不同。
pythonscipy

ql3eal8s

ql3eal8s2#

这个问题很老了,但如果它对其他人有用的话:Heaviside函数在步长处不可微,这导致了最小化的问题。在这种情况下,我拟合一个逻辑函数,如下所示。
在我的情况下,拟合一个单侧函数总是失败。

x = np.linspace(0,10,101)
y = np.heaviside((x-5), 0.) 
def sigmoid(x, x0,b):
    return scipy.special.expit((x-x0)*b)
args, cov = optim.curve_fit(sigmoid, x, y)
plt.scatter(x,y)
plt.plot(x, sigmoid(x, *args))
print(args)

> 

[  5.05006427 532.21427701]

slmsl1lt

slmsl1lt3#

对于噪声和更复杂的数据,您也可以使用误差函数来拟合步长:

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.special import erf
np.random.seed(0)

def func(x,x0,y0,h,a,b=0,c=0):
    return y0 + h/2*erf((x-x0)*a) + b*x + c*x**2

# Generate mock data
x = np.linspace(0,1,200)
y = (x>0.5)*0.2 + 0.1 + np.random.rand(len(x))*0.2 + x*0.3

# Use curvefit
popt,pocv = curve_fit(func,x,y,p0 = (np.nanmean(x),np.min(y),np.max(y)-np.min(y),1.0,1.0))

plt.plot(x,y)
plt.plot(x,func(x,*popt))

相关问题