簡體   English   中英

如何將樣條擬合轉換為分段 function?

[英]How to convert a spline fit into a piecewise function?

假設我有

import numpy as np
from scipy.interpolate import UnivariateSpline

# "true" data; I don't know this function
x = np.linspace(0, 100, 1000)
d = np.sin(x * 0.5) + 2 + np.cos(x * 0.1)

# sample data; that's what I actually measured
x_sample = x[::20]
d_sample = d[::20]

# fit spline
s = UnivariateSpline(x_sample, d_sample, k=3, s=0.005)

plt.plot(x, d)
plt.plot(x_sample, d_sample, 'o')
plt.plot(x, s(x))
plt.show()

我明白了

在此處輸入圖像描述

我現在想要的是所有橙色點之間的函數,所以像

knots = s.get_knots()
f0 = <some expression> for knots[0] <= x < knots[1]
f1 = <some expression> for knots[1] <= x < knots[2]
...

因此, fi選擇方式應能再現樣條擬合的形狀。

我在這里找到了帖子,但是上面的示例中生成的樣條線似乎不正確,而且它也不完全是我需要的,因為它不返回表達式。

如何將樣條曲線變成分段 function? 是否有(直截了當)的方式來表示每個區間,例如作為多項式?

簡短的回答是,如果您對標准冪基礎中的多項式系數感興趣,則最好使用CubicSpline (請參閱此討論):

cu = scipy.interpolate.CubicSpline(x_sample, d_sample)

plt.plot(x_sample, y_sample, 'ko')
for i in range(len(cu.x)-1):
    xs = np.linspace(cu.x[i], cu.x[i+1], 100)
    plt.plot(xs, np.polyval(cu.c[:,i], xs - cu.x[i]))

三次樣條分段

And to answer your question, you could instead create a piecewise function from here using numpy.piecewise , the breakpoints in cu.x and the coefficients in cu.c , and either directly code the polynomial expressions yourself or use numpy.polyval . 例如,

cu.c[:,0]  # coeffs for 0th segment
# array([-0.01316353, -0.02680068,  0.51629024,  3.        ])

# equivalent ways to code polynomial for this segment
f0 = lambda x: cu.c[0,0]*(x-x[0])**3 + cu.c[1,0]*(x-x[0])**2 + cu.c[2,0]*(x-x[0]) + cu.c[3,0]
f0 = lambda x: [cu.c[i,0]*(x-x[0])**(3-i) for i in range(4)]

# ... or getting values directly from x's
y0 = np.polyval(cu.c[:,0], xs - cu.x[0])

更長的答案:

這里有幾個潛在的混淆點:

  • UnivariateSpline擬合B 樣條基,因此系數與標准多項式冪基不同
  • 為了從 B 樣條轉換,我們可以使用PPoly.from_spline ,但不幸的是, UnivariateSpline返回一個截斷的結和系數列表,這些結和系數不會與這個 function 一起使用。 我們可以通過訪問樣條object的內部數據來解決這個問題,這是一個小禁忌。
  • 此外,系數矩陣c (無論來自UnivariateSpline還是CubicSpline )的度數相反,並假設您自己“居中”,例如c[k,i]處的系數屬於c[k,i]*(xx[i])^(3-k)

鑒於您的設置,請注意,如果我們不使用 UnivariateSpline 包裝器,而是直接擬合splrep並且不進行平滑 ( s=0 ),我們可以獲取tck (knots-coefficients-degree) 元組並將其發送到PPoly.from_spline function並得到我們想要的系數:

tck = scipy.interpolate.splrep(x_sample, d_sample, s=0)
tck
# (array([0.        , 0.        , 0.        , 0.        , 2.68456376,
#        4.02684564, 5.36912752, 6.7114094 , 9.39597315, 9.39597315,
#        9.39597315, 9.39597315]),
# array([3.        , 3.46200469, 4.05843704, 3.89649312, 3.33792889,
#        2.29435138, 1.65015175, 1.59021688, 0.        , 0.        ,
#        0.        , 0.        ]),
# 3)

p = scipy.interpolate.PPoly.from_spline(tck)
p.x.shape  # breakpoints in unexpected shape
# (12,)

p.c.shape  # polynomial coeffs in unexpected shape
# (4, 11)

注意tckpx中奇怪的重復斷點:這是一個 FITPACK 的東西(運行所有這些的算法)。

如果我們嘗試使用(s.get_knots(), s.get_coeffs(), 3)從 UnivariateSpline 發送一個tck元組,我們會丟失這些重復,因此from_spline不起作用。 檢查雖然看起來完整的向量存儲在self._data中,所以我們可以這樣做

s = scipy.interpolate.UnivariateSpline(x_sample, d_sample, s=0)
tck = (s._data[8], s._data[9], 3)
p = scipy.interpolate.PPoly.from_spline(tck)

和以前一樣。 要檢查這些系數是否有效:

plt.plot(x_sample, d_sample, 'o')

for i in range(len(p.x)-1):
    xs = np.linspace(p.x[i], p.x[i+1], 10)
    plt.plot(xs, np.polyval(p.c[:,i], xs - p.x[i]))

分段樣條

注意numpy.polyval想要 coeff 的反向順序,因此我們可以按原樣傳遞p.c

如您所述,應該能夠使用分段 function ,例如:

import numpy as np
from scipy.interpolate import UnivariateSpline

# "true" data; I don't know this function
x = np.linspace(0, 100, 1000)
d = np.sin(x * 0.5) + 2 + np.cos(x * 0.1)

# sample data; that's what I actually measured
x_sample = x[::20]
d_sample = d[::20]

# fit spline
s = UnivariateSpline(x_sample, d_sample, k=3, s=0.005)

plt.plot(x, d)
plt.plot(x_sample, d_sample, 'o')
plt.plot(x, s(x))

knots = s.get_knots()

conditions = [x < knots[0], (x >= knots[0]) * (x < knots[1]), (x >= knots[1]) * (x < knots[10]), x >= knots[10]]
# need one function for each condition
fns = [0, lambda x :-x, lambda x: 0.01*x**2, lambda x: 0.2*x**0.5]
y = np.piecewise(x, conditions, fns)

plt.plot(x, y)
plt.show()

我選擇了一些隨機條件和函數——我相信你能找到更合適的!

覆蓋分段示例

暫無
暫無

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

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