Ya hemos visto varias formas de extender las capacidades de la regresión lineal en Arduino. En este caso vamos a asociar pesos a los valores para que no todos los casos aporten los mismo al resultado final. Pero qué significa «aportar» más al resultado, de forma gráfica podríamos imaginarnos que los puntos de mayor peso atraen más a la recta de la regresión lineal por lo que esta tiende a acercarse más a estos. La utilidad de este sistema es cuando tenemos resultados que por algún motivo valoramos más que otros.
Vamos a modelar el peso como un valor entre 0 y 1. De tal forma que el peso máximo corresponda con 1 y el mínimo con 0. A mayor peso más «aporta» ese valor al resultado. Entre dos valores uno con peso 1 y otro con peso 0.5 el primer cuenta el doble que el segundo. Cuando el peso es 1 no hay diferencia con la regresión lineal sin pesos. Y cuando el peso es cero el valor no va a aportar nada al resultado.
Partimos de la función de regresión lineal que ya vimos en otro post:
void LinearRegression::learn(double x, double y){
n++;
meanX = meanX + ((x-meanX)/n);
meanX2 = meanX2 + (((x*x)-meanX2)/n);
varX = meanX2 - (meanX*meanX);
meanY = meanY + ((y-meanY)/n);
meanY2 = meanY2 + (((y*y)-meanY2)/n);
varY = meanY2 - (meanY*meanY);
meanXY = meanXY + (((x*y)-meanXY)/n);
covarXY = meanXY - (meanX*meanY);
m = covarXY / varX;
b = meanY-(m*meanX);
}
Como ya hemos visto en otro post vamos a usar «el truco» que consiste en transformar el valor de x e y que se le pasa a la función que calcula la regresión lineal (learn). Podríamos verlo como que el valor de x se usan para modificar el valor de meanX y meanX2 y el de y para meanY y meanY2. Entonces si w es el peso:
- Si el peso es 1 x e y no cambian su valor
- Si es 0 x e y no tienen que afectar a los valores de meanX y meanY para que pase eso el valor de x ha de ser igual que meanX y el de y igual a meanY.
- Si el peso este entre 0 y 1 el valor ha de componerse con el valor de x e y y el valor de las medias de cada uno.
Para conseguir eso vamos a ponderar el valor de la x y el de meanX según w
x = x*w + meanX*(1-w);
y = y*w + meanY*(1-w);
Solo queda añadir un par de comprobaciones para evitar que el valor pueda ser mayor de 1 o menor de 0:
void LinearRegression::learn(double x, double y, double w){
if(w >= 1) {
learn(double x, double y);
} else if(w <= 0) {
return;
}
x = x*w + meanX*(1-w);
y = y*w + meanY*(1-w);
learn(double x, double y);
}
Todo esto se puede ver en la librería Regressino.
Por último comentar que hay dos posible optimizaciones que se podrían aplicar si fuera necesario y que nos permiten ahorrar algunos cálculos si hay muchos pesos cercanos a 0 o a 1:
- Los pesos muy cercanos a 0 se ignoran
- Los pesos muy cercanos a 1 se tratan como si no tuvieran peso
Hay una pequeña pérdida de precisión pero en el caso de tener muchos datos puede compensar al reducir el tiempo de cálculo.
Pingback: Regresión lineal con incertidumbre en Arduino | Construyendo a Chispas