Python scipy.optimize.curve_fit 使用了过多参数
我正在尝试在一个类的方法里进行曲线拟合,但curve_fit函数给我的类方法传递了太多参数。
代码是
class HeatData(hx.HX):
"""Class for handling data from heat exchanger experiments."""
然后有几行方法都运行得很好,接下来我的函数是:
def get_flow(pressure_drop, coeff):
"""Sets flow based on coefficient and pressure drop."""
flow = coeff * pressure_drop**0.5
return flow
而curve_fit函数的调用
def set_flow_array(self):
"""Sets experimental flow rate through heat exchanger"""
flow = self.flow_data.flow
pressure_drop = self.flow_data.pressure_drop
popt, pcov = spopt.curve_fit(self.get_flow, pressure_drop, flow)
self.exh.flow_coeff = popt
self.exh.flow_array = ( self.exh.flow_coeff * self.exh.pressure_drop**0.5 )
出现了错误
get_flow() takes exactly 2 arguments (3 given)
我可以通过在类外定义get_flow来解决这个问题,然后这样调用它:
spopt.curve_fit(get_flow, pressure_drop, flow)
但这样不太好,因为我希望它能作为类中的一个方法,这样才能更灵活。我该如何让它作为类的方法工作呢?
我还想能够把self传给get_flow,这样可以给它更多的参数,这些参数不是curve_fit使用的拟合参数。这样做可以吗?
5 个回答
试着去掉“self”,然后这样调用:spopt.curve_fit(get_flow, pressure_drop, flow)
如果你在你的 HeatData
类里面定义 get_flow
方法,那么第一个参数必须是 self
,也就是这样写:def get_flow(self, pressure_drop, coeff):
补充说明:在查找 curve_fit
的定义时,我发现它的原型是 curve_fit(f, xdata, ydata, p0=None, sigma=None, **kw)
,所以第一个参数必须是一个可以调用的函数,这个函数会用独立变量作为第一个参数来调用。你可以试试用闭包来实现:
def set_flow_array(self):
"""Sets experimental flow rate through heat exchanger"""
flow = self.flow_data.flow
pressure_drop = self.flow_data.pressure_drop
def get_flow((pressure_drop, coeff):
"""Sets flow based on coefficient and pressure drop."""
#here you can use self.what_you_need
# you can even call a self.get_flow(pressure_drop, coeff) method :)
flow = coeff * pressure_drop**0.5
return flow
popt, pcov = spopt.curve_fit(get_flow, pressure_drop, flow)
self.exh.flow_coeff = popt
self.exh.flow_array = ( self.exh.flow_coeff * self.exh.pressure_drop**0.5 )
这真是个倒霉的情况,可能还有一个在curve_fit里的bug。curve_fit会用inspect来判断起始值的数量,如果多了一个self
,它就会搞混或者被误导。
我原以为给一个起始值就能避免这个问题。然而,条件里还有个iscale(p0),我不知道为什么会有这个,我觉得应该把这个当作问题或bug报告一下:
if p0 is None or isscalar(p0):
# determine number of parameters by inspecting the function
import inspect
args, varargs, varkw, defaults = inspect.getargspec(f)
补充:避免把标量作为起始值
>>> np.isscalar([2])
False
这意味着如果起始值定义为[...],比如下面的例子,只有一个参数的情况就能正常工作:
mc.optimize([2])
一个有两个参数和给定起始值的例子可以避免inspect的调用,一切都正常:
import numpy as np
from scipy.optimize import curve_fit
class MyClass(object):
def get_flow(self, pressure_drop, coeff, coeff2):
"""Sets flow based on coefficient and pressure drop."""
flow = coeff * pressure_drop**0.5 + coeff2
return flow
def optimize(self, start_value=None):
coeff = 1
pressure_drop = np.arange(20.)
flow = coeff * pressure_drop**0.5 + np.random.randn(20)
return curve_fit(self.get_flow, pressure_drop, flow, p0=start_value)
mc = MyClass()
print mc.optimize([2,1])
import inspect
args, varargs, varkw, defaults = inspect.getargspec(mc.get_flow)
print args, len(args)
补充:这个bug已经修复了,所以现在可以把绑定的方法作为curve_fit的第一个参数传入,只要你有一个足够新的scipy版本。
在github上提交的bug修复记录