【问题标题】:Newton method in python / scipypython / scipy中的牛顿法
【发布时间】:2018-02-26 04:14:28
【问题描述】:

我正在尝试在 python 上使用牛顿算法获取函数的根。即使我更改精度级别,我也会遇到运行时错误。您能帮我了解如何改进它吗?

最好, 国标

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

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)

【问题讨论】:

    标签: python scipy mathematical-optimization newtons-method


    【解决方案1】:

    很难在如此稀疏的上下文中给出建议。但有几点意见:

    答:

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

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

    乙:

    你的错误来自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) 等的问题。

    这不是关于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 初始化),因为这是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!
    

    输出:

    117.214682594
    

    【讨论】:

    • 非常感谢您的 cmets,它很有帮助!实际上,在我的优化中,我想在我的函数 = 0 时求解 S。所以也许 args=(r,T,d,sigma,q,K1,K2,) 部分不正确。你知道我怎么能抽搐吗?
    • 这不是评论。这是 SO 术语的答案。如果有帮助,答案通常会被赞成(并且不应该总是假设一个将您的非工作解决方案转换为一个工作解决方案;而只是指出明显的问题);-)。 编辑阅读我的答案编辑!
    • 这很有效,我应该尝试颠倒顺序。非常感谢您的帮助!
    • @phacoo 也许是时候接受答案了。我想新用户应该能够做到这一点,对吧?
    • 嗨,sacha,我很乐意接受。我已经验证过了。如果我还有其他事情要做,请告诉我。
    猜你喜欢
    • 2017-05-05
    • 2018-01-03
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 2017-01-25
    相关资源
    最近更新 更多