簡體   English   中英

Python有效地為多個多項式找到局部最大值/最小值

[英]Python finding local maxima/minima for multiple polynomials efficiently

我正在尋找一種有效的方法來找到給定/指定范圍/邊界中多個(> 100 萬)但獨立的四階多項式的局部最小值。

我有兩個要求:

R1:即使對 100 萬個不同的多項式方程也有效

R2:局部最小值精確到0.01(即2dp)

這是我使用scipy創建的一些代碼。 沒關系,但我想知道在我進行並行編程之前是否有其他更好的包來執行這樣的任務

為了說明我的問題,讓我們先從一個多項式開始:

下面我試圖在 (-5, 5) 范圍內找到 4x^4 + 6x^3 + 3x^2 + x + 5 的局部最小值。

在我的筆記本電腦上,大約需要 2 毫秒才能找到本地最小值(約為 -0.72770502)。

一個多項式的時間還可以,但我想要更快的東西,因為我需要定期執行此操作超過 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)

下面是我打算用 100 萬個不同的 4 階多項式定期做的事情,我想在本地最小化。 希望有人能指出我比scipy更合適的包。 或者有什么替代方法? 謝謝!

# 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)

由於您要找到多項式的最小值,因此您可以利用以下事實:對多項式求導很容易,並且有許多很好的算法可以找到多項式的根。

以下是它的工作原理:

  1. 首先,取導數。 所有最小值點的導數都為零。
  2. 尋找那些零,也就是找到導數的根。
  3. 一旦我們有了候選人名單,請檢查解決方案是否真實。
  4. 檢查解決方案是否在您設置的范圍內。 (我不知道您是否添加了邊界,因為您實際上想要邊界,或者讓它更快。如果是后者,請隨時刪除此步驟。)
  5. 實際上用多項式評估候選者並找到最小的那個。

這是代碼:

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)))

這在我的計算機上需要 162 微秒,比 scipy.optimize 解決方案快大約 6 倍。 (問題中顯示的解決方案在我的計算機上需要 1.12 毫秒。)

編輯:更快的選擇

這是一種更快的方法。 但是,它放棄了邊界檢查,使用了已棄用的 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))

它的時鍾速度為 110 微秒,比原來的速度快了大約 10 倍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM