[英]Python finding local maxima/minima for multiple polynomials efficiently
I am looking for an efficient way to find local mins for multiple (>1 million) but independent 4th order polynomials in given/ specified ranges/ boundaries .我正在寻找一种有效的方法来找到给定/指定范围/边界中多个(> 100 万)但独立的四阶多项式的局部最小值。
I have two requirements:我有两个要求:
R1: efficient even for 1 million different polynomial equations R1:即使对 100 万个不同的多项式方程也有效
R2: the local min is accurate up to 0.01 (ie 2dp) R2:局部最小值精确到0.01(即2dp)
Here is some code I have created using scipy
.这是我使用
scipy
创建的一些代码。 It's okay but I am wondering if there's any other better packages in performing such a task before I go for parallel programming.没关系,但我想知道在我进行并行编程之前是否有其他更好的包来执行这样的任务。
To illustrate my problem, let's start with one polynomial first:为了说明我的问题,让我们先从一个多项式开始:
Below I am trying to find the local min of 4x^4 + 6x^3 + 3x^2 + x + 5 within the range (-5, 5).下面我试图在 (-5, 5) 范围内找到 4x^4 + 6x^3 + 3x^2 + x + 5 的局部最小值。
On my laptop, it takes about 2ms to find the local min (which is at ~ -0.72770502).在我的笔记本电脑上,大约需要 2 毫秒才能找到本地最小值(约为 -0.72770502)。
The time is alright for one polynomial but I would want something faster as I need to perform this operation over 1 million times regularly.一个多项式的时间还可以,但我想要更快的东西,因为我需要定期执行此操作超过 100 万次。
from scipy import optimize
import numpy as np
# Define a objective and gradient function for 4th order polynomial
# x is the value to be evaluated
# par is a numpy array of len 5 that specifies the polynomial coefficients.
def obj_grad_fun_custom(x,par):
obj = (np.array([x**4,x**3,x**2,x**1,1]) * par).sum()
grad = (np.array([4*x**3,3*x**2,2*x,1]) * par[:-1]).sum()
return obj, grad
# Try minimise an example polynomial of 4x^4 + 6x^3 + 3x^2 + x + 5
# with contrainted bound
res = optimize.minimize(
fun = obj_grad_fun_custom,
x0 = 0,
args=(np.array([4,6,3,1,5])), # polynomial coefficients
jac=True ,
bounds=[(-2, 10)],
tol=1e-10)
print(res.x)
# Timing (this takes about 2 ms for me)
%timeit optimize.minimize(fun = obj_grad_fun_custom, x0 = 0, args=(np.array([4,6,3,1,5])), jac=True, bounds=[(-5, 5)], tol=1e-10)
Below is what I am planning to do regular with 1 million different order 4 polynomials I would want to minimise locally.下面是我打算用 100 万个不同的 4 阶多项式定期做的事情,我想在本地最小化。 Hopefully, someone could point me to a more suitable package other than
scipy
.希望有人能指出我比
scipy
更合适的包。 Or any alternative methods?或者有什么替代方法? Thanks!
谢谢!
# Multiple polynomials
result = [] # saving the local minima
poly_sim_no = 1000000 #ideally 1 million or even more
np.random.seed(0)
par_set = np.random.choice(np.arange(10), size=(poly_sim_no, 5), replace=True) #generate some order 4 polynomial coefficients
for a in par_set:
res = optimize.minimize(obj_grad_fun_custom, 0,args=(a), jac=True ,bounds=[(-5, 5)], tol=1e-10)
result.append(res.x)
print(result)
Since you're finding the minimum of a polynomial, you can take advantage of the fact that it's easy to take the derivative of a polynomial, and that there are many good algorithms for finding the roots of a polynomial.由于您要找到多项式的最小值,因此您可以利用以下事实:对多项式求导很容易,并且有许多很好的算法可以找到多项式的根。
Here's how it works:以下是它的工作原理:
Here's the code:这是代码:
import numpy as np
from numpy.polynomial import Polynomial
def find_extrema(poly, bounds):
deriv = poly.deriv()
extrema = deriv.roots()
# Filter out complex roots
extrema = extrema[np.isreal(extrema)]
# Get real part of root
extrema = np.real(extrema)
# Apply bounds check
lb, ub = bounds
extrema = extrema[(lb <= extrema) & (extrema <= ub)]
return extrema
def find_minimum(poly, bounds):
extrema = find_extrema(poly, bounds)
# Note: initially I tried taking the 2nd derivative to filter out local maxima.
# This ended up being slower than just evaluating the function.
# Either bound could end up being the minimum. Check those too.
extrema = np.concatenate((extrema, bounds))
# Check every candidate by evaluating the polynomial at each possible minimum,
# and picking the minimum.
value_at_extrema = poly(extrema)
minimum_index = np.argmin(value_at_extrema)
return extrema[minimum_index]
# Warning: polynomial expects coeffients in the opposite order that you use.
poly = Polynomial([5,1,3,6,4])
print(find_minimum(poly, (-5, 5)))
This takes 162 microseconds on my computer, making it about 6x faster than the scipy.optimize solution.这在我的计算机上需要 162 微秒,比 scipy.optimize 解决方案快大约 6 倍。 (The solution shown in the question takes 1.12 ms on my computer.)
(问题中显示的解决方案在我的计算机上需要 1.12 毫秒。)
Here's a faster approach.这是一种更快的方法。 However, it abandons bounds checking, uses a deprecated API, and is generally harder to read.
但是,它放弃了边界检查,使用了已弃用的 API,并且通常更难阅读。
p = np.poly1d([4,6,3,1,5]) # Note: polynomials are opposite order of before
def find_minimum2(poly):
roots = np.real(np.roots(poly.deriv()))
return roots[np.argmin(poly(roots))]
print(find_minimum2(p))
This clocks in at 110 microseconds, making it roughly 10x faster than the original.它的时钟速度为 110 微秒,比原来的速度快了大约 10 倍。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.