簡體   English   中英

查找一維插值函數的最大值/最小值

[英]Find maximum/minimum of a 1d interpolated function

我有一組數據,我正在用kind = 'cubic'插值。

我想找到這個三次插值函數的最大值。

目前我正在做的只是在插值數據數組中找到最大值,但我想知道插值函數作為一個對象是否可以微分以找到它的極值?

代碼:

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

x_axis = np.array([ 2.14414414,  2.15270826,  2.16127238,  2.1698365 ,  2.17840062, 2.18696474,  2.19552886,  2.20409298,  2.2126571 ,  2.22122122])
y_axis = np.array([ 0.67958442,  0.89628424,  0.78904004,  3.93404167,  6.46422317, 6.40459954,  3.80216674,  0.69641825,  0.89675386,  0.64274198])

f = interp1d(x_axis, y_axis, kind = 'cubic')

x_new = np.linspace(x_axis[0], x_axis[-1],100)

fig = plt.subplots()
plt.plot(x_new, f(x_new))

三次樣條的導數是二次樣條。 SciPy 只有一個內置的方法來找到三次樣條的根。 所以有兩種方法:

  1. 使用 4 度樣條進行插值,以便可以輕松找到其導數的根。
  2. 使用三次樣條(通常更可取),並為其導數的根編寫自定義函數。

我在下面描述了這兩種解決方案。

4 度樣條

使用InterpolatedUnivariateSpline .derivative.derivative方法返回三次樣條,可以應用.roots方法。

from scipy.interpolate import InterpolatedUnivariateSpline
f = InterpolatedUnivariateSpline(x_axis, y_axis, k=4)
cr_pts = f.derivative().roots()
cr_pts = np.append(cr_pts, (x_axis[0], x_axis[-1]))  # also check the endpoints of the interval
cr_vals = f(cr_pts)
min_index = np.argmin(cr_vals)
max_index = np.argmax(cr_vals)
print("Maximum value {} at {}\nMinimum value {} at {}".format(cr_vals[max_index], cr_pts[max_index], cr_vals[min_index], cr_pts[min_index]))

輸出:

最大值 6.779687224066201 在 2.1824928509277037
最小值 0.34588448400295346 在 2.2075868177297036

三次樣條

我們需要一個用於二次樣條根的自定義函數。 在這里(解釋如下)。

def quadratic_spline_roots(spl):
    roots = []
    knots = spl.get_knots()
    for a, b in zip(knots[:-1], knots[1:]):
        u, v, w = spl(a), spl((a+b)/2), spl(b)
        t = np.roots([u+w-2*v, w-u, 2*v])
        t = t[np.isreal(t) & (np.abs(t) <= 1)]
        roots.extend(t*(b-a)/2 + (b+a)/2)
    return np.array(roots)

現在完全按照上述進行,除了使用自定義求解器。

from scipy.interpolate import InterpolatedUnivariateSpline
f = InterpolatedUnivariateSpline(x_axis, y_axis, k=3)
cr_pts = quadratic_spline_roots(f.derivative())
cr_pts = np.append(cr_pts, (x_axis[0], x_axis[-1]))  # also check the endpoints of the interval
cr_vals = f(cr_pts)
min_index = np.argmin(cr_vals)
max_index = np.argmax(cr_vals)
print("Maximum value {} at {}\nMinimum value {} at {}".format(cr_vals[max_index], cr_pts[max_index], cr_vals[min_index], cr_pts[min_index]))

輸出:

最大值 6.782781181150518 在 2.1824928579767167
最小值 0.45017143148176136 在 2.2070746522580795

與第一種方法的輸出略有差異不是錯誤; 4 度樣條和 3 度樣條有點不同。

quadratic_spline_roots解釋

假設我們知道二次多項式在 -1、0、1 處的值是 u、v、w。 它在區間 [-1, 1] 上的根是什么? 通過一些代數,我們可以發現多項式是

((u+w-2*v) * x**2 + (w-u) * x + 2*v) / 2

現在可以使用二次公式,但最好使用np.roots因為它也將處理前導系數為零的情況。 然后將根過濾為 -1 到 1 之間的實數。最后,如果區間是 [a, b] 而不是 [-1, 1],則進行線性變換。

獎勵:中頻三次樣條的寬度

假設我們想找到樣條曲線取其最大值和最小值的平均值(即中值)的位置。 那么我們絕對應該使用三次樣條進行插值,因為現在需要使用roots方法。 不能只做(f - mid_range).roots() ,因為 SciPy 不支持向樣條添加常數。 相反,從y_axis - mid_range構建一個向下移動的樣條。

mid_range = (cr_vals[max_index] + cr_vals[min_index])/2
f_shifted = InterpolatedUnivariateSpline(x_axis, y_axis - mid_range, k=3)
roots = f_shifted.roots()
print("Mid-range attained from {} to {}".format(roots.min(), roots.max()))

從 2.169076230034363 到 2.195974299834667 的中間值

暫無
暫無

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

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