区分多项式插值数据点集

时间:2016-04-16 18:03:20

标签: python numpy

我知道我们可以让numpy区分多项式与以下内容:

f = numpy.poly1d([1, 0, 1])
f.deriv()

我尝试插入一组数据点并对生成的多项式执行deriv()

from scipy import interpolate

x = [-2,-1,2]
y = [-2,1,-1] 

f = interpolate.interp1d(x, y)
f.deriv()

但是对象f的类型不同。

基本上,我如何将f转换为准备区分的numpy多项式对象?

非常感谢!

1 个答案:

答案 0 :(得分:3)

您在这里面临的问题是插值的实际工作方式。插值最多可以猜测一些与给定点匹配最好的局部函数,但它可以完全,并且可能永远不会,除了可能是一些极端简单的情况(?),与给定的实际函数完全正确。

也就是说,您可以将给定范围内的函数近似为泰勒多项式。这应该是相对较窄的范围,并且对初始函数的良好猜测对你来说足够好。(?)

import numpy as np
from scipy import interpolate

x = [-2, -1, 2]
y = [-2, 1, -1]

f  = interpolate.interp1d(x, y)
h = interpolate.approximate_taylor_polynomial(f, -1, 2, 2)

h
>>>> poly1d([-0.61111111,  1.16666667, -0.22222222])

h.deriv()
>>>> poly1d([-1.22222222,  1.16666667])

编辑I扩展原始答案以澄清:

我想表明这种方法在某种程度上起作用。上面使用的OP示例实际上是一个很小的MWE示例,因此结果不太令人信服。

为了表明它非常接近,我将构造一个多项式。我会在范围[-5,5]中得到它的值。我将范围[-5,5]和多项式的返回值用作插值数组。

我使用最佳"猜测"来近似使用泰勒级数展开的插值函数。我有(因为我构造了原始多项式,这不是真的猜测tbh)。

我将泰勒展开范围[-5,5]中的结果与范围内的原始多项式值进行比较。

f = np.poly1d([1,0,1])

f([-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5])
>>> array([26, 17, 10,  5,  2,  1,  2,  5, 10, 17, 26])

x = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
y = [26, 17, 10,  5,  2,  1,  2,  5, 10, 17, 26]

f = interpolate.interp1d(x, y)

h = interpolate.approximate_taylor_polynomial(f, 0, 2, 5)

h(x)
>>> [26., 17.12, 10.21333333, 5.28, 2.32, 1.33333333, 2.32, 5.28, 10.21333333, 17.12, 26.]

f(x)
>>> [26., 17., 10., 5., 2., 1., 2., 5., 10., 17., 26.]

以下是一些示例,用于说明猜测如何越来越好,以及您使用的泰勒扩展的更高阶数。小心如手册所说,一旦达到30级,扩展就会不稳定。

h = interpolate.approximate_taylor_polynomial(f, 0, 15, 5)
>>> [ 25.41043927,  17.18570392,  10.19122784,   5.09107466,
         2.02363911,   1.        ,   2.02664952,   5.07915194,
        10.22646919,  17.13871545,  26.        ])

h = interpolate.approximate_taylor_polynomial(f, 0, 20, 5)
>>> [  26.        ,  17.13481942,  10.10070835,   5.21247548,
         2.13174692,   1.23098041,   2.13174692,   5.21247548,
        10.10070835,  17.13481942,  25.9999999 ])

EDIT II评论中的问题答案:

这不是一个愚蠢的问题。我可以看到泰勒系列令你困惑。在数学中,他们通常在扩展点上基于原函数的n阶导数显示泰勒级数的数学定义,但是没有显示其他因子,因此如何在更广泛的意义上应用它可能会令人困惑。

本质上它与衍生物相同:

f' = lim d->0 [ ( f(x+d)-f(x) )/d ]

在数值编程中我们只是近似于:

f' = f(x+d)-f(x)/d (there are other approx of the derivative as well)
只要d保持很小,这就是一个很好的近似值。泰勒系列函数就是这样的:

0th order: h ~ f(a) 
1st order: h ~ f(a) + f'(a)(x-a)
2nd order: h ~ f(a) + f'(a)(x-a) + f''(a)/2 * (x-a)^2 ...
...

所以如果我们现在将我们的导数近似引入到系列展开中:

               1st deriv                        2nd deriv
h ~ f(a) + [ (f(a+d)-f(a))/d ] (x-a) + [ ( f(a+d) - 2f(a) + f(a-d) )/d^2 ) ] * (x-a)^2 ....

所以现在你看到为什么函数需要它需要被评估的点。现在,这有助于我们摆脱原有函数的推导。

所以你看,我们根本不需要知道原来的功能。我们必须做的就是提供原始函数在扩展点时可能具有的近似值。而这正是插值给你的。

插值接受一组可能归因于某些原始函数的点,然后基于这些点的行为试图猜测给定点之间的哪些点最可能也在原始函数的图中。因此,在本质上,插值会尝试在原始点的范围内猜测我们所知道的原始点的可能函数的值。

确定。但是我们如何处理Taylor exp。进入无限? 我们只围绕它:

h ~ 0th + 1st + 2nd + 3rd + ... + nth + P

我们称P为余数。有一些方法可以估算这个余数,其中一些由泰勒自己提出。

好的,但现在我们为什么需要在函数调用中使用范围?

我们在这里做的是什么称为有限差分法。从本质上讲,它就是那么简单,实际上事情可能会变得更复杂,因为你必须证明你确实可以做这些事情而不是打破泰勒系列的融合。事实证明,你不会破坏泰勒系列但仅限于有界连续函数,这意味着你只能在一定的时间间隔内近似函数。

这样想。您可以使用泰勒系列近似直线。可以把它想象为越来越多的多项式阶数,直到它们的“波纹度”为止。互相取消。喜欢犯罪^ 2 + cos ^ 2总是1。

但是如果你按某种顺序停止系列扩张,那么突然之间,你没有任何阻止系列再次发散的东西。因为泰勒级数只是一个大的多项式,它将开始上升到无穷大或下降到无穷大。看下面的图像,它显示了泰勒序列近似于原始二次函数f在它周围10的范围内的扩展点0;但从-50到50绘制。

enter image description here

特别感兴趣的是第一个系列订单,从上面的公式(绿色)可以看出这只是一条直线。请注意,一旦系列跨越-10或10,他们就会开始大量偏离实际功能。在某些情况下,函数足够相似以继续与原始函数接近(即,二阶泰勒级数也是二次方程,这就是为什么它非常好地跟踪原始函数)。

不幸的是,因为我们在你的案例中没有关于原始函数的任何先验知识,所以不可能确定一些泰勒扩展完全估计它。据我们所知,我们只接近0左右的函数。它可能包含正弦或余弦成员。

就你关于f的问题而言:

f只是我开始的一些虚拟功能。它应该看起来像np.poly1d([1,0,1]),它应该是f(x) = x**2 +1。我不知道你从哪里来2.1667 + 0.25x - 0.9167x**2

我只使用f来创建xy数组,这样我就可以确定这些数字确实属于某个函数。否则会有什么意义。我最后通过f(x)再次使用它来显示数字的相似程度。

记住x是一个数组,f(x)表示"计算数组x"的每个成员的函数f的值。而已。它只是点f(x) = x**2+1中函数[-5, -4, .... 4, 5]的值。

所有其他作品都是基于如何通过泰勒展开来近似函数,只要你拥有的是一些固定数据集并且不知道原始函数。我展示了如果你在点之间进行插值并用泰勒展开逼近未知函数,你可以重建一个在有界数字x范围内具有有意义相似结果的函数。

这个近似函数在我的代码片段中被称为h,它看起来像:

h = 2.28194274e-08 + 5.37467022e-17 x - 1.98652602e-06 x^2 - 3.65181145e-15 x^3 + 7.38646849e-05 x^4 + 1.02224219e-13 x^5 + ... till 25th order would be reached

并且要在python中获得它的衍生物,你需要做的就是

h.deriv()

因为它的类型是poly1d。