Método que permite encontrar un polinomio que interpola un conjunto de puntos mediante un sistema de ecuaciones. El grado del polinomio resultante depende directamente de la cantidad de puntos dada y se verá en algunos ejemplos que la cantidad de puntos puede generar oscilaciones indeseadas en las curvas generadas dependiendo de la naturaleza de las funciones.
Creado: Abril 16 de 2017
Modificado: Noviembre 12 de 2018
Testeado en Python 3.6.4
Modificado: Noviembre 12 de 2018
Testeado en Python 3.6.4
Se encontrará un polinomio que interpole $k+1$ puntos diferentes $(x_0, y_0), (x_1, y_1), ..., (x_k, y_k)$ usando el método de interpolación de Lagrange. El polinomio generado es una combinación lineal de la forma:
Dónde $l_j$ son las bases polinómicas de Lagrange definidas como:
In [1]:
import sympy
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('ggplot')
Implementación del método¶
In [2]:
def arg_prod(i, j):
""" Argumento de la productoria de las bases polinómicas de
Lagrange.
"""
# Variable simbólica
x_sim = sympy.symbols('x')
return (x_sim-x[i]) / (x[j]-x[i]) if i != j else 1
def interpolacion_lagrage(x, y, num_puntos=100):
""" Estima la curva generada por el polinomio de lagrange que
interpola los puntos datos
args:
x (np.array): Datos del eje x
y (np.array): Datos del eje y
num_puntos (int): Número de puntos estimados a partir del polinomio
returns:
Puntos (x, y) estimados a partir del polinomio encontrado. Tupla
"""
# Variable simbólica
x_sim = sympy.symbols('x')
# Número de puntos ingresados
points = len(x)
# Bases polinómicas lj = [l1, l2, ..., lk]
lj = []
for k in range(points):
lk = np.prod([arg_prod(i, k) for i in range(points)])
lj.append(lk)
# Polinomio de lagrange
pol = sum(y*lj)
# Se generan los datos x, y a partir del polinomio encontrado
x_test = np.linspace(min(x), max(x), num_puntos)
y_pol = [pol.subs(x_sim, i) for i in x_test]
return x_test, y_pol
Aplicación¶
Se aproximará la función seno a un polinomio tomando solo 4 puntos
In [3]:
# Datos
x = np.linspace(-np.pi, np.pi, 4)
y = np.array([np.sin(i) for i in x])
# Puntos generados por el polinomio de Lagrange
x_test, y_pol = interpolacion_lagrage(x, y)
# Gráfica
plt.plot(x_test, y_pol)
plt.scatter(x, y)
plt.legend(['Lagrange', 'Datos'], loc='best')
Out[3]:
<matplotlib.legend.Legend at 0x166509cb5f8>
Para mejorar la precisión se aumenta la cantidad de puntos a 15
In [4]:
# Datos
x = np.linspace(-np.pi, np.pi, 15)
y = np.array([np.sin(i) for i in x])
# Puntos generados por el polinomio de Lagrange
x_test, y_pol = interpolacion_lagrage(x, y)
# Gráfica
plt.plot(x_test, y_pol)
plt.scatter(x, y)
plt.legend(['Lagrange', 'Datos'], loc='best')
Out[4]:
<matplotlib.legend.Legend at 0x16650af2860>
El grado del polinomio aumenta que se aumentan los puntos a interpolar por lo que, dependiendo de la naturaleza de la función, para una gran cantidad de puntos las oscilaciones entre estos son mayores. Veamos un ejemplo tomando 10 puntos:
In [5]:
# Datos
x = np.array([-3.2300, 2.0000, -1.0023, 0.0000, 2.1230,
-3.5120, 0.1223, 5.6420, -2.2574, 5.3410])
y = np.array([-3.4360, 3.4120, 0.9300, 1.5960, 0.0000,
0.9315, 4.1230, 0.0140, -0.2320, 2.123])
# Puntos generados por el polinomio de Lagrange
x_test, y_pol = interpolacion_lagrage(x, y)
# Gráfica
plt.plot(x_test, y_pol)
plt.scatter(x, y)
plt.legend(['Lagrange', 'Datos'], loc='best')
Out[5]:
<matplotlib.legend.Legend at 0x16650bb0a20>