Saltar al contenido

¿Cómo aplicar el ajuste lineal por partes en Python?

Si encuentras alguna parte que no entiendes puedes dejarlo en los comentarios y te responderemos tan rápido como podamos.

Puedes usar numpy.piecewise() para crear la función por partes y luego usar curve_fit(), Aquí está el código

from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])

def piecewise_linear(x, x0, y0, k1, k2):
    return np.piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])

p , e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(0, 15, 100)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))

La salida:

ingrese la descripción de la imagen aquí

Para un ajuste de N piezas, consulte segments_fit.ipynb

Podría hacer un esquema de interpolación spline para realizar una interpolación lineal por partes y encontrar el punto de inflexión de la curva. La segunda derivada será la más alta en el punto de inflexión (para una curva monótonamente creciente) y se puede calcular con una interpolación spline de orden > 2.

import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15])
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])

tck = interpolate.splrep(x, y, k=2, s=0)
xnew = np.linspace(0, 15)

fig, axes = plt.subplots(3)

axes[0].plot(x, y, 'x', label = 'data')
axes[0].plot(xnew, interpolate.splev(xnew, tck, der=0), label = 'Fit')
axes[1].plot(x, interpolate.splev(x, tck, der=1), label = '1st dev')
dev_2 = interpolate.splev(x, tck, der=2)
axes[2].plot(x, dev_2, label = '2st dev')

turning_point_mask = dev_2 == np.amax(dev_2)
axes[2].plot(x[turning_point_mask], dev_2[turning_point_mask],'rx',
             label = 'Turning point')
for ax in axes:
    ax.legend(loc = 'best')

plt.show()

Punto de inflexión e interpolación lineal por partes

Puede usar pwlf para realizar una regresión lineal continua por partes en Python. Esta biblioteca se puede instalar usando pip.

Hay dos enfoques en pwlf para realizar su ajuste:

  1. Puede ajustarse a un número específico de segmentos de línea.
  2. Puede especificar las ubicaciones x donde deben terminar las líneas continuas por tramos.

Vayamos con el enfoque 1, ya que es más fácil y reconocerá el "punto de cambio de gradiente" que le interesa.

Noto dos regiones distintas cuando miro los datos. Por lo tanto, tiene sentido encontrar la mejor línea continua posible por tramos utilizando dos segmentos de línea. Este es el enfoque 1.

import numpy as np
import matplotlib.pyplot as plt
import pwlf

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59,
              84.47, 98.36, 112.25, 126.14, 140.03])

my_pwlf = pwlf.PiecewiseLinFit(x, y)
breaks = my_pwlf.fit(2)
print(breaks)

[ 1. 5.99819559 15. ]

El primer segmento de línea va desde [1., 5.99819559], mientras que el segundo segmento de línea va desde [5.99819559, 15.]. Por lo tanto, el punto de cambio de gradiente que solicitó sería 5.99819559.

Podemos graficar estos resultados usando la función de predicción.

x_hat = np.linspace(x.min(), x.max(), 100)
y_hat = my_pwlf.predict(x_hat)

plt.figure()
plt.plot(x, y, 'o')
plt.plot(x_hat, y_hat, '-')
plt.show()

El ajuste resultante

Sección de Reseñas y Valoraciones

Nos encantaría que puedieras dar visibilidad a esta sección si si solucionó tu problema.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags :

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *