[英]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 只有一個內置的方法來找到三次樣條的根。 所以有兩種方法:
我在下面描述了這兩種解決方案。
使用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.