Regresión lineal segmentada en Arduino

Vamos a seguir viendo “trucos” para aprovechar la regresión lineal. La principal limitación de la regresión lineal es precisamente que es “lineal”. Ya hemos visto que se puede utilizar la regresión lineal para calcular otro tipo de regresiones. Ahora vamos a ver como aproximar formas mas complicadas.

Cualquier curva se puede aproximar usando segmentos de linea recta. A mayor número de segmentos mejor aproximación. Por ejemplo debajo podemos ver la aproximación a una curva con forma de campana.

Se puede consguir mejor resultado si cada segmento empieza en el mismo punto que termina el anterior, pero la imagen es más realista respecto al caso que vamos a ver: Usar la regresión lineal para calcular cada uno de esos segmentos de forma independiente.

La forma de trabajar es muy sencilla, dividimos el espacio en varias partes para cada una de las cuales calculamos una regresión lineal. Luego cuando queremos estimar un valor lo primero es ver a que segmento corresponde y usar esa regresión para calcular su valor.

Para elegir como dividir la regresión hay varias opciones:

  • Dividir en segmentos iguales, es la forma más sencilla y entendible. Tiene el problema de que te puedes encontrar huecos sin datos.
  • Dividir cuando haya datos suficientes para asegurarse la calidad del aprendizaje. Se toman segmentos de longitud variable, el unico requisito es que haya suficiente punto de aprendizaje en ese segmento para asegurarse de que hay datos, si no los hay se alarga el segmento hasta que los haya.
  • Se empieza con una solo regresión, luego se divide en dos y se compara el error cuadrático medio entre ambos, si es menor en la version de mas segmentos se repite la operación

Este último punto no muestra algo interesante. Si necesitas comparar que combinación de segmentos es la mejor opción se puede usar el error cuadrático medio. Aquí puedes ver como calcularlo.

Ejemplo

Vamos a usar la librería Regressino en concreto nos vamos a basar en uno de sus ejemplos.

Lo primero es incluir la librería correspondiente y declarar una regresión lineal para cada segmento que queremos crear (en este caso 3)

#include <LinearRegression.h>

LinearRegression lr1 = LinearRegression();
LinearRegression lr2 = LinearRegression();
LinearRegression lr3 = LinearRegression();

El primer segmento va de X = 1 a X = 10, el segundo de X = 11 a X = 20 y el tercero de X = 21 a X = 30.

    Serial.println("Start learn");
    //1-10
    lr1.learn(1,2);  
    lr1.learn(2,3);
    lr1.learn(3,4);
    lr1.learn(6,7);
    lr1.learn(8,9);

    //11-20
    lr2.learn(11,24);  
    lr2.learn(12,26);
    lr2.learn(13,28);
    lr2.learn(16,34);
    lr2.learn(18,38);

    //21-30
    lr3.learn(21,66);  
    lr3.learn(22,69);
    lr3.learn(23,72);
    lr3.learn(26,81);
    lr3.learn(28,87);
    Serial.println("End learn");

Para calcular la estimaciones hay que tener en cuenta esos límites para saber que regresión lineal usar:


    for(int i = 0; i < 31; i++){
      Serial.print("Result (");
      Serial.print(i);
      Serial.print("): ");
      if(i < 11){
        Serial.println(lr1.calculate(i));    
      } else if(i < 21){
        Serial.println(lr2.calculate(i));
      } else {
        Serial.println(lr3.calculate(i));
      }
    }

Como podemos ver es un proceso muy sencillo pero no todo son ventajas.

Problemas

  • Puede dar lugar discontinuidades y saltos bruscos en los puntos donde se produce un cambio de segmento
  • Una de las limitaciones es que para cada valor de X solo puede existir un valor Y. Las rectas calculadas en cada segmento no pueden solaparse en ningun punto.
  • Lo contrario si que puede producirse, que varios valores de X tengan el mismo valor de Y
  • Necesitas tener valores de muestra en todos los segmentos. Si divides los datos en cinco segmentos, te tienes que asegurar de que tienes muestras suficientes para que el algoritmo de regresión calcule una buena aproximación en cada uno de ellos.

Ideas para explorar

  • Hemos usado el algoritmo de regresión lineal para cada segmento, pero podria usarse algún otro de los que hemos visto, incluso distintos en cada segmento.
  • Si hay un hueco sin datos podemos estimar la ecuación del segmento Y = m*X + c usando el punto final de segmento anterior (X1, Y1) y el punto inicial del segmento siguiente (X2, Y2). Para ello m = (Y2-Y1)/(X2-X1) una vez calculada la m podemos calcular la c = Y1 – m*X1. No es una solución ideal y seguramente resulte en una mala aproximación
  • Otra opción pra calcularlo es realizar el aprendizaje con algunos de los puntos del final del segmento anterior y de algunos del inicio del segmento siguiente.
  • Esa misma idea se puede usar para tratar de mejorar el aprendizaje permitiendo que el inicio y final de cada segmento se solapen con los segmento anterior y siguiente.