Está en la página 1de 11

9/4/2018 0001-SciPy-interpolacion-ajuste

Python para ingenieros

INTERPOLACIÓN Y AJUSTE
Vamos a ver cómo interpolar y ajustar una serie de puntos con SciPy. Son tareas diferentes que
aprovecharemos en circunstancias distintas, pero ambas muy útiles. Esta clase está basada en el artículo
http://pybonacci.org/2013/08/15/ajuste-e-interpolacion-unidimensionales-basicos-en-python-con-scipy/
(http://pybonacci.org/2013/08/15/ajuste-e-interpolacion-unidimensionales-basicos-en-python-con-scipy/)

Dos problemas diferentes


Supongamos que tenemos una serie de puntos que representan los datos de un cierto experimento. Como
ejemplo, vamos a cargar los datos de la polar de un avión que están en el archivo polar.dat .

In [1]:

import numpy as np

In [2]:

%matplotlib inline
import matplotlib.pyplot as plt

El primer array línea son los datos de CL y el segunds los datos de CD .


In [3]:

# Definimos C_L y C_D


C_L=np.array([-0.91, -0.72, -0.48, -0.27, -0.06, 0.16, 0.31, 0.47, 0.6, 0.82, 1.02,
C_D=np.array([0.0538, 0.0438, 0.0316, 0.0245, 0.0228, 0.0232, 0.0262, 0.0301, 0.0348, 0.046

Vamos a representar esos datos con cruces azules (pista: usar mew=2 , "marker edge width 2", para que las
cruces se vean mejor):

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 1/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [4]:

plt.plot(C_D, C_L, 'x', mew=2, label="Datos reales")


plt.xlabel("$C_D$")
plt.ylabel("$C_L$")
plt.legend()

Out[4]:

<matplotlib.legend.Legend at 0x18ebf00f278>

Vemos la forma clásica de la polar de un avión. Hallando el índice del máximo valor de CL
podemos descartar
los datos fuera de la región de entrada en pérdida, y para eso necesitamos la función np.argmax :

In [5]:

# Índice de C_L max


idx_stall = np.argmax(C_L)
idx_stall

Out[5]:

12

In [6]:

# C_L max
C_L[idx_stall]

Out[6]:

1.24

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 2/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [7]:

# Pintamos los datos dentro y fuera de rango


plt.plot(C_D[:idx_stall + 1], C_L[:idx_stall + 1], 'x', mew=2, label="Datos reales")
plt.plot(C_D[idx_stall + 1:], C_L[idx_stall + 1:], 'o', mfc='none', label="Fuera del modelo
plt.xlabel("$C_D$")
plt.ylabel("$C_L$")
plt.legend(loc=4)

Out[7]:

<matplotlib.legend.Legend at 0x18ebf00f978>

Hay dos cosas que nos pueden interesar:

Como solo tenemos puntos intermedios, no tenemos posibilidad de evaluar, por ejemplo, CL para unCD
que no esté en los datos. Si interpolamos la curva ya podemos hacerlo.
Sabemos que, fuera de la región de entrada en pérdida, la polar tiene forma parabólica. Si ajustamos la
curva podemos hallar el CD0 k
y el .

Interpolación polinómica de Lagrange


Para interpolar utilizaremos el paquete interpolate de SciPy:

In [8]:

from scipy.interpolate import lagrange

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 3/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [9]:

x_i = [0.0, 0.9, 1.8, 2.7, 3.6, 4.4, 5.3, 6.2, 7.1, 8.0]
y_i = [0.0, 0.8, 1.0, 0.5, -0.4, -1.0, -0.8, -0.1, 0.7, 1.0]
plt.plot(x_i, y_i, 'x', mew=2)

Out[9]:

[<matplotlib.lines.Line2D at 0x18ebf827e10>]

In [10]:

# Cálculo de lo polinomio interpolante


lag_pol = lagrange(x_i, y_i)
print(lag_pol)

9 8 7 6 5 4
-8.812e-05 x + 0.003069 x - 0.04453 x + 0.3494 x - 1.614 x + 4.502 x
3 2
- 7.378 x + 6.033 x - 0.9713 x

In [11]:

x = np.linspace(x_i[0], x_i[-1])
plt.plot(x, lag_pol(x))
plt.plot(x_i, y_i, 'x', mew=2)

Out[11]:

[<matplotlib.lines.Line2D at 0x18ebf0af438>]

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 4/11
9/4/2018 0001-SciPy-interpolacion-ajuste

Fenómeno de Runge

In [12]:

# preserve
def runge(x):
return 1 / (1 + x ** 2)

In [13]:

# Número de nodos
N = 11 # Nodos de interpolación

# Seleccionamos los nodos


xp = np.linspace(-5, 5, N) # -5, -4, -3, ..., 3, 4, 5
fp = runge(xp)

# Seleccionamos la x para interpolar


x = np.linspace(-5, 5, 200)

# Calculamos el pol interp de Lagrange


lag_pol = lagrange(xp, fp)

y = lag_pol(x)

# pintamos
plt.plot(x, y, label='interpolation')
plt.plot(xp, fp, 'o', label='samples')
plt.plot(x, runge(x), label='real')
plt.legend(loc='upper center')

Out[13]:

<matplotlib.legend.Legend at 0x18ec08c7630>

Interpolación con spline


Para interpolar utilizaremos el paquete interpolate de SciPy:

In [14]:

from scipy.interpolate import InterpolatedUnivariateSpline

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 5/11
9/4/2018 0001-SciPy-interpolacion-ajuste

Vamos a generar unos puntos de ejemplo para explicar cómo funciona. Para eso, vamos a usar simplemente la
función sinx
en un dominio con pocos puntos:

In [15]:

# preserve
x_i = [0.0, 0.9, 1.8, 2.7, 3.6, 4.4, 5.3, 6.2, 7.1, 8.0]
# y_i es aproximación a un decimal de sin(x_i)
y_i = [0.0, 0.8, 1.0, 0.5, -0.4, -1.0, -0.8, -0.1, 0.7, 1.0]
plt.plot(x_i, y_i, 'x', mew=2)

Out[15]:

[<matplotlib.lines.Line2D at 0x18ec092aa58>]

Para crear una función interpolante (f_interp)


utilizaremos el objeto InterpolatedUnivariateSpline del
paquete interpolate . A este objeto solo hay que pasarle los puntos de interpolación y el grado, y generará
un spline. Fíjate en el valor de k
In [16]:

f_interp = InterpolatedUnivariateSpline(x_i, y_i, k=1)


f_interp

Out[16]:

<scipy.interpolate.fitpack2.InterpolatedUnivariateSpline at 0x18ebf85c080>

¿Cómo obtengo los puntos desde aquí? El resultado que hemos obtenido es una función y admite como
x
argumento la . Evaluemos f_interp( π2 )
In [17]:

f_interp(np.pi / 2)

Out[17]:

array(0.94906585)

Vamos a representar esta función junto con los puntos de interpolación. Fíjate en que, ahora que tenemos una
función interpolante, podemos representarla en un dominio:

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 6/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [18]:

# Representación
x = np.linspace(0, 8)
y_interp = f_interp(x)

plt.plot(x_i, y_i, 'x', mew=2)


plt.plot(x, y_interp)

Out[18]:

[<matplotlib.lines.Line2D at 0x18ec095a3c8>]

Retrocede ahora y comprueba lo que pasa si cambias el grado del spline, por ejemplo k=3.

Ejercicio: Crear una función interpolante CD = f(CL )


usando splines de grado 2 y representarla. Utiliza solo
x y
los datos que resultan de haber eliminado la región de entrada en pérdida. y ten en cuenta que la y la para
este caso están cambiadas de sitio.

1. Crea un polinomio interpolante usando los valores que encajan en el modelo parabólico.
2. Crea un dominio de CL
entre C_L.min() y C_L.max() .
3. Halla los valores interpolados de CD
en ese dominio.
4. Representa la función y los puntos.

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 7/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [19]:

f_C_D = InterpolatedUnivariateSpline(C_L[:idx_stall + 1], C_D[:idx_stall + 1], k=2)

C_L_domain = np.linspace(C_L.min(), C_L.max())


C_D_interp = f_C_D(C_L_domain)

plt.plot(C_D_interp, C_L_domain)
plt.plot(C_D, C_L, 'x', mew=2)
plt.xlabel('$C_D$')
plt.ylabel('$C_L$')
plt.show()

Ajuste
El ajuste funciona de manera totalmente distinta: obtendremos una curva que no tiene por qué pasar por
ninguno de los puntos originales, pero que a cambio tendrá una expresión analítica simple.

In [20]:

from scipy.optimize import curve_fit

Vamos otra vez a generar unos datos para ver cómo funcionaría, del tipo:

y(x) = x2 − x + 1 + Ruido

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 8/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [21]:

# preserve
x_i = np.linspace(-2, 3, num=10)
y_i = x_i ** 2 - x_i + 1 + 0.5 * np.random.randn(10)
plt.plot(x_i, y_i, 'x', mew=2)

Out[21]:

[<matplotlib.lines.Line2D at 0x18ec0a61d68>]

Vamos a utilizar la función polynomial.polyfit , que recibe los puntos de interpolación y el grado del
polinomio. El resultado serán los coeficientes del mismo, en orden de potencias decrecientes.

In [22]:

def poldeg2(x, a, b, c):


return a * x**2 + b * x + c

In [23]:

val, cov = curve_fit(poldeg2, x_i, y_i)


a, b, c= val

print(a, b, c)

0.9802013135527935 -1.0797161677146634 1.021044863114686

¡Muy similares a lo que esperábamos!

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 9/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [24]:

x = np.linspace(-2, 3)

y_fit = poldeg2(x, a, b, c)

#grafica los puntos


plt.plot(x_i, y_i, 'x', mew=2,color='b')

#grafica la curva
plt.plot(x, y_fit, color='g')

Out[24]:

[<matplotlib.lines.Line2D at 0x18ec0a61470>]

Ejercicio

Si modelizamos la polar como:

CD = CD0 + kCL2
hallar los coeficientes CD0 y k.
In [25]:

def model(x, A, C):


return A*x**2 + C

In [26]:

#Dominio C_L
print(C_L)

[-0.91 -0.72 -0.48 -0.27 -0.06 0.16 0.31 0.47 0.6 0.82 1.02 1.2
1.24 1.15 1. 0.8 ]

In [27]:

popt, _ = curve_fit(model, C_L[:idx_stall+1], C_D[:idx_stall+1])

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 10/11
9/4/2018 0001-SciPy-interpolacion-ajuste

In [28]:

A, B = popt

In [29]:

x = np.linspace(-1.5, 1.5, 50)


y = model(x, A, B)

In [30]:

plt.plot(y, x)
plt.plot(C_D, C_L, 'x', mew=2, c='r')
plt.xlabel('$C_D$')
plt.ylabel('$C_L$')

Out[30]:

Text(0,0.5,'$C_L$')

Hemos aprendido:

Cómo realiar interpolaciones en funciones unidimensionales con distintio grado


Cómo ajustar un modelo con datos experimentales utilizando la función curve_fit

Juan Luis Cano, Mabel Delgado, Alejandro Sáez, Jesús Espinola

http://localhost:8888/notebooks/Desktop/Python/Notebooks/0001-SciPy-interpolacion-ajuste.ipynb 11/11

También podría gustarte