me ocurrió una solución bastante elegante (en mi humilde opinión), por lo que no puede resistirse 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])
I mapa para float
de manera que la división entera (pitón < = 2,7) no entrará en funcionamiento y arruinar las cosas si x1
, x2
, y1
y y2
son enteros para algunos iterval.
En __getitem__
estoy tomando ventaja del hecho de que self.x_list se ordena en orden ascendente utilizando bisect_left
a (muy) encontrar rápidamente el índice del elemento más grande más pequeño que x
en self.x_list
.
Uso de 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]
yo no he tratado con las condiciones de borde a todos aquí, por razones de simplicidad. Tal como está, i[x]
para x < 1
funcionará como si la línea desde (2.5, 4) a (1, 2) se hubiera extendido hasta menos el infinito, mientras que i[x]
para x == 1
o x > 6
levantará un IndexError
. Sería mejor plantear un IndexError en todos los casos, pero esto se deja como un ejercicio para el lector.:)
Esto es ... no es fácil. ¿Qué has intentado? – zellio
-1 como demasiado general. usted no entiende cómo programar, o cómo hacer el algoritmo en Python? – steabert
Bueno, siendo un nuevo aprendiz, me he lanzado a lo más profundo, por así decirlo. Estaba pensando en usar sentencias 'for' o 'if' en un algoritmo. Entonces entre numerosos rangos de x. – Helpless