Scipy中使用导数的牛顿法:TypeError:'numpy.float64'对象不可调用。

3

我遇到了scipy的牛顿法问题。当我使用给定的导数来使用newton时,会出现错误(请参见下面的错误输出)。

我正在尝试使用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

功能 = <函数f,地址为0x04049EF0>,起始点 = 2.0,一阶导数 = 4.0,参数 = () 容差 = 1.48e-08,最大迭代次数 = 50,二阶导数 = 无
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

文件 "C:\Anaconda\lib\site-packages\scipy\optimize\zeros.py", 第116行 类型错误

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的点,因此如果没有实根,我也不会感到惊讶。


函数“expr”没有任何根。但是,如果您从某一点减去其y值,并计算结果函数f = gamma(1 + 3 / x)/ gamma(1 + 1 / x)** 3-y0的根,则可以得到“expr”在点y0处的反向x0。感谢您使用lambdify的答案,这将有所帮助。 - jjack
我的意思是导数没有根。从数学上讲,原函数似乎也没有根(这在数学上是巧合)。 - asmeurer

2
我认为发生的情况是您传递了导数的值,而不是表示导数的函数。您需要一个可调用的东西,而值(更具体地说是值dfx0 = derivative(f, 2.0))无法像函数一样“调用”。
顺便说一下:如果您还没有这样做,看一下这些示例可能是个好主意。

不行,你需要为导数定义一个函数。你已经定义了 f。那么你如何定义 f 的导数呢? - rookie
@jjack:你可以尝试这样做:newton(f, 2.0, lambda x: 2*x) - rookie
@jjack 我不明白...我的建议没有帮助吗? - rookie
不,它有帮助。我只是想符号化地计算导数,而不是手动计算。谢谢。 - jjack
@jjack:你可能想要查看这个 - rookie
显示剩余4条评论

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