Scipy牛顿法求导时:TypeError: 'numpy.float64'对象不可调用
我在使用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)
这样的值是不能像函数那样被“调用”的。
顺便说一下,如果你还没看过,建议你去看看 这些例子。