Scipy牛顿法求导时:TypeError: 'numpy.float64'对象不可调用

3 投票
2 回答
3841 浏览
提问于 2025-04-18 16:36

我在使用scipy的牛顿法时遇到了问题。当我提供导数时,使用newton函数会出现错误(下面是错误输出)。

我想计算x**2的根,起始值设为x0 = 2.0:

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' object is not callable

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

TypeError

2 个回答

3

你可以使用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的明显点,所以如果没有实数根,我也不会感到惊讶。

2

我觉得你遇到的问题是,你传入的是一个导数的值,而不是一个表示导数的函数。你需要的是一个可以“调用”的东西,而像 dfx0 = derivative(f, 2.0) 这样的值是不能像函数那样被“调用”的。

顺便说一下,如果你还没看过,建议你去看看 这些例子

撰写回答