How to do it...

  1. Interpolation is a basic method in numerical computation that is obtained from a discrete set of data points, intended to find an interpolation function that represents some higher order structure that contains the data.
  2. 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 of the points in the order dictated by the sequence.
  3. 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, 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.
  4. 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:

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 a size of 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 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 the 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 the 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

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()

The result of the plot is as follows:

More advanced one-dimensional interpolation is possible with piecewise polynomials (PiecewisePolynomial). This allows control regarding the degrees of different pieces as well as the derivatives at their intersections. Other interpolation options are the scipy.interpolate module, 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 bboxparameter 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 upon their intersection. We will proceed as follows:

import numpy
import matplotlib.pyplot as plt
mport 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:

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:

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

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