Python函数与partial - Scipy不喜欢partials

3

我正在阅读 curve_fit文档。作为第一个参数,curve_fit 接受要拟合的函数。为了让它以部分函数作为第一个参数,我稍微修改了示例代码:

In:

import numpy as np
from scipy.optimize import curve_fit
def func( t, x , a, b, c): # I added a dummy variable t so that I can apply partials later
    return a*np.exp(-b*x) + c + t 
func = partial( func, 0 ) # use of partial to remove the dummy variable
x = np.linspace(0,4,50)
y = func(x, 2.5, 1.3, 0.5)
yn = y + 0.2*np.random.normal(size=len(x))
popt, pcov = curve_fit(func, x, yn) # curve_fit gets a partial instead of a Python function

Out:
TypeError: <functools.partial object at 0x104551c58> is not a Python function

啊,那很令人失望。我想下次我会使用一个 lambda。 不管怎样,这里的问题是什么?函数能做什么而部分函数不能做什么?
2个回答

3

curve_fit使用标准库inspect中的getargspec来确定函数的参数。不幸的是,getargspec无法处理部分参数:

In [31]: from inspect import getargspec

In [32]: from functools import partial

In [33]: def func(t, x, a, b, c):
   ....:     return a*np.exp(-b*x) + c + t
   ....: 

In [34]: pfunc = partial(func, 0)

getargspec(func) works fine.

In [35]: getargspec(func)
Out[35]: ArgSpec(args=['t', 'x', 'a', 'b', 'c'], varargs=None, keywords=None, defaults=None)

但是getargspec不能处理部分函数:

In [36]: getargspec(pfunc)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-3fb5eaea7c94> in <module>()
----> 1 getargspec(pfunc)

/Users/warren/anaconda/python.app/Contents/lib/python2.7/inspect.pyc in getargspec(func)
    814         func = func.im_func
    815     if not isfunction(func):
--> 816         raise TypeError('{!r} is not a Python function'.format(func))
    817     args, varargs, varkw = getargs(func.func_code)
    818     return ArgSpec(args, varargs, varkw, func.func_defaults)

TypeError: <functools.partial object at 0x107ec6d08> is not a Python function

将代码追踪更深一层,问题在于isinstance(func, types.FunctionType)是否成立。type(pfunc)functools.partial - hpaulj
curvefit 只是使用 getargspec 来确定 len(args)。在这种情况下,func 的长度为 5,pfunc 的长度为 5-1,即 len(getargspec(pfunc.func)[0])-len(pfunc.args)。使用此计算的自定义 curvefit 可能会起作用。 - hpaulj

2

更新: 在Python 3.5和3.6中,getargspec可以处理部分函数,因此使用partial与curve_fit一起使用是可行的。我没有安装旧版本的Python 3,所以无法检查它们。

Python 3.6,Scipy 0.18.1,Numpy 1.12.0

import numpy as np
from functools import partial
from scipy.optimize import curve_fit

def func(t, x, a, b, c):
    return a*np.exp(-b*x) + c + t

x = np.linspace(0,4,50)

pfunc = partial(func, 0.0)
y = pfunc(x, 2.5, 1.3, 0.5)
popt, pcov = curve_fit(pfunc, x, y)
print(popt, y[0:2])

pfunc = partial(func, 100.0)
y = pfunc(x, 2.5, 1.3, 0.5)
popt, pcov = curve_fit(pfunc, x, y)
print(popt, y[0:2])

[ 2.5  1.3  0.5] [   3.       2.7482863]
[ 2.5  1.3  0.5] [ 103.     102.7482863]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接