Interpolation

Interpolation is a basic method in numerical computation that is obtained from a discrete set of data points, intended to find an interpolation function which represents some higher order structure that contains the data. The best known example is the interpolation of a sequence of points (x_k and y_k) in a plane to obtain a curve that goes through all the points in the order dictated by the sequence.

If the points in the previous sequence are in the right position and order, it is possible to find a univariate function y = f(x) for which y_k = f(x_k). It is often reasonable to request this interpolating function to be a polynomial, or a rational function, or a more complex functional object. Interpolation is also possible in higher dimensions, of course. The objective of the scipy.interpolate module is to offer a complete set of optimally coded applications to address this problem in different settings.

Let's address the easiest way of interpolating data to obtain a polynomial: lagrange interpolation. Given a sequence of different x values of size n and a sequence of arbitrary real values y of the same size n, we seek a polynomial p(x) of the degree of n - 1 that satisfies the n constraints p(x[k]) = y[k] for all k from 0 to n - 1. The following code illustrates how to obtain a polynomial of degree 9 that interpolates the 10 uniformly spaced values of sine in the interval (-1, 1):

>>> import numpy
>>> import matplotlib.pyplot as plt
>>> import scipy.interpolate
>>> x=numpy.linspace(-1,1,10); xn=numpy.linspace(-1,1,1000)
>>> y=numpy.sin(x)
>>> polynomial=scipy.interpolate.lagrange(x, numpy.sin(x))
>>> plt.plot(xn,polynomial(xn),x,y,'or')
>>> plt.show()

We will obtain the following plot showing the Lagrange interpolation:

Interpolation

There are numerous issues with Lagrange interpolation. The first obvious drawback is that the user cannot specify the degree of the interpolation; this depends solely on the data. The procedure is also highly unstable numerically, especially for datasets with size over 20 points. This issue can be addressed by allowing the algorithm to depend on different properties of the dataset, rather than just the size and location of the points.

Also, it is inconvenient when we need to update the dataset by adding a few more instances; the procedure needs to be repeated again from the beginning. This proves impractical if the datasets are increasing in size and are updated frequently. To address this issue, BarycentricInterpolator has the add_xi and set_yi methods. For example, in the next session we start by interpolating 10 uniformly spaced values of the sine function between 1 and 10. Once done, we update the interpolating polynomial with 10 more uniformly spaced values between 1.5 and 10.5. As expected, this operation reduces the (percent) relative error of an interpolation computed at points within the interpolating ones. The following commands are used:

>>> import numpy
>>> import scipy.interpolate
>>> x1=numpy.linspace(1,10,10); y1=numpy.sin(x1)
>>> Polynomial=scipy.interpolate.BarycentricInterpolator(x1,y1)
>>> exactValues=numpy.sin(x1+0.3)
>>> exactValues

Here is the output for exactValues:

array([ 0.96355819,  0.74570521, -0.15774569, -0.91616594, 
-0.83226744,
        0.0168139 ,  0.85043662,  0.90217183,  0.12445442, 
-0.76768581])

Let's find the value of interpolatedValues by issuing following commands:

>>> interpolatedValues=Polynomial(x1+0.3)
>>> interpolatedValues

The output is as follows:

array([ 0.97103132,  0.74460631, -0.15742869, -0.91631362, 
-0.83216445, 
        0.01670922,  0.85059283,  0.90181323,  0.12588718, 
-0.7825744 ])

Let's find the value of PercentRelativeError by issuing following commands:

>>> PercentRelativeError = numpy.abs((exactValues - interpolatedValues)/interpolatedValues)*100
>>> PercentRelativeError

The output is as follows:

array([ 0.76960822,  0.14758101,  0.20136334,  0.01611703,  0.01237594, 
        0.62647084,  0.01836479,  0.0397652 ,  1.13812858,  1.90251374])

Then, we find what interpolatedValues2 holds:

>>> x2=numpy.linspace(1.5,10.5,10); y2=numpy.sin(x2)
>>> Polynomial.add_xi(x2,y2)
>>> interpolatedValues2=Polynomial(x1+0.3)
>>> interpolatedValues2

The output is as follows:

array([ 0.96355818,  0.74570521, -0.15774569, -0.91616594, -0.83226744,
        0.0168139 ,  0.85043662,  0.90217183,  0.12445442, -0.76768581])

Let's find the value of PercentRelativeError, keeping in consideration interpolatedValues2:

>>> PercentRelativeError = numpy.abs((exactValues - interpolatedValues2)/interpolatedValues2)*100
>>> PercentRelativeError

The output is as follows:

array([  1.26241742e-07,   2.02502252e-09,   5.95225989e-10,
         1.84438143e-11,   8.75086862e-12,   4.14359323e-10,
         1.75194631e-11,   8.52321518e-11,   9.45285176e-09,
         1.29570657e-07])

It is possible to interpolate data not only by point location, but also with the derivatives at those locations. The KroghInterpolator command allows this by including repeated x values and indicating the location and successive derivatives in order on the corresponding y values.

For instance, if we desire to construct a polynomial that is zero at the origin, one at x = 1, two at x = 2, and has horizontal tangent lines at each of these three locations, we issue the following commands:

>>> import numpy
>>> import matplotlib.pyplot as plt
>>> import  scipy.interpolate
>>> x=numpy.array([0,0,1,1,2,2]); y=numpy.array([0,0,1,0,2,0])
>>> interp=scipy.interpolate.KroghInterpolator(x,y)
>>> xn=numpy.linspace(0,2,20)   # evaluate polynomial in larger set
>>> plt.plot(x,y,'o',xn,interp(xn),'r')
>>> plt.show()

This renders the following graph:

Interpolation

More advanced one-dimensional interpolation is possible with piecewise polynomials (PiecewisePolynomial). This allows control over the degrees of different pieces as well as the derivatives at their intersections. Other interpolation options in the scipy.interpolate module are PCHIP monotonic cubic interpolation (pchip) or even univariate splines (InterpolatedUnivariateSpline).

Let's examine an example with univariate splines. Its syntax is as follows:

InterpolatedUnivariateSpline(x, y, w=None, bbox=[None, None], k=3)

The x and y arrays contain dependent and independent data, respectively. The array w contains positive weights for spline fitting. The two-sequence bbox parameter specifies the boundary of the approximation interval. The last option indicates the degree of the smoothing polynomials (k).

Suppose we want to interpolate five points as shown in the following example. These points are ordered by strictly increasing x values. We need to perform this interpolation with four cubic polynomials (one for every two consecutive points) in such a way that at least the first derivative of each two consecutive pieces agree on their intersection. We will proceed as follows:

>>> import numpy
>>> import matplotlib.pyplot as plt
>>>import scipy.interpolate
>>> x=numpy.arange(5); y=numpy.sin(x)
>>> xn=numpy.linspace(0,4,40)
>>> interp=scipy.interpolate.InterpolatedUnivariateSpline(x,y)
>>> plt.plot(x,y,'.',xn,interp(xn))
>>> plt.show()

This offers the following plot showing interpolation with univariate splines:

Interpolation

SciPy excels at interpolating in two-dimensional grids as well. It performs well with simple piecewise polynomials (LinearNDInterpolator), piecewise constants (NearestNDInterpolator), or more advanced splines (BivariateSpline). It is capable of carrying out spline interpolation on rectangular meshes in a plane (RectBivariateSpline) or on the surface of a sphere (RectSphereBivariateSpline). For unstructured data, besides the basic scipy.interpolate.BivariateSpline, it is capable of computing smooth approximations (SmoothBivariateSpline) or more involved weighted least-squares splines (LSQBivariateSpline).

The following code creates a 10 x 10 grid of uniformly spaced points in the square from (0, 0) to (9, 9), and evaluates the function sin(x) * cos(y) on the points. We use these points to create a scipy.interpolate.BivariateSpline and evaluate the resulting function on the square for all values:

>>> import numpy
>>> import scipy.interpolate
>>> import matplotlib.pyplot as plt
>>> from mpl_toolkits.mplot3d import Axes3D
>>> x=y=numpy.arange(10)
>>> f=(lambda i,j: numpy.sin(i)*numpy.cos(j))  # function to interpolate
>>> A=numpy.fromfunction(f, (10,10))           # generate samples
>>> spline=scipy.interpolate.RectBivariateSpline(x,y,A)
>>> fig=plt.figure()
>>> subplot=fig.add_subplot(111,projection='3d')
>>> xx=numpy.mgrid[0:9:100j, 0:9:100j]     # larger grid for plotting
>>> A=spline(numpy.linspace(0,9,100), numpy.linspace(0,9,100))
>>> subplot.plot_surface(xx[0],xx[1],A)
>>> plt.show()

The output is as follows, and it shows the interpolation of 2D data with bivariate splines:

Interpolation
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.205.99