《用Python学习数值分析--插值与拟合》

2017-08-29

  插值与拟合似乎是密不可分的话题。我在刚开始学习OpenGL绘图时,就没有搞明白曲线是如何绘制出来的。 所幸的是OpenGL封装的好,且绝大多数时候需要提供离散的几何数据。但是,我还是一直很想搞明白,从函数到曲线的离散数据,再到OpenGL程序中曲线的展示是如何做到的。
  内插是数学领域数值分析中的通过已知的离散数据求未知数据的过程或方法。科学和工程问题可以通过诸如采样、实验等方法获得若干离散的数据,根据这些数据,我们往往希望得到一个连续的函数(也就是曲线)或者更加密集的离散方程与已知数据相吻合。这个过程叫做拟合。内插是曲线必须通过已知点的拟合。插值是函数求值的逆向过程,我们最终想要得到的是一个函数。

  插值类型有:

  • 分段常量插值
  • 线性插值 
  • 多项式插值
  • 样条曲线内插 
  • 多变量插值

一,基础

  分段常量插值是最简单的,就是每个数据点都横线占据两侧区间。

   线性插值也非常简单明了,就是最终得到的函数是直线。
  最重要的是多项式插值与样条曲线插值。多项式插值,就是采用多项式来拟合经过数据点的曲线。常用的多项式有 Lagrange polynomial,Newton polynomials, Chebyshev polynomials,Trigonometric polynomials,Laurent polynomials,Power series等。多项式最高次数可以很高,但是一般由于Runge现象,太高的次数就没有意义了。样条曲线插值,就是利用多段低次曲线来模拟最终的曲线。每一段曲线一般不超过5次。贝塞尔曲线、B-Spline一般是三阶或者四阶的。N+1个控制点可以构造N阶的曲线 ( order = degree + 1)。
  Bezier曲线使用 Bernstein polynomials来进行插值。三次贝塞尔曲线有四个点,两个点为首末点叫endpoint,中间两个点是控制点。如果多段Bezier曲线在breakpoint处一阶连续,那么两边的切线斜率相同;如果在breakpoint处二阶连续,那么两边曲率相同。如果二阶连续(曲线函数为三次),那么更改多段曲线中的任意点,就会改变曲线整体。这也是Bezier曲线的弱点。
  B-spline也分为两类,均匀的与非均匀的。当节点等距时,称B-Spline为uniform的,否则是non-uniform的。当节点数和多项式次数相等时,B样条退化为贝济埃曲线。我们希望更改曲线中某个控制点的位置来更改曲线,只影响周围几个控制点所影响的曲线部分,而不是整条曲线。
  在插值中,有一个现象“龙格现象”,表明了高阶多项式通常不适合用于插值。可以证明,在多项式的阶数增高时插值误差甚至会趋向无限大,故有了上面提到的使用分段多项式的方法。为了解决龙格现象,可以使用切比雪夫节点代替等距点可以减小震荡,在这种情况下,随着多项式阶次的增加最大误差逐渐减小。

二,拟合
  代码为:https://gist.github.com/knowthyselfcn/a49e6901288b1872bb2364cdeab9b81b 

  

  上图的数据点是通过三次函数求值加上噪声产生的,也就是如果拟合,曲线对应的函数也是三次的。也可以看到,如果噪声更大一点,我们也可能猜测这是一个二次函数,那么我们最终拟合出来的曲线就是错误的。
  scipy.interpolate module提供了丰富的插值工具:单变量,多变量,1-D Spline, 2-D Spline,还有附加的工具函数。我们一般只关注单变量拟合(1-D Spline)。
  如代码 演示了拉格朗日插值的使用。可以使用上下键来提高或者降低多项式的次数,我们可以看到,当次数逐渐升高时,拟合出来的函数就没有意义了。由此处代码可知,scipy.interpolate.lagrange()是不稳定的,如果数据点超过20个,就不要期待能正常工作。反观scipy.interpolate.interp1d() 一直能够稳定工作。

ref:

  1. https://www.zhihu.com/question/24276013
  2. https://en.wikipedia.org/wiki/Interpolation
  3. https://en.wikipedia.org/wiki/B-spline
  4. https://docs.scipy.org/doc/scipy/reference/interpolate.html
如果有任何意见,欢迎留言讨论。 


[ 主页 ]

你可能感兴趣的:(机器学习)