使用 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.brentq
和 scipy.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.
的那一部分
下面是本例中的一些典型代码。
我有函数 f1 = lambda x: 1 - 1.12 * (x ** 0.5) * ((1-x) ** 0.02)
,我想求解它在区间 (0, 1) 中的根。我曾尝试使用 scipy.optimize.brentq
和 scipy.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.
的那一部分下面是本例中的一些典型代码。