python / scipy中的牛顿方法

时间:2017-09-17 15:02:51

标签: python scipy mathematical-optimization newtons-method

我试图在python上使用牛顿算法获得函数的根。即使我更改了精度级别,我也有运行时错误。能帮助我了解我该如何改进它?

最佳, GB

在我的“简单”代码和根查找部分下面:

from scipy.stats import norm
import numpy as np 
import matplotlib.pyplot as plt  
import scipy.optimize as opt


def vega_callspread(r,S,T,d,sigma,q,K1,K2):

    d1 = (np.log(S/K1)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))
    d2 = (np.log(S/K2)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))

    u1 = S*np.exp(-q*T)*norm.pdf(d1,0,1)
    u2 = S*np.exp(-q*T)*norm.pdf(d2,0,1)

    return u1-u2;

x0=112
r=0
T=1
d=0
sigma=0.2
q=0
K1=110
K2=130




res2= opt.newton(vega_callspread, x0, args=(r,T,d,sigma,q,K1,K2,),tol=10**(-1),maxiter=1000000)


the error i get is: res2= opt.zeros.newton(vega_callspread, x0, args=(r,T,d,sigma,q,K1,K2,),tol=10**(-1),maxiter=1000000)
/Users/anaconda/lib/python3.5/site-packages/scipy/optimize/zeros.py:173: RuntimeWarning: Tolerance of 0.011300000000005639 reached
  warnings.warn(msg, RuntimeWarning)

1 个答案:

答案 0 :(得分:1)

很难用如此稀疏的语境提供建议。但有些评论:

A:

您没有使用牛顿,如here所述:

  

如果提供了func的导数fprime,则使用Newton-Raphson方法,否则使用割线方法。

B:

您的错误来自here我会说:

由于这些tol值是硬编码的,我想这不应该发生!

# Secant method
p0 = x0
if x0 >= 0:
    p1 = x0*(1 + 1e-4) + 1e-4
else:
    p1 = x0*(1 + 1e-4) - 1e-4
q0 = func(*((p0,) + args))
q1 = func(*((p1,) + args))
for iter in range(maxiter):
    if q1 == q0:
        if p1 != p0:
            msg = "Tolerance of %s reached" % (p1 - p0)
            warnings.warn(msg, RuntimeWarning)
        return (p1 + p0)/2.0

含义:你的代码可能有问题!

C:

让我们尝试更慢但更安全的bisection-method

# brackets not tuned! it's just some trial!
res2 = opt.bisect(vega_callspread, 0, 200, args=(r,T,d,sigma,q,K1,K2))

输出:

X:\so_newton.py:9: RuntimeWarning: divide by zero encountered in log
  d1 = (np.log(S/K1)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))
X:\so_newton.py:10: RuntimeWarning: divide by zero encountered in log
  d2 = (np.log(S/K2)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))

这是一个不好的迹象。

D(跟C):

你的功能是:

def vega_callspread(r,S,T,d,sigma,q,K1,K2):

    d1 = (np.log(S/K1)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))
    d2 = (np.log(S/K2)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))

    u1 = S*np.exp(-q*T)*norm.pdf(d1,0,1)
    u2 = S*np.exp(-q*T)*norm.pdf(d2,0,1)

    return u1-u2;

你打电话给:

x0=112
r=0
T=1
d=0
sigma=0.2
q=0
K1=110
K2=130

args=(r,T,d,sigma,q,K1,K2,)

没有S!

所以你要么危险地重命名变量,要么你的结尾有一些错误!

S的值是log(S/K1)和co。

中的问题

它不是关于S/K1而是关于此:

import numpy as np
np.log(0)
# __main__:1: RuntimeWarning: divide by zero encountered in log
# -inf

我是从this SO-answer获得的。

您现在可以尝试解释这对您的函数的作用,因为此log-eval将获得-np.inf的值。

E scipy如何处理(遵循D):

我懒得阅读args-handling的文档/来源,但让我们检查一下(给func添加一个打印件;使用之前的二分法):

def vega_callspread(r,S,T,d,sigma,q,K1,K2):

    print('S: ', S)

    d1 = (np.log(S/K1)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))
    d2 = (np.log(S/K2)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))

    u1 = S*np.exp(-q*T)*norm.pdf(d1,0,1)
    u2 = S*np.exp(-q*T)*norm.pdf(d2,0,1)

    return u1-u2;

输出:

S:  0
X:\so_newton.py:11: RuntimeWarning: divide by zero encountered in log
  d1 = (np.log(S/K1)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))
X:\so_newton.py:12: RuntimeWarning: divide by zero encountered in log
  d2 = (np.log(S/K2)+(r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))
S:  0

所以似乎arg-handling是通过arg-name(而不仅仅是调用中的param-position;我在这里错过了正确的编程语言术语;再次懒惰!)

这个(S = 0)可能非常糟糕(而不是你想要的),这是你的错误!

修改

发表评论后,您似乎尝试优化S。这让我很清楚,您正在使用一些优化算法优化x,而您的函数中没有x

我没有在这里分析您的任务,但您可能希望让您的功能使用一些x(由x0初始化),因为这是{{1}的一般概念}。我们可以保留名称scipy.optimize,但它必须是函数的第一个参数。这些都在文档中解释。

所以:

S

输出:

def vega_callspread(S, r,T,d,sigma,q,K1,K2):  # S now first argument !!!
    ...

res2= opt.newton(vega_callspread, x0, args=(r,T,d,sigma,q,K1,K2,),tol=10**(-1),maxiter=1000000)  # S removed from args; S is init by x0 -> read docs!