Método de interpolación que no añade extremidades innecesarias.

Esta pregunta es la mitad de la progtwigción, pero también la mitad de las matemáticas. Quiero interpolar un conjunto de puntos por una curva sin agregar extremidades innecesarias que permanezcan “cerca de la interpolación lineal” mientras mantengo una curva que parece suave. Sé que esta formulación es vaga, pero espero que comience más clara con un ejemplo. Veamos el siguiente fragmento de código y el resultado:

#! /usr/bin/python import numpy as np from scipy.interpolate import interp1d import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(1,1,1) ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') ax.spines['bottom'].set_position('zero') ax.spines['top'].set_color('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') list_points=[(-3,0.1),(-2,0.15),(0,4),(2,-6),(4,-2),(7,-0.15),(8,-0.1)] (xp,yp)=zip(*list_points) fun=interp1d(xp,yp,kind='cubic') xc=np.linspace(min(xp),max(xp),300) plt.plot(xp,yp,'o',color='black',ms=5) plt.plot(xc,fun(xc)) fun2=interp1d(xp,yp,kind='linear') plt.plot(xc,fun2(xc)) plt.show() 

Interpolación

Hubiera esperado un interpolante que tuviera solo dos extremos (alrededor de x ~ 0 y x ~ 2) mientras que aquí tenemos 5 extremos. Es lo que la mayoría de la gente dibujará si les pedimos que unan los puntos con una curva suave a mano. ¿Hay una manera de lograr este objective (en python).

Actualización: Tenga en cuenta que xfig tiene algo cercano (llamado “dibujo de spline aproximado”) con los inconvenientes de que la curva no pasa exactamente por los puntos especificados. Preferiría una curva que pase exactamente a través de los puntos especificados, pero agradecería el método xfig si nadie conoce una solución mejor.

Si bien no es exactamente la misma (?), Su pregunta es similar a esta , por lo que quizás la misma respuesta sería útil. Puedes probar un interpolador monotónico. Se puede usar la clase PchipInterpolator (a la que puede hacer referencia por su nombre más corto pchip ) en scipy.interpolate . Aquí hay una versión de su script con una curva creada usando pchip incluido:

 import numpy as np from scipy.interpolate import interp1d, pchip import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(1,1,1) ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') ax.spines['bottom'].set_position('zero') ax.spines['top'].set_color('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') list_points = [(-3,0.1),(-2,0.15),(0,4),(2,-6),(4,-2),(7,-0.15),(8,-0.1)] (xp,yp) = zip(*list_points) fun = interp1d(xp,yp,kind='cubic') xc = np.linspace(min(xp),max(xp),300) plt.plot(xp,yp,'o',color='black',ms=5) plt.plot(xc,fun(xc)) fun2 = interp1d(xp,yp,kind='linear') plt.plot(xc,fun2(xc)) p = pchip(xp, yp) plt.plot(xc, p(xc), 'r', linewidth=3, alpha=0.6) plt.show() 

La ttwig que genera se muestra a continuación.

  • Puntos negros: datos originales
  • Líneas verdes: interpolación lineal.
  • Líneas azules: interpolación spline cúbica
  • Líneas rojas: interpolación pchip.

trama

¿Has probado un spline cuadrático en su lugar, aunque no estoy convencido de que eso ayude? Otra opción de fudge es agregar puntos de datos adicionales muy cerca de tus máximos. por ejemplo, en (-0.05,4) y (1.95, -6) – esto causaría que el algoritmo de spline cúbico aplane esas áreas cerca del máximo. Depende de lo que estés tratando de lograr. Existen técnicas para restringir el máximo y el mínimo de splines cúbicos, pero no estoy lo suficientemente familiarizado con esas o python / matplotlib para ayudar, lo siento.

Puede usar la interpolación lineal y luego filtrarla (con un filtro de media):

 size = 51.0; fun = interpolate.interp1d(xp, yp,kind='linear'); filt = (1/size)*np.ones(size); yc = signal.convolve( fun(xc),filt,'same'); 

Con el size del parámetro puede controlar el grado de suavizado.

introduzca la descripción de la imagen aquí

Este es el código integrado:

 import numpy as np from scipy.interpolate import interp1d import matplotlib.pyplot as plt from scipy import interpolate,signal fig = plt.figure() ax = fig.add_subplot(1,1,1) ax.spines['left'].set_position('zero') ax.spines['right'].set_color('none') ax.spines['bottom'].set_position('zero') ax.spines['top'].set_color('none') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') list_points=[(-3,0.1),(-2,0.15),(0,4),(2,-6),(4,-2),(7,-0.15),(8,-0.1)] (xp,yp)=zip(*list_points) xc=np.linspace(min(xp),max(xp),300) ######################################################## size = 41.0;#Put here any odd number fun = interpolate.interp1d(xp, yp,kind='linear'); filt = (1/size)*np.ones(size); yc = signal.convolve(fun(xc),filt,'same'); ######################################################## plt.plot(xp,yp,'o',color='black',ms=5) plt.plot(xc,yc) plt.plot(xc,fun(xc)) plt.show()