Algoritmo de regresión lineal para predecir el precio de viviendas en el estado de California, EE.UU.

Richard Rosario Sánchez
LatinXinAI
Published in
9 min readNov 28, 2023

Objetivos:

1. Descargar el conjunto de datos y prepararlo para su entrenamiento.
2. Entrenar el modelo de regresión lineal para predecir el precio de las casas de California.

El conjunto de datos contiene información de las casas del estado de california, EEUU. Se encuentra en kaggle: https://www.kaggle.com/datasets/camnugent/california-housing-prices

Paso 1. Importamos las librerías:

  • numpy: para realizar cálculos matemáticos sobre matrices.
  • pandas: para la manipulación y el análisis de datos.
  • seaborn: para crear gráficos estadísticos.
  • train_test_split: para separar los datos en train y test.
  • LinearRegression: para el algoritmo de regresión lineal.
  • mean_squared_error: para medir el error cuadrado promedio de las predicciones.
  • StandardScaler: para estandarizar los datos.
  • from google.colab import drive: para montar Google Drive dentro del cuaderno en Google Colab.
import numpy as np
import pandas as pd
import seaborn as sb
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import StandardScaler
from google.colab import drive

Paso 2. Cargamos los datos:

  • El conjunto de datos se encuentra en formato .csv
  • Descargamos el conjunto de datos “housing.csv” para cargarlo en nuestro google drive personal.
  • Nos conectamos a google drive.
  • Llamamos a la dirección del conjunto de datos convirtiéndolo en un dataframe con el nombre de “datos”.
drive.mount('/content/drive')
datos = pd.read_csv("/content/drive/MyDrive/GitHub Projects/house_prices/housing.csv")

Paso 3. Conociendo los datos:

Para comenzar a conocer los datos podemos utilizar dos métodos que nos ayudaran a obtener un vistazo rápido del conjunto de datos, se utilizan los comandos:

  • dataframe.shape indica el número de filas y columnas.
  • dataframe.info indica el número de filas, columnas, el nombre de las columnas, cuenta el número de nulos, muestra de tipo de dato de cada columna y su cantidad.
datos.shape
datos.info()
  • Observamos que la característica total_bedrooms presenta 207 registros con el valor null, es por ello que en los siguientes pasos lo eliminaremos quedando todas las columnas con el mismo número de registros.

Paso 4. Identificar los tipos de datos:

Exploramos los tipos de datos de cada columna. Así mismo, identificaremos si hay alguna columna que según su significado no coincida con su tipo de dato:

  • La función dtypes genera una tabla con el tipo de dato de cada columna:
datos.dtypes
  • Podemos observar que la columna ocean_proximity es de tipo object, para un mejor análisis lo transformaremos de tipo int64 en el Paso 8.

Paso 5. Calcular las estadísticas:

dataframe.describe: para visualizar las estadísticas del conjunto de datos. Por defecto, la función describe trabaja con columnas numéricas y no con columnas de tipo object, mostrando los siguientes datos:

  • El número de elementos de la variable
  • La media
  • La desviación estándar (std)
  • El valor mínimo
  • Los cuartiles
  • El valor máximo
datos.describe()

Ahora visualizamos a las variables categóricas: agregándole include=['object'] podremos observar solo las columnas que son categóricas (de tipo object):

datos.describe(include=['object'])
  • unique: conocer los valores únicos, como podemos ver en la columna ocean_proximity hay 5 valores diferentes.
  • top: para conocer el valor que más se repite, el cual es <1H OCEAN.
  • freq: la frecuencia en que se repide el valor <1H OCEAN.

Paso 6. Exploración y visualización de los datos:

  • Utilizando tecnicas de visualización se puede comenzar a comprender el contexto alrededor de los datos.
  • Graficamos cada característica del conjunto de datos:
datos.hist(figsize=(15,8), bins=30, edgecolor="black")

Realizamos una nueva gráfica con ayuda de la latitud y longitud determinando que las casas con mayor precio se encuentran cerca al mar. Así mismo, el tamaño de los círculos depende de la población.

sb.scatterplot(x="latitude", y="longitude", data=datos, hue="median_house_value",
palette="coolwarm", s=datos["population"]/100)

Paso 7. Limpieza de datos:

  • Resolvemos el problema de datos faltantes, observemos qué variables tienen datos faltantes:
print(datos.isnull().sum())
  • Eliminamos los datos faltantes de la columna total_bedrooms:
datos_na = datos.dropna()
datos_na.info()

Paso 8. Convertimos la característica categórica a numérica (ocean_proximity):

  • Usando el método dummies se creará una pequeña tabla:

<1H OCEAN INLAND ISLAND NEAR BAY NEAR OCEAN
1 0 0 0 0
0 0 1 0 0
0 1 0 0 0
0 0 0 1 0
0 0 0 0 1
  • Asignamos la columna específica del que queremos obtener dummies:
dummies = pd.get_dummies(datos_na["ocean_proximity"], dtype=int)
  • Unimos los dummies al conjunto datos_na:
datos_na = datos_na.join(dummies)
  • Eliminamos la columna ocean_proximity:
datos_na = datos_na.drop(["ocean_proximity"], axis=1)
datos_na.head()

Paso 9. Análisis de correlación:

La correlación de Pearson es una medida estadística que evalúa la relación lineal entre dos variables continuas.

sb.set(rc={'figure.figsize': (15,8)})
sb.heatmap(datos_na.corr(), annot=True, cmap="YlGnBu")

En esta gráfica observamos la relación existente entre todos los atributos del conjunto de datos, el cual sus valores van desde -1 hasta 1, donde:

  • 1 indica una correlación positiva perfecta, lo que significa que a medida que una variable aumenta, la otra también lo hace en proporción constante.
  • -1 indica una correlación negativa perfecta, lo que significa que a medida que una variable aumenta, la otra disminuye en proporción constante.
  • 0 indica una ausencia de relación lineal entre las variables
  • Analizando la etiqueta median_house_value, observamos que su relación con la etiqueta median_income es de 0.69 indicando que mientras más ingresos tengan los habitantes de un bloque de casas, mayor es su precio de las casas donde viven. De esta manera se pueden analizar todas las demás etiquetas que se relacionan con median_house_value.

Paso 10. Análisis de correlación con la característica median_house_value:

datos_na.corr()["median_house_value"].sort_values(ascending=False)

Con ello determinamos qué características tienen mayor relación con el precio, observamos que las características que influyen en el costo de las casas son: median_income, <1H OCEAN, NEAR BAY, NEAR OCEAN, total_rooms, housing_median_age.

Con esto concluimos el análisis de datos, teniendo preparados los datos y listos para continuar con el segundo objetivo: Entrenar el modelo de regresión lineal, con ello podemos predecir el precio de las casas de California.

Paso 11. Entrenar el modelo de regresión lineal:

  • Continuamos con el desarrollo del proyecto utilizando el algoritmo de regresión lineal.
  • Usando seaborn realizamos una gráfica con ayuda de los datos de median_house_value (eje x) y median_income (eje y).
sb.scatterplot(x=datos_na["median_house_value"], y=datos_na["median_income"])
  • En esta gráfica observamos que existe una relación, ya que a mayor promedio de ingresos mayor es el costo de las casas.

Si queremos saber la proporción de cuantos cuartos de todos los cuartos son cuartos para dormir creamos una nueva característica: bedroom_ratio.

datos_na["bedroom_ratio"] = datos_na["total_bedrooms"] / datos_na["total_rooms"]
sb.set(rc={'figure.figsize': (15,8)})
sb.heatmap(datos_na.corr(), annot=True, cmap="YlGnBu")

En la gráfica observamos que la nueva característica bedroom_ratio tiene una relación de -0.26 con median_house_value, entonces si hay menos habitaciones para dormir más cuesta la casa.

Paso 12. Separar las características de la etiqueta:

  • X = datos para entrenar el modelo y predecir.
  • y = datos de respuesta.
X = datos_na.drop(["median_house_value"], axis=1)
y = datos_na["median_house_value"]

Paso 13. Separar los datos en 2 partes:

  1. Conjunto de entrenamiento (X_ent, y_ent).
  2. Conjunto de pruebas. (X_pru, y_pru)
  • train_test_split: devuelve 4 valores.
  • test_size = .2: indicamos que el 20% de datos es para pruebas.
X_ent, X_pru, y_ent, y_pru = train_test_split(X, y, test_size=.2)

Si queremos conocer la forma de cada variable (número de registros y número de columnas) podemos ingresar lo siguiente:

X_ent.shape tiene 16346 registros con 14 columnas.

y_ent.shape tiene 16346 registros con 1 columna.

X_pru.shape tiene 4087 registros con 14 columnas.

y_pru.shape tiene 4087 registros con 1 columna.

Paso 14. Creamos el modelo de regresión lineal:

modelo = LinearRegression()

Paso 15. Entrenamos el modelo:

  • Entrenamos el modelo con el conjunto de datos de entrenamiento (X_ent, y_ent):
modelo.fit(X_ent, y_ent)

Paso 16. Realizamos las predicciones:

  • Realizamos las predicciones con el conjunto de datos de pruebas.
  • modelo.predict(X_pru)realiza las predicciones de acuerdo al modelo entrenado.
  • Luego de realizar las predicciones lo comparamos con los resultados reales de pruebas (y_pru).
predicciones = modelo.predict(X_pru)

Paso 17. Comparamos lo que se predijo con los valores reales:

comparativa = {"Prediccion": predicciones, "Valor Real": y_pru}
pd.DataFrame(comparativa)
  • Podemos observar que algunas predicciones se acercan a los precios reales de las casas, sin embargo, otras no tanto. Esto puede llevarnos a la idea que el modelo esté pasando por overfitting.

Comprobamos si el modelo está pasando por un overfitting (sobreajuste):

print(modelo.score(X_ent, y_ent))
print(modelo.score(X_pru, y_pru))

Paso 18. Calcular el error:

  • Comparamos las etiquetas reales con las predicciones.
  • mean_squared_error: obtiene la diferencia entre predicciones y y_pru (datos reales) y lo eleva al cuadrado (para que los negativos sean positivos y los datos que tienen mayor error aumenten mucho más a diferencia de los que tienen poco error).
mse = mean_squared_error(y_pru, predicciones)
  • mse: es un número muy grande porque está elevado al cuadrado:
mse
  • Por ello sacamos su raíz cuadrada:
rmse = np.sqrt(mse)
  • Promedio de cuanto estamos fallando al calcular el precio de todas las casas:
rmse

Paso 19. Transformación de datos:

  • Si mostramos el conjunto de datos no normalizados, observamos que sus valores son muy distantes.
X_ent
  • Es por ello que se recomienda normalizar el conjunto de datos para un mejor entrenamiento.

19.1. Normalización:

  • La normalización o escalamiento es necesario para poner todas las variables numéricas en la misma escala y así el modelo no le de más importancia a los números grandes.
  • Las técnicas basadas en distancias siempre necesitan normalización.
  • Se recomienda escalar los datos de entrenamiento y de prueba, pero solo a los de características mas no los de salida.
scaler = StandardScaler()

X_ent_esc = scaler.fit_transform(X_ent)
X_pru_esc = scaler.fit_transform(X_pru)
pd.DataFrame(X_ent_esc)
  • Observamos que los datos ahora son números pequeños positivos y negativos, ya no son números con grandes distancias entre sí.

Conclusión:

✅ Se desarrolló los pasos de preparación de datos sobre el conjunto de datos de housing, pasando por los diferentes pasos como lo son: recopilación del conjunto de datos, entendimiento y visualización, análisis de calidad, limpieza y transformación del conjunto de datos, entrenamiento del modelo de regresión lineal, predicción y comparación de sus resultados con los datos reales.

✅ De esta manera se espera realizar nuevamente el entrenamiento con el nuevo conjunto de datos normalizados, obteniendo posibles mejores predicciones, cercanos a los precios reales de las casas de California. 🏡

✅ Este proyecto se llevó a cabo gracias a los conocimientos impartidos de Rodrigo Montemayor en su curso de Introducción a la IA con Python.

✅ Muchas gracias por tomarte el tiempo en leer y practicar. Si tienes alguna pregunta, no dudes en hacerlo. ¡Espero que te haya sido útil! 🙌🏼 🚀

Richard Rosario Sánchez

🔗¡Conectémonos!

➡️ LinkedIn | GitHub

LatinX in AI (LXAI) logo

Do you identify as Latinx and are working in artificial intelligence or know someone who is Latinx and is working in artificial intelligence?

Don’t forget to hit the 👏 below to help support our community — it means a lot!

--

--