我對編程相當陌生,並且認爲我會嘗試編寫線性插值函數。線性插值 - Python
說我給定的數據,如下所示: X = [1,2.5,3.4,5.8,6] Y = [2,4,5.8,4.3,4]
我想設計的功能這將使用Python在1到2.5,2.5到3.4之間線性插入。
我已經試過 http://docs.python.org/tutorial/,但我仍然無法得到我的頭。
我對編程相當陌生,並且認爲我會嘗試編寫線性插值函數。線性插值 - Python
說我給定的數據,如下所示: X = [1,2.5,3.4,5.8,6] Y = [2,4,5.8,4.3,4]
我想設計的功能這將使用Python在1到2.5,2.5到3.4之間線性插入。
我已經試過 http://docs.python.org/tutorial/,但我仍然無法得到我的頭。
正如我理解你的問題,你想寫一些函數y = interpolate(x_values, y_values, x)
,這會給你y
值在一些x
?然後基本思想如下這些步驟:
x_values
限定容納x
的間隔的索引。例如,對於x=3
與您的示例列表,含間隔將是[x1,x2]=[2.5,3.4]
,以及指數將是i1=1
,i2=2
(y_values[i2]-y_values[i1])/(x_values[i2]-x_values[i1])
(即dy/dx
)計算在此時間間隔的斜率。x
現在的值爲x1
加上坡度乘以距離x1
的距離。您還需要決定是否x
是x_values
區間外發生了什麼,無論它是一個錯誤,或者你可以插值「倒退」,假設坡度是一樣的第一/最後一個區間。
有幫助嗎,還是您需要更具體的建議?
我想出了一個相當優雅的解決方案(恕我直言),所以我無法抗拒張貼:
from bisect import bisect_left
class Interpolate(object):
def __init__(self, x_list, y_list):
if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])):
raise ValueError("x_list must be in strictly ascending order!")
x_list = self.x_list = map(float, x_list)
y_list = self.y_list = map(float, y_list)
intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]
def __getitem__(self, x):
i = bisect_left(self.x_list, x) - 1
return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])
我映射到float
使整數除法(蟒蛇< = 2.7)不會踢並破壞的東西,如果x1
,x2
,y1
和y2
都是一些iterval的整數。
在__getitem__
我走的事實,self.x_list以升序使用bisect_left
來按順序排列的(非常)快速查找最大元素小於x
在self.x_list
的索引。
使用類是這樣的:
i = Interpolate([1, 2.5, 3.4, 5.8, 6], [2, 4, 5.8, 4.3, 4])
# Get the interpolated value at x = 4:
y = i[4]
我沒有處理邊界條件都在這裏,爲了簡單起見。因爲它是i[x]
對於x < 1
將工作,就像從(2.5,4)到(1,2)的行已經擴展到負無窮大,而i[x]
對於x == 1
或x > 6
將引起IndexError
。更好的辦法是在所有情況下引發IndexError,但這是留給讀者的一個練習。:)
我會發現使用'__call__'而不是'__getitem__'通常是可取的,它通常是一個插值*函數*。 – Dave
import scipy.interpolate
y_interp = scipy.interpolate.interp1d(x, y)
print y_interp(5.0)
scipy.interpolate.interp1d
執行線性插值,可定製處理錯誤條件。
您的解決方案在Python 2.7中無法使用。檢查x元素的順序時發生錯誤。我不得不改變代碼來這得到它的工作:
from bisect import bisect_left
class Interpolate(object):
def __init__(self, x_list, y_list):
if any([y - x <= 0 for x, y in zip(x_list, x_list[1:])]):
raise ValueError("x_list must be in strictly ascending order!")
x_list = self.x_list = map(float, x_list)
y_list = self.y_list = map(float, y_list)
intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]
def __getitem__(self, x):
i = bisect_left(self.x_list, x) - 1
return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])
外推離端相反的,你可能會返回y_list
的範圍。大部分時間你的申請表現良好,Interpolate[x]
將在x_list
。推斷出兩端的(可能是)線性影響可能會誤導您相信您的數據表現良好。
返回非線性結果(通過x_list
和y_list
內容爲界),你的程序的行爲可能會極大地提醒你的問題的值以外x_list
。 (給定的非線性輸入時的線性特性去香蕉!)
返還y_list
的範圍爲Interpolate[x]
外x_list
也意味着你知道你的輸出值的範圍。如果根據x
進行外推得多,遠遠低於x_list[0]
或x
遠遠多於x_list[-1]
,那麼您的退貨結果可能超出您的預期值範圍。
def __getitem__(self, x):
if x <= self.x_list[0]:
return self.y_list[0]
elif x >= self.x_list[-1]:
return self.y_list[-1]
else:
i = bisect_left(self.x_list, x) - 1
return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])
我會發現使用'__call__'而不是'__getitem__'通常是可取的,它通常是一個插值*函數*。 – Dave
這是......不容易。你有什麼嘗試? – zellio
-1太一般了。你不懂如何編程,或者如何在Python中執行算法? – steabert
作爲一個新的學習者,我已經把自己投入了深刻的目的。 我正在考慮在算法中使用'for'或'if'語句。所以在x的許多範圍之間。 – Helpless