【问题标题】:Scipy Newton with derivative: TypeError: 'numpy.float64' object is not callable具有导数的 Scipy Newton:TypeError:'numpy.float64' 对象不可调用
【发布时间】:2014-10-02 09:59:56
【问题描述】:

我对 scipy 的牛顿法有疑问。当我使用带有给定导数的牛顿时出现错误(请参阅下面的错误输出)。

我正在尝试以 x0 = 2.0 的起始值计算 x**2 的根:

def test_newtonRaphson():
def f(x):
    resf = x**2
    return resf
assert(derivative(f, 1.0)) == 2.0
assert(round(newton(f, 0.0), 10)) == 0.0
dfx0 = derivative(f, 2.0)
assert(round(newton(f, 2.0, dfx0), 10)) == 0.0

整个错误输出如下:

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

func = <function f at 0x04049EF0>, x0 = 2.0, fprime = 4.0, args = () tol = 1.48e-08, maxiter = 50, fprime2 = None

def newton(func, x0, fprime=None, args=(), tol=1.48e-8, maxiter=50,
           fprime2=None):
    """
    Find a zero using the Newton-Raphson or secant method.

    Find a zero of the function `func` given a nearby starting point `x0`.
    The Newton-Raphson method is used if the derivative `fprime` of `func`
    is provided, otherwise the secant method is used.  If the second order
    derivate `fprime2` of `func` is provided, parabolic Halley's method
    is used.

    Parameters
    ----------
    func : function
        The function whose zero is wanted. It must be a function of a
        single variable of the form f(x,a,b,c...), where a,b,c... are extra
        arguments that can be passed in the `args` parameter.
    x0 : float
        An initial estimate of the zero that should be somewhere near the
        actual zero.
    fprime : function, optional
        The derivative of the function when available and convenient. If it
        is None (default), then the secant method is used.
    args : tuple, optional
        Extra arguments to be used in the function call.
    tol : float, optional
        The allowable error of the zero value.
    maxiter : int, optional
        Maximum number of iterations.
    fprime2 : function, optional
        The second order derivative of the function when available and
        convenient. If it is None (default), then the normal Newton-Raphson
        or the secant method is used. If it is given, parabolic Halley's
        method is used.

    Returns
    -------
    zero : float
        Estimated location where function is zero.

    See Also
    --------
    brentq, brenth, ridder, bisect
    fsolve : find zeroes in n dimensions.

    Notes
    -----
    The convergence rate of the Newton-Raphson method is quadratic,
    the Halley method is cubic, and the secant method is
    sub-quadratic.  This means that if the function is well behaved
    the actual error in the estimated zero is approximately the square
    (cube for Halley) of the requested tolerance up to roundoff
    error. However, the stopping criterion used here is the step size
    and there is no guarantee that a zero has been found. Consequently
    the result should be verified. Safer algorithms are brentq,
    brenth, ridder, and bisect, but they all require that the root
    first be bracketed in an interval where the function changes
    sign. The brentq algorithm is recommended for general use in one
    dimensional problems when such an interval has been found.

    """
    if tol <= 0:
        raise ValueError("tol too small (%g <= 0)" % tol)
    if fprime is not None:
        # Newton-Rapheson method
        # Multiply by 1.0 to convert to floating point.  We don't use float(x0)
        # so it still works if x0 is complex.
        p0 = 1.0 * x0
        fder2 = 0
        for iter in range(maxiter):
            myargs = (p0,) + args
          fder = fprime(*myargs)

E TypeError: 'numpy.float64' 对象不可调用

File "C:\Anaconda\lib\site-packages\scipy\optimize\zeros.py", line 116 TypeError

【问题讨论】:

    标签: python numpy scipy pydev anaconda


    【解决方案1】:

    您可以使用 SymPy 计算导数,然后使用 lambdify 将该表达式转换为可与 scipy 一起使用的函数。请注意,lambdify 目前默认不了解 SciPy,因此您必须手动为 scipy 特殊功能添加翻译字典:

    In [23]: expr = gamma(1+3/x)/gamma(1+1/x)**3
    
    In [24]: print(expr.diff(x))
    3*gamma(1 + 3/x)*polygamma(0, 1 + 1/x)/(x**2*gamma(1 + 1/x)**3) - 3*gamma(1 + 3/x)*polygamma(0, 1 + 3/x)/(x**2*gamma(1 + 1/x)**3)
    
    In [25]: f = lambdify(x, expr.diff(x), ['numpy', {'gamma': scipy.special.gamma, 'polygamma': scipy.special.polygamma}])
    

    此时,我无法使用 newton 函数找到此表达式的任何根。根据Wolfram Alpha 的原始图,我没有看到导数为 0 的任何明显点,所以如果没有真正的根,我不会感到惊讶。

    【讨论】:

    • 函数 'expr' 没有任何根。但是如果你从中减去它的 y 值并计算结果函数 f = gamma(1+3/x)/gamma(1+1/x)**3-y0 的根,那么你得到'expr' 在点 y0 处的 x0 倒数。感谢您使用 lambdify 的回答,这会有所帮助。
    • 我的意思是导数没有根。看起来原版也没有根(从数学上讲,这是一个巧合)。
    【解决方案2】:

    我认为正在发生的事情是您传递的是导数的值,而不是表示导数的函数。你需要一些“可调用”的东西,并且一个值(更具体地说是值dfx0 = derivative(f, 2.0))不能像函数一样被“调用”。

    仅供参考:如果您还没有,不妨看看these examples

    【讨论】:

    • 所以我必须声明'x'一个符号变量并使用sympy来计算f的导数df?如何获取导数 df 的 python 函数?
    • 否 - 您需要为导数定义一个函数。你已经定义了f。你如何定义f 的导数?
    • @jjack:你可以试试这样:newton(f, 2.0, lambda x: 2*x)
    • 问题是我只是以x**2为例。我真的想根据Gamma(1+3/x)/Gamma(1+1/x)**3 评估一个函数。
    • 我想我只能手动完成。但是很高兴知道 Python 也可以处理这个问题。
    猜你喜欢
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2021-01-27
    • 2021-11-08
    相关资源
    最近更新 更多