Lagrange Polynomials
In numerical analysis, the Lagrange polynomial is the polynomial of least degree that exactly coincides with a set of data points. I provide the geometric intuition and proof of correctness for this idea.
In numerical analysis, given a set of data points where each is unique, a Lagrange polynomial (Waring, 1779) is a polynomial of lowest degree that “fits” these data in the sense that the polynomial passes through each point . As we will see, the geometric intuition is elegant and the proof of correctness is straightforward. Formally, the Lagrange polynomial is
where each term is called a basis polynomial,
There is a lot of notation to unpack, but the geometric intuition is quite simple (Figure ). The Lagrange polynomial passes through each point because each of the scaled basis polynomials passes through precisely one of the points while “zeroing out” at the other points.
To show the correctness of , consider the th basis polynomial on data point :
If , then each term in the product is one and . If , then one term in the product is zero, the term in which . Since , the exclusion does not prevent . Put differently, , and provided . Finally, notice in Equation that each basis polynomial is scaled by its associated .
Why is the Lagrange polynomial the one of least degree that fits points? To fit points exactly, we need a polynomial of at most degree . Think about it for small . If , we need a line. If , we may need a curve. And so forth. Of course, is the maximum needed degree. For example, three points could form a line in . The Lagrange polynomial has basis polynomials, each of which has degree because each is the product of terms with a single . So , the sum of polynomials of degree , must have degree at most .
Here is the Python implementation that I used to generate Figure :
import numpy as np
class LagrangePoly:
def __init__(self, X, Y):
self.n = len(X)
self.X = np.array(X)
self.Y = np.array(Y)
def _basis(self, x, j):
b = [(x - self.X[m]) / (self.X[j] - self.X[m])
for m in range(self.n) if m != j]
return np.prod(b, axis=0)
def scaled_basis(self, x, j):
return self._basis(x, j) * self.Y[j]
def interpolate(self, x):
b = [self.scaled_basis(x, j) for j in range(self.n)]
return np.sum(b, axis=0)
- Waring, E. (1779). VII. Problems concerning interpolations. Philosophical Transactions of the Royal Society of London, 69, 59–67.