我对编程相当陌生,并且认为我会尝试编写线性插值函数。线性插值 - 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