python scipy.optimize.curve_fit 使用的参数太多

发布于 2024-12-07 05:24:18 字数 1177 浏览 0 评论 0原文

我正在尝试在类实例方法中进行一些曲线拟合,并且 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 使用的拟合参数的参数。这可能吗?

I'm attempting to do some curve fitting within a class instance method, and the curve_fit function is giving my class instance method too many arguments.

The code is

class HeatData(hx.HX):
    """Class for handling data from heat exchanger experiments."""

then several lines of methods that work fine, then my function is:

    def get_flow(pressure_drop, coeff):
        """Sets flow based on coefficient and pressure drop.""" 
        flow = coeff * pressure_drop**0.5
        return flow

and the curve_fit function call

    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 )

gives the error

get_flow() takes exactly 2 arguments (3 given)

I can make it work by defining get_flow outside of the class and calling it like this:

spopt.curve_fit(get_flow, pressure_drop, flow)   

but that's no good because it really needs to be a method within the class to be as versatile as I want. How can I get this work as a class instance method?

I'd also like to be able to pass self to get_flow to give it more parameters that are not fit parameters used by curve_fit. Is this possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

久而酒知 2024-12-14 05:24:18

不幸的是,可能是 curve_fit 中的错误。 curve_fit 使用检查来确定起始值的数量,如果存在额外的 self,则会造成混淆或误导。

所以我想,给出一个起始值应该可以避免这个问题。但是,条件中还有一个 isscalar(p0) ,我不知道为什么,我认为最好将其报告为问题或错误:

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

意味着该示例仅如果起始值定义为 [...],则 1 个参数有效,例如类似于下面的示例:

mc.optimize([2])

具有两个参数和给定起始值的示例可以避免检查调用,并且一切都很好:

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)

编辑:此错误已修复,因此绑定方法现在可以作为curve_fit 的第一个参数,如果您有足够新的 scipy 版本。
在 github 上提交错误修复

Unlucky case, and maybe a bug in curve_fit. curve_fit uses inspect to determine the number of starting values, which gets confused or misled if there is an extra self.

So giving a starting value should avoid the problem, I thought. However, there is also an isscalar(p0) in the condition, I have no idea why, and I think it would be good to report it as a problem or 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)

edit: avoiding the scalar as starting value

>>> np.isscalar([2])
False

means that the example with only 1 parameter works if the starting value is defined as [...], e.g.similar to example below:

mc.optimize([2])

An example with two arguments and a given starting value avoids the inspect call, and everything is fine:

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)

EDIT: This bug has been fixed so bound methods can now be passed as the first argument for curve_fit, if you have a sufficiently new version of scipy.
Commit of bug fix submission on github

娇女薄笑 2024-12-14 05:24:18

如果您在 HeatData 类中定义 get_flow,则必须将 self 作为第一个参数:def get_flow(self, pressure_drop, coeff):

编辑:在寻找 curve_fit 的定义后,我 发现原型是 curve_fit(f, xdata, ydata, p0=None, sigma=None, **kw) 所以第一个arg必须是可调用的将以第一个参数作为自变量调用:
尝试使用闭包:

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 ) 

If you define get_flow inside your HeatData class you'll have to have self as first parameter : def get_flow(self, pressure_drop, coeff):

EDIT: after seeking for the definition of curve_fit, i found that the prototype is curve_fit(f, xdata, ydata, p0=None, sigma=None, **kw) so the first arg must be a callable that will be called with first argument as the independent variable :
Try with a closure :

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 ) 
杀手六號 2024-12-14 05:24:18

尝试放弃“自我”并进行调用:spopt.curve_fit(get_flow, pressure_drop, flow)

Trying dropping the "self" and making the call: spopt.curve_fit(get_flow, pressure_drop, flow)

阿楠 2024-12-14 05:24:18

类方法定义的第一个参数应该始终是 self。它会自动传递并引用调用类,因此该方法总是比调用它时传递的参数多接收一个参数。

The first argument of a class method definition should always be self. That gets passed automatically and refers to the calling class, so the method always receives one more argument than you pass when calling it.

海螺姑娘 2024-12-14 05:24:18

处理这个问题的唯一 Python 方法是让 Python 知道 get_flow 是一个 staticmethod:一个放入类中的函数,因为从概念上讲它属于该类,但实际上并不属于该类。需要,因此不需要 self

@staticmethod   
def get_flow(pressure_drop, coeff):
    """Sets flow based on coefficient and pressure drop.""" 
    flow = coeff * pressure_drop**0.5
    return flow

staticmethod 可以通过函数中未使用 self 来识别。

The only pythonic way to deal with this is to let Python know get_flow is a staticmethod: a function that you put in the class because conceptually it belongs there but it doesn't need to be, and therefore doesn't need self.

@staticmethod   
def get_flow(pressure_drop, coeff):
    """Sets flow based on coefficient and pressure drop.""" 
    flow = coeff * pressure_drop**0.5
    return flow

staticmethod's can be recognized by the fact that self is not used in the function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文