使用 scipy.optimize 求解给定区间内的根

Solve for roots in given interval using scipy.optimize

我有函数 f1 = lambda x: 1 - 1.12 * (x ** 0.5) * ((1-x) ** 0.02),我想求解它在区间 (0, 1) 中的根。我曾尝试使用 scipy.optimize.brentqscipy.optimize.fsolve 来执行此操作,但是这两种方法 运行 都存在问题。根据一些实验,我得到这个方程的根大约等于 0.86322414 和 0.9961936895432034(我们知道最多有 2 个根,因为函数在这个区间有一个拐点):

f1 = lambda x: 1 - 1.12 * (x ** 0.5) * ((1-x) ** 0.02)
print(fsolve(f1, 0.5))
print(f1(0.99))
print(f1(0.999))
print(brentq(f1, 0.99, 0.999))

输出:

[ 0.86322414]
-0.016332046983897452
0.025008640855473052
0.9961936895432034

这里的问题是,为了使 brentq 工作,函数的值必须在指定的端点处具有相反的符号。此外,当我以 x 接近 1 的值启动 fsolve 时,我收到 运行 时间警告消息:

print(fsolve(f1, 0.97))
print(fsolve(f1, 0.98))

输出:

[ 0.97]
[ 0.98]
C:/Users/Alexander/Google Drive/Programming/Projects/Root Finding/roots.py:6: RuntimeWarning: invalid value encountered in power

C:\Users\Alexander\Anaconda3\lib\site-packages\scipy\optimize\minpack.py:161: RuntimeWarning: The iteration is not making good progress, as measured by the 
  improvement from the last ten iterations.

有没有人有更系统的方法来求解这个方程的根,为什么 fsolve 在 x = 0.97, 0.98 上不起作用?

fsolve 不支持区间求根。它可能会偏离到 x<0 或 x>1,因此 RuntimeWarning(一次)和垃圾作为答案。您可以通过使用 print(x).

检测您的函数来检查它

如果区间包含一个以上的根,Brentq 的行为是未定义的。

如果你知道拐点,或者知道拐点只有一个,那么你可以通过brentq找到它,用它来括住你的两个根。

如果对函数取导数并将其设为 0,经过一点代数运算后您会发现导数在 x0 = 0.5/0.52 时为 0。 (在微积分中class,这个点叫做临界点,不是拐点。)函数在这个点有极小值,那里的值为负。 x=0 和 x=1 处的值为正数,因此您可以使用 [0, x0] 和 [x0, 1] 作为 brentq:

中的包围间隔
In [17]: from scipy.optimize import brentq

In [18]: f1 = lambda x: 1 - 1.12 * (x ** 0.5) * ((1-x) ** 0.02)

In [19]: x0 = 0.5/0.52

In [20]: brentq(f1, 0, x0)
Out[20]: 0.8632241390303161

In [21]: brentq(f1, x0, 1)
Out[21]: 0.9961936895432096

如您所知,部分问题的直接答案是 fsolve 在区间 [0.97,0.98] 中找不到根,因为那里没有根。至于系统的方法,为什么不用plot?

一旦您将函数定义为 lambda,准备好与 Brent 或其他各种例程一起使用,您只需将需要的子字符串复制并粘贴到对绘制 并指出感兴趣的区间。如果其中一个根有点模糊,则扩大 x-axis.

的那一部分

下面是本例中的一些典型代码。