Regresión Lineal. Qué es, para qué se utiliza y ejemplo práctico

En el blog ya hemos hablado de qué es Machine Learning, las métricas de clasificación más importantes e incluso un algoritmo, el KNN, pero en este post vamos a comentar el algoritmo más básico e intuitivo que existe: la regresión lineal. Explicaré qué es, cómo se utiliza y añadiré un ejemplo práctico en Python.

¿Qué es la Regresión Lineal?

La definición más básica de este algoritmo es intentar representar los puntos mediante una recta lineal (de ahí el nombre). Este algoritmo forma parte de los modelos supervisados, puesto que necesitamos datos etiquetados (la variable Y tiene que tener valores numéricos) para que el modelo aprenda a predecir.

Para calcular esta recta, lo que tendremos que hacer es multiplicar la variable independiente (la X) por un peso ( \beta{_j} , sumar una constante (\beta{_0} en la ecuación, también llamado Intercepto). Así de simple. Para los que os acordéis de las matemáticas del instituto, es la ecuación de una recta escrito con otros símbolos: y = mx + b .

Tipos de Regresión Lineal

Si os habéis fijado, antes he puesto \beta{_j} , la ‘j‘ indica a qué variable está asociado el peso. Es decir, podemos utilizar más de una variable para predecir, y ésta es la diferencia entre los dos tipos de regresión lineal que existen:

  1. Regresión lineal simple (o univariante): en este tipo de regresión utilizamos sólo una variable más el intercepto para predecir algo. Por ejemplo, predecir el peso de una persona a partir de su altura:
    Peso = \beta{_0} + \beta_1 * Altura
  2. Regresión lineal múltiple: utiliza más de una variable para hacer el ajuste de la recta. Por ejemplo, predecir el peso de una persona a partir de su altura, su edad, su sexo:
    Peso = \beta{_0} + \beta_1 * Altura + \beta_2 * Edad + \beta_3 * Sexo

Ya sabemos qué es la regresión lineal pero, ¿cómo hacemos que la recta se ajuste a nuestros datos que queremos predecir?

Como en (casi) todos los algoritmos de Machine Learning, el modelo de predicción necesita datos para aprender y optimizar los pesos de predicción (KNN es un ejemplo de algoritmo Lazy Learning), pero ¿cómo podemos ajustar estos pesos en este modelo? Hay varios métodos para calcularlos, pero en este post nos centraremos en el descenso de gradiente. Hay dos conceptos clave para entender este método:

  • Inicialización de los pesos
  • Función de Coste
  • Descenso de gradiente

Inicialización de los pesos

Muy bien, tenemos la función de la recta, pero ¿qué valores de pesos utilizamos para hacer nuestra predicción? Los pesos son los que van a determinar cómo de bien predice nuestra regresión lineal, así que son un factor clave. Pues bien, la solución a esto no podría ser más sencilla, vamos a dejar que el modelo aprenda por si sólo, vamos a poner pesos aleatorios como valor inicial y los optimizaremos con los datos que tenemos. Esta optimización es lo que viene justo ahora:

¿Qué es la función de coste?

La función de coste es el primer paso para averiguar los mejores valores para los pesos y el intercepto y así ajustar lo mejor posible la recta de predicción. El coste es el error que produce la predicción, y, por lo tanto, lo que queremos hacer es minimizarlo. Vamos, que lo que queremos es optimizar cuánto nos equivocamos al predecir. Hay muchas funciones de coste diferentes, que se adaptan a diferentes escenarios, pero para explicarlo voy a utilizar el Error Cuadrático Medio (MSE):

MSE = \frac{1}{2m} * \sum_{i=1}^{m} (y_i - \hat{y}_i)^2 


Donde y representa el valor verdadero de la variable a predecir e y representa el valor de nuestra predicción. Vamos a sustituir en la ecuación por la recta de la regresión para obtener nuestra función de coste J:

J(\beta_0 , \beta_1) = \frac{1}{2m} * \sum_{i=1}^{m} [y_i - (\beta_0 + \beta_1 * x_i)]^2

Es decir, es la media del cuadrado de los errores. Se divide por 2 para facilitar el descenso de gradiente como veremos ahora.

Descenso de gradiente

Algunos no lo recordaréis, pero para resolver los problemas de optimización es necesario derivar para encontrar el punto mínimo (o máximo) de la ecuación. Entonces, lo primero que tenemos que hacer es sacar la derivada de nuestra función de coste. Como ya sabréis, la derivada es la tangente de la curva, esta tangente nos dirá la dirección en la que tenemos que cambiar nuestros pesos para reducir el coste.

La actualización de los pesos va a ser un proceso iterativo que terminará o bien cuando encontremos el mínimo, o bien cuando se haya iterado el número límite de veces que se haya indicado. Cuánto cambiaremos el peso en cada iteración viene dado por el gradiente (derivada de la función) multiplicado por el learning rate <strong>\alpha</strong> (un hiperparámetro a optimizar en la validación).

{\beta_j}^{i+1} =  {\beta_j}^{i+1} - \alpha * \frac{\partial J}{\partial \beta_j}  J(\beta_0 , \beta_1)

En este curso de Google podréis experimentar con el descenso de gradiente y ver gráficamente cómo afecta tanto la iteración, como el learning rate.

Ejemplo práctico

Bien, ya que hemos visto qué es, cómo funciona, y los aspectos clave a entender de la regresión lineal, vamos a ver un ejemplo práctico en Python. Voy a utilizar el dataset de ejemplo que nos proporciona Google Colab. Con estos datos vamos a intentar predecir el valor mediano de las casas de una manzana.

Primero, instalamos las librerías que necesitamos para ejecutar el programa, y hacer unas visualizaciones que vendrán bien para entender el problema.

from sklearn import linear_model
import pandas as pd

Una vez importadas todas las librerías que vamos a necesitar, vamos a importar los datos (Google nos lo proporciona dividido en Train y Test, por lo que no necesitamos hacer el split), y vamos a realizar un tratamiento sencillo a los datos para que se puedan enchufar al modelo de regresión.

train = pd.read_csv("/content/sample_data/california_housing_train.csv")
test = pd.read_csv('/content/sample_data/california_housing_test.csv')
# Eliminamos los NA de los datos, que a sklearn no le gustan
train.dropna(inplace=True)
test.dropna(inplace=True)

Bien, ya tenemos los datos para poder hacer una predicción mediante una regresión lineal, pero vamos a ver un poco más a fondo los datos que tenemos:

train.describe()
Dataset utilizado para la Regresi?n Lineal

Bien, vemos que para cada manzana tenemos la geolocalización (longitud y latitud), la mediana de la antigüedad de las casas de la manzana, el número de habitaciones total, el número de dormitorios total de la manzana, población, ingreso mediano y el valor mediano de la casa.

¡Bien! Ya es hora de entrenar la regresión y ver los resultados que nos da:

X = train.drop(columns='median_house_value')
Y =  train['median_house_value']
lm = linear_model.LinearRegression()
lm.fit(X, Y)
print('El R^2 de nuestro modelo para los datos de entrenamiento es de', lm.score(X, Y))

El modelo nos devuelve un R^2 de 0.641 para los datos de entrenamiento, veamos para el test:

Xtest = test.drop(columns='median_house_value')
Ytest = test['median_house_value']
print('El R^2 de nuestro modelo para los datos de entrenamiento es de', lm.score(Xtest, Ytest))

Para el test, el modelo nos devuelve un \ R^2 de 0.619, vemos que no empeora mucho para la muestra de test, por lo que esto nos indica que nuestro modelo no tiene problemas de varianza.

Os dejo un enlace a un post en el que Luis os habla de la regresión logística y cómo aplicar regularización para evitar el overfitting.