signal interpolate extrapolate cubicos code python linear interpolation

python - interpolate - ¿Cómo implementar la interpolación lineal?



signal interpolation python (5)

Soy bastante nuevo en programación y pensé que intentaría escribir una función de interpolación lineal.

Digamos que me dan los datos de la siguiente manera:

x = [1, 2.5, 3.4, 5.8, 6] y = [2, 4, 5.8, 4.3, 4]

Quiero diseñar una función que interpolará linealmente entre 1 y 2.5, 2.5 a 3.4, y así sucesivamente usando Python.

He intentado mirar el Tutorial de Python , pero todavía no puedo entenderlo.


En lugar de extrapolar los extremos, puede devolver las extensiones de la y_list . La mayor parte del tiempo su aplicación se comporta bien, y el Interpolate[x] estará en la lista x_list . Los efectos (presumiblemente) lineales de la extrapolación de los extremos pueden inducirle a error a creer que sus datos se comportan bien.

  • Al x_list un resultado no lineal (limitado por el contenido de x_list y y_list ), el comportamiento de su programa puede alertarlo sobre un problema para los valores que se encuentran fuera de x_list . (El comportamiento lineal se vuelve banano cuando se le dan entradas no lineales)

  • Devolver las extensiones de la y_list para Interpolate[x] fuera de x_list también significa que conoce el rango de su valor de salida. Si extrapola en función de x mucho, mucho menos que x_list[0] o x mucho, mucho más que x_list[-1] , su resultado de retorno podría estar fuera del rango de valores que esperaba.

    def __getitem__(self, x): if x <= self.x_list[0]: return self.y_list[0] elif x >= self.x_list[-1]: return self.y_list[-1] else: i = bisect_left(self.x_list, x) - 1 return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])


Pensé en una solución bastante elegante (IMHO), así que no puedo resistirme a publicarla:

from bisect import bisect_left class Interpolate(object): def __init__(self, x_list, y_list): if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])): raise ValueError("x_list must be in strictly ascending order!") x_list = self.x_list = map(float, x_list) y_list = self.y_list = map(float, y_list) intervals = zip(x_list, x_list[1:], y_list, y_list[1:]) self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals] def __getitem__(self, x): i = bisect_left(self.x_list, x) - 1 return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])

Asigno a float para que la división de enteros (python <= 2.7) no se active y arruine las cosas si x1 , x2 , y1 e y2 son enteros para algunos iterval.

En __getitem__ estoy aprovechando el hecho de que self.x_list se ordena en orden ascendente utilizando bisect_left para encontrar (muy) rápidamente el índice del elemento más grande más pequeño que x en self.x_list .

Usa la clase como esta:

i = Interpolate([1, 2.5, 3.4, 5.8, 6], [2, 4, 5.8, 4.3, 4]) # Get the interpolated value at x = 4: y = i[4]

No he tratado con las condiciones de la frontera en absoluto aquí, por simplicidad. Tal como está, i[x] para x < 1 funcionará como si la línea de (2.5, 4) a (1, 2) se hubiera extendido a menos infinito, mientras que i[x] para x == 1 o x > 6 levantará un IndexError . Mejor sería levantar un IndexError en todos los casos, pero esto se deja como un ejercicio para el lector. :)


Según entiendo su pregunta, desea escribir alguna función y = interpolate(x_values, y_values, x) , que le dará el valor y en alguna x ? La idea básica sigue estos pasos:

  1. Encuentre los índices de los valores en x_values valores que definen un intervalo que contiene x . Por ejemplo, para x=3 con sus listas de ejemplo, el intervalo que contiene sería [x1,x2]=[2.5,3.4] , y los índices serían i1=1 , i2=2
  2. Calcule la pendiente en este intervalo mediante (y_values[i2]-y_values[i1])/(x_values[i2]-x_values[i1]) (es decir, dy/dx ).
  3. El valor en x es ahora el valor en x1 más la pendiente multiplicada por la distancia desde x1 .

Además, deberá decidir qué sucede si x está fuera del intervalo de x_values , ya sea un error, o podría interpolar "hacia atrás", asumiendo que la pendiente es la misma que la del primer / último intervalo.

¿Te ayudó esto o necesitaste un consejo más específico?


Su solución no funcionó en Python 2.7. Hubo un error al verificar el orden de los elementos x. Tuve que cambiar el código a este para que funcione:

from bisect import bisect_left class Interpolate(object): def __init__(self, x_list, y_list): if any([y - x <= 0 for x, y in zip(x_list, x_list[1:])]): raise ValueError("x_list must be in strictly ascending order!") x_list = self.x_list = map(float, x_list) y_list = self.y_list = map(float, y_list) intervals = zip(x_list, x_list[1:], y_list, y_list[1:]) self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals] def __getitem__(self, x): i = bisect_left(self.x_list, x) - 1 return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])


import scipy.interpolate y_interp = scipy.interpolate.interp1d(x, y) print y_interp(5.0)

scipy.interpolate.interp1d realiza interpolación lineal y puede personalizarse para manejar las condiciones de error.