Menu iconMenu icon
Fundamentos de Ingeniería de Datos

Proyecto 1: Predicción del Precio de la Casa con Ingeniería de Características

2. Ingeniería de Características para la Predicción de Precios de Viviendas

Ahora que hemos limpiado el conjunto de datos y realizado una exploración inicial, es momento de sumergirnos en el proceso crucial de ingeniería de características. Este paso es donde el arte y la ciencia de la ciencia de datos realmente brillan, ya que transformamos datos crudos en características que representan de manera más precisa los patrones y relaciones subyacentes en nuestro problema de predicción de precios de viviendas.

La ingeniería de características no se trata solo de manipular datos; se trata de descubrir conocimientos ocultos y crear un conjunto de datos más rico y informativo para que nuestro modelo aprenda. Al elaborar cuidadosamente nuevas características y refinar las existentes, podemos mejorar significativamente la capacidad de nuestro modelo para captar relaciones complejas y matices en el mercado de viviendas que de otro modo pasarían desapercibidos.

En el ámbito de la predicción de precios de viviendas, la ingeniería de características puede involucrar una amplia gama de técnicas. Por ejemplo, podríamos crear características compuestas que combinen múltiples atributos, como un "índice de lujo" que considere acabados de alta calidad, singularidad arquitectónica y electrodomésticos de primera categoría. También podríamos desarrollar características que capturen tendencias del mercado incorporando datos históricos de precios e indicadores económicos locales, permitiendo a nuestro modelo comprender mejor la naturaleza dinámica de la valoración de bienes raíces.

En esta sección, exploraremos varias técnicas clave de ingeniería de características que son particularmente relevantes para nuestra tarea de predicción de precios de viviendas:

  • Creación de nuevas características: Derivaremos información significativa a partir de puntos de datos existentes, como calcular la edad de una casa a partir de su año de construcción o determinar el precio por pie cuadrado.
  • Codificación de variables categóricas: Transformaremos datos no numéricos, como nombres de vecindarios o tipos de propiedades, en un formato que nuestros algoritmos de machine learning puedan procesar eficazmente.
  • Transformación de características numéricas: Aplicaremos operaciones matemáticas a nuestros datos numéricos para captar mejor sus relaciones con los precios de las viviendas, como usar escalado logarítmico para características muy sesgadas como el tamaño del lote o el precio de venta.

Al dominar estas técnicas, podremos crear un conjunto de características que no solo represente las características obvias de una propiedad, sino que también capture dinámicas de mercado sutiles, tendencias de vecindario y otros factores que influyen en los precios de las viviendas. Este conjunto de características mejorado servirá como la base para construir un modelo predictivo altamente preciso y robusto.

2.1 Creación de Nuevas Características

La creación de nuevas características es un aspecto crucial de la ingeniería de características que implica derivar información significativa a partir de puntos de datos existentes. En el contexto de bienes raíces, este proceso es particularmente valioso, ya que nos permite captar factores complejos que influyen en los precios de las viviendas, más allá de las características evidentes como el metraje cuadrado y el número de habitaciones. Al sintetizar nuevas características, podemos proporcionar a nuestros modelos predictivos entradas más matizadas e informativas, permitiéndoles comprender mejor las complejidades de la valoración de propiedades.

Por ejemplo, podríamos crear características que reflejen la calidad de la ubicación de la propiedad combinando datos sobre comodidades cercanas, tasas de criminalidad y calificaciones de distritos escolares. Otro ejemplo podría ser un "índice de lujo" que considere acabados de alta gama, singularidad arquitectónica y electrodomésticos premium. También podríamos desarrollar características que capturen tendencias de mercado incorporando datos históricos de precios e indicadores económicos locales. Estas características elaboradas nos permiten encapsular conocimientos del dominio y dinámicas de mercado sutiles que pueden no ser evidentes en los datos crudos.

Además, la creación de características puede ayudar a abordar relaciones no lineales entre variables. Por ejemplo, el impacto de la edad de una propiedad en su precio podría no ser lineal: las casas muy antiguas podrían ser valiosas debido a su importancia histórica, mientras que las casas moderadamente antiguas podrían ser menos deseables. Al crear características que capturen estas relaciones matizadas, permitimos que nuestros modelos aprendan patrones de precios más precisos y sofisticados.

Ejemplo: Edad de la Casa

Una característica útil a crear es la edad de la casa, que se puede derivar de la columna YearBuilt. Generalmente, las casas más nuevas tienden a tener precios más altos debido a materiales mejores y diseños modernos.

Ejemplo de Código: Creación de la Característica Edad de la Casa

import pandas as pd

# Assuming the dataset has a YearBuilt column and the current year is 2024
df['HouseAge'] = 2024 - df['YearBuilt']

# View the first few rows to see the new feature
print(df[['YearBuilt', 'HouseAge']].head())

Este código crea una nueva característica llamada 'HouseAge' calculando la diferencia entre el año actual (asumido como 2024) y el año en que se construyó la casa. A continuación, se desglosa lo que hace el código:

  • Primero, importa la biblioteca pandas, que se utiliza comúnmente para la manipulación de datos en Python.
  • Asume que el conjunto de datos (representado por 'df') ya tiene una columna llamada 'YearBuilt' que contiene el año en que se construyó cada casa.
  • El código crea una nueva columna 'HouseAge' restando el valor de 'YearBuilt' de 2024 (el año actual asumido). Este cálculo da la edad de cada casa en años.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto la columna 'YearBuilt' como la nueva columna 'HouseAge'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque la edad de una casa puede ser un factor significativo en la determinación de su precio. Las casas más nuevas suelen tener precios más altos debido a diseños y materiales modernos, mientras que las casas muy antiguas podrían ser valiosas por razones históricas.

Al calcular la edad de la casa, añadimos una característica que puede ayudar al modelo a comprender cómo el paso del tiempo afecta los precios de las viviendas.

Ejemplo: Tamaño del Lote por Dormitorio

Otra característica que podemos crear es el Tamaño del Lote por Dormitorio, que representa la cantidad de terreno asociada con cada dormitorio. Esta característica puede ofrecer información sobre cómo la distribución del espacio en una propiedad afecta su valor.

Ejemplo de Código: Creación de la Característica Tamaño del Lote por Dormitorio

# Assuming the dataset has LotSize and Bedrooms columns
df['LotSizePerBedroom'] = df['LotSize'] / df['Bedrooms']

# View the first few rows to see the new feature
print(df[['LotSize', 'Bedrooms', 'LotSizePerBedroom']].head())

En este ejemplo, calculamos el tamaño del lote por dormitorio, lo cual puede proporcionar al modelo información más detallada sobre la distribución del espacio en la casa.

Este código crea una nueva característica llamada 'LotSizePerBedroom' dividiendo el 'LotSize' por el número de 'Bedrooms' para cada casa en el conjunto de datos. A continuación, se desglosa lo que hace el código:

  • Asume que el conjunto de datos (representado por 'df') ya tiene columnas llamadas 'LotSize' y 'Bedrooms'.
  • Crea una nueva columna 'LotSizePerBedroom' dividiendo el valor de 'LotSize' entre el valor de 'Bedrooms' para cada fila en el dataframe.
  • Finalmente, imprime las primeras filas del dataframe, mostrando las columnas 'LotSize', 'Bedrooms' y la recién creada 'LotSizePerBedroom'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque proporciona información sobre cómo la distribución del espacio en una propiedad afecta su valor. El tamaño del lote por dormitorio puede ser un factor importante en la determinación del precio de una casa, ya que representa la cantidad de terreno asociada a cada dormitorio. Esta nueva característica proporciona al modelo información más detallada sobre la distribución del espacio en la casa, lo que puede ayudar a mejorar la precisión predictiva en los precios de las viviendas.

2.2 Codificación de Variables Categóricas

En el ámbito del aprendizaje automático para la predicción de precios de viviendas, a menudo nos encontramos con variables categóricas, es decir, características que tienen un conjunto finito de valores posibles. Ejemplos incluyen Ubicación (Código Postal)Tipo de Edificio o Estilo Arquitectónico. Estas variables presentan un desafío particular, ya que la mayoría de los algoritmos de aprendizaje automático están diseñados para trabajar con datos numéricos. Por lo tanto, necesitamos transformar estas características categóricas en un formato numérico que nuestros modelos puedan procesar eficazmente.

Este proceso de transformación se conoce como codificación y es un paso crucial en la preparación de nuestros datos para el análisis. Existen varios métodos de codificación disponibles, cada uno con sus propias ventajas y casos de uso ideales. Dos de las técnicas más comúnmente utilizadas son one-hot encoding y label encoding.

One-Hot Encoding es un método particularmente adecuado para variables categóricas sin un orden o jerarquía inherente. Esta técnica crea nuevas columnas binarias para cada categoría única dentro de una característica. Por ejemplo, si estamos trabajando con la característica Barrio, el one-hot encoding crearía columnas separadas para cada barrio en nuestro conjunto de datos. Una casa ubicada en un barrio específico tendría un '1' en la columna correspondiente y '0' en todas las demás columnas de barrios.

Este enfoque es especialmente valioso al trabajar con características como Código Postal o Estilo Arquitectónico, donde no existe un orden jerárquico entre categorías. El one-hot encoding permite que nuestro modelo trate cada categoría de manera independiente, lo cual puede ser crucial para capturar los efectos particulares de diferentes barrios o estilos en los precios de las viviendas.

Sin embargo, es importante tener en cuenta que el one-hot encoding puede aumentar significativamente la dimensionalidad de nuestro conjunto de datos, especialmente cuando se trata de categorías con muchos valores únicos. Esto puede llevar al "problema de la dimensionalidad" y puede requerir técnicas adicionales de selección de características para gestionar eficazmente el número aumentado de características.

Ejemplo de Código: One-Hot Encoding

# One-hot encode the 'Neighborhood' column
df_encoded = pd.get_dummies(df, columns=['Neighborhood'])

# View the first few rows of the encoded dataframe
print(df_encoded.head())

En este ejemplo:

La función get_dummies() crea nuevas columnas binarias para cada vecindario en el conjunto de datos. El modelo ahora puede usar esta información para diferenciar entre casas en distintos vecindarios.

Este código muestra cómo realizar one-hot encoding en una variable categórica, específicamente en la columna 'Neighborhood' de un conjunto de datos. A continuación, se explica lo que hace el código:

  1. df_encoded = pd.get_dummies(df, columns=['Neighborhood'])
    Esta línea utiliza la función get_dummies() de pandas para crear columnas binarias para cada valor único en la columna 'Neighborhood'. Cada nueva columna representa un vecindario específico, y contendrá un 1 si una casa está en ese vecindario, y un 0 en caso contrario.
  2. print(df_encoded.head())
    Esta línea imprime las primeras filas del dataframe recién codificado, permitiéndote ver el resultado del one-hot encoding.

El one-hot encoding es particularmente útil para variables categóricas como 'Neighborhood', donde no hay un orden o jerarquía inherente entre las categorías. Esto permite que el modelo trate cada vecindario como una característica independiente, lo cual es crucial para capturar los efectos específicos de diferentes vecindarios en los precios de las viviendas.

Sin embargo, es importante notar que este método puede aumentar significativamente el número de columnas en tu conjunto de datos, especialmente si la variable categórica tiene muchos valores únicos. Esto podría llevar al "problema de la dimensionalidad" y requerir técnicas adicionales de selección de características para manejar el incremento en el número de características de manera efectiva.

Label Encoding

Otra opción es el label encoding, que convierte cada categoría en un entero único. Este método es particularmente útil cuando las categorías tienen un orden o jerarquía inherente. Por ejemplo, al trabajar con una característica como Condition (por ejemplo, pobre, promedio, buena, excelente), el label encoding puede capturar la naturaleza ordinal de los datos.

El label encoding asigna un entero único a cada categoría, preservando el orden relativo. Por ejemplo, 'pobre' podría codificarse como 1, 'promedio' como 2, 'buena' como 3 y 'excelente' como 4. Esta representación numérica permite que el modelo comprenda la progresión o jerarquía dentro de la característica.

Sin embargo, es importante notar que el label encoding debe usarse con cautela. Aunque funciona bien para datos ordinales, aplicarlo a categorías nominales (aquellas sin un orden natural) puede introducir relaciones no deseadas en los datos. Por ejemplo, codificar 'rojo', 'azul' y 'verde' como 1, 2 y 3 respectivamente podría llevar al modelo a suponer incorrectamente que 'verde' es más similar a 'azul' que a 'rojo'.

Al usar label encoding, es fundamental documentar el esquema de codificación y considerar su impacto en la interpretación del modelo. En algunos casos, una combinación de label encoding para características ordinales y one-hot encoding para características nominales puede proporcionar los mejores resultados.

Ejemplo de Código: Label Encoding

from sklearn.preprocessing import LabelEncoder

# Label encode the 'Condition' column
label_encoder = LabelEncoder()
df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])

# View the first few rows to see the encoded column
print(df[['Condition', 'ConditionEncoded']].head())

En este ejemplo:

Usamos LabelEncoder para convertir la columna Condition en valores numéricos. Este enfoque es adecuado porque las condiciones de las casas pueden ordenarse en términos de calidad, de pobre a excelente.

Desglose del código:

  • from sklearn.preprocessing import LabelEncoderEsta línea importa la clase LabelEncoder de scikit-learn, que se utiliza para convertir etiquetas categóricas en forma numérica.
  • label_encoder = LabelEncoder()Esto crea una instancia de la clase LabelEncoder.
  • df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])Esta línea aplica la codificación de etiquetas a la columna 'Condition'. El método fit_transform() aprende el esquema de codificación a partir de los datos y luego lo aplica, creando una nueva columna 'ConditionEncoded' con las etiquetas numéricas.
  • print(df[['Condition', 'ConditionEncoded']].head())Esto imprime las primeras filas tanto de la columna original 'Condition' como de la nueva columna 'ConditionEncoded', permitiéndote ver el resultado de la codificación.

Este enfoque es particularmente útil para variables categóricas ordinales como las condiciones de las casas, donde existe un orden natural (por ejemplo, pobre, promedio, bueno, excelente). La codificación preserva este orden en la representación numérica.

2.3 Transformación de Características Numéricas

La transformación de características numéricas es un paso crucial para preparar los datos para los modelos de machine learning, especialmente cuando se trata de distribuciones sesgadas. Este proceso puede mejorar significativamente la capacidad del modelo para detectar patrones y relaciones dentro de los datos. Dos técnicas de transformación ampliamente utilizadas son el escalado logarítmico y la normalización.

Transformación Logarítmica

La transformación logarítmica es particularmente efectiva para características que presentan un amplio rango de valores o están fuertemente sesgadas. En el contexto de la predicción de precios de casas, características como SalePrice y LotSize suelen mostrar esta característica. Al aplicar una función logarítmica a estas variables, podemos comprimir la escala de valores grandes mientras ampliamos la escala de valores más pequeños. Esto tiene varios beneficios:

  • Reducción del sesgo: Acerca la distribución a una distribución normal, lo cual es un supuesto de muchas técnicas estadísticas.
  • Mitigación del impacto de los valores atípicos: Los valores extremos se acercan al resto de los datos, reduciendo su influencia desproporcionada en el modelo.
  • Mejora de la linealidad: En algunos casos, puede ayudar a linearizar las relaciones entre variables, facilitando su captura por modelos lineales.

Por ejemplo, una casa con un precio de $1,000,000 y otra con un precio de $100,000 tendrían valores transformados logarítmicamente de aproximadamente 13.82 y 11.51 respectivamente, reduciendo la diferencia absoluta y manteniendo la relación relativa.

Sin embargo, es importante tener en cuenta que las transformaciones logarítmicas deben aplicarse con prudencia. Son más efectivas cuando los datos tienen un sesgo positivo y todos los valores son positivos. Además, interpretar los resultados de un modelo que usa características transformadas logarítmicamente requiere una consideración cuidadosa, ya que los efectos ya no están en la escala original.

Ejemplo de Código: Transformación Logarítmica

import numpy as np

# Apply a logarithmic transformation to SalePrice and LotSize
df['LogSalePrice'] = np.log(df['SalePrice'])
df['LogLotSize'] = np.log(df['LotSize'])

# View the first few rows to see the transformed features
print(df[['SalePrice', 'LogSalePrice', 'LotSize', 'LogLotSize']].head())

En este ejemplo:

Aplicamos np.log() a las columnas SalePrice y LotSize, transformándolas en un formato más cercano a una distribución normal. Esto puede ayudar al modelo a desempeñarse mejor al reducir la asimetría.

Este código muestra cómo aplicar una transformación logarítmica a características numéricas en un conjunto de datos, específicamente en las columnas 'SalePrice' y 'LotSize'. Aquí tienes un desglose de lo que hace el código:

  • Primero, importa la biblioteca numpy como 'np', la cual proporciona funciones matemáticas, incluida la función de logaritmo.
  • Luego, crea dos nuevas columnas en el dataframe:
    • 'LogSalePrice': Se crea aplicando el logaritmo natural (np.log()) a la columna 'SalePrice'.
    • 'LogLotSize': De manera similar, se crea aplicando el logaritmo natural a la columna 'LotSize'.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto las versiones originales como las transformadas con logaritmo de 'SalePrice' y 'LotSize'.

El propósito de esta transformación es reducir la asimetría en la distribución de los datos y potencialmente mejorar el rendimiento de los modelos de machine learning. La transformación logarítmica puede ser particularmente útil para características como precios de venta y tamaños de lote, que a menudo tienen rangos amplios y pueden estar sesgados positivamente.

Normalización

La normalización es una técnica crucial en la ingeniería de características que reescala los valores de las características numéricas a un rango estándar, típicamente entre 0 y 1. Este proceso es especialmente importante cuando se trabaja con características que tienen escalas o unidades de medida significativamente diferentes. Por ejemplo, en nuestro modelo de predicción de precios de casas, características como LotSize (que podría estar en miles de pies cuadrados) y Bedrooms (generalmente un número entero pequeño) existen en escalas muy diferentes.

La importancia de la normalización se hace evidente cuando consideramos cómo los algoritmos de machine learning procesan los datos. Muchos algoritmos, como los métodos basados en descenso de gradiente, son sensibles a la escala de las características de entrada. Cuando las características están en diferentes escalas, aquellas con magnitudes mayores pueden dominar el proceso de aprendizaje, lo que podría llevar a un rendimiento del modelo sesgado o subóptimo. Al normalizar todas las características a una escala común, aseguramos que cada característica contribuya proporcionalmente al proceso de aprendizaje del modelo.

Además, la normalización puede mejorar la velocidad de convergencia de los algoritmos de optimización utilizados en el entrenamiento de modelos de machine learning. Ayuda a crear un espacio de características más uniforme, lo que puede conducir a un entrenamiento del modelo más rápido y estable. Esto es particularmente beneficioso cuando se utilizan algoritmos como redes neuronales o máquinas de soporte vectorial.

En el contexto de nuestro modelo de predicción de precios de casas, normalizar características como LotSize y Bedrooms permite que el modelo las trate de manera equitativa, a pesar de sus diferencias inherentes en escala. Esto puede llevar a predicciones más precisas y a una mejor comprensión del impacto real de cada característica en los precios de las casas.

Ejemplo de Código: Normalización de Características Numéricas

from sklearn.preprocessing import MinMaxScaler

# Define the numerical columns to normalize
numerical_columns = ['LotSize', 'HouseAge', 'SalePrice']

# Initialize the MinMaxScaler
scaler = MinMaxScaler()

# Apply normalization
df[numerical_columns] = scaler.fit_transform(df[numerical_columns])

# View the first few rows of the normalized dataframe
print(df[numerical_columns].head())

En este ejemplo:

Usamos MinMaxScaler de Scikit-learn para normalizar las columnas numéricas seleccionadas. Esto asegura que todas las características numéricas estén en la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning.

Este código demuestra cómo normalizar características numéricas en un conjunto de datos usando MinMaxScaler de scikit-learn. Aquí tienes un desglose de lo que hace el código:

  1. Importa MinMaxScaler desde sklearn.preprocessing.
  2. Define una lista de columnas numéricas para normalizar: 'LotSize', 'HouseAge' y 'SalePrice'.
  3. Inicializa el MinMaxScaler.
  4. Aplica la normalización a las columnas seleccionadas usando fit_transform(). Esto escala los valores a un rango entre 0 y 1.
  5. Imprime las primeras filas del dataframe normalizado para ver los resultados.

El propósito de esta normalización es llevar todas las características numéricas a la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning, especialmente aquellos sensibles a la escala de las características de entrada. Esto es particularmente útil al trabajar con características que tienen escalas o unidades de medida significativamente diferentes, como el tamaño del lote y la antigüedad de la casa.

Características de Interacción

Las características de interacción se crean combinando dos o más características existentes para capturar relaciones complejas entre ellas que puedan influir significativamente en la variable objetivo. En el contexto de la predicción de precios de casas, estas interacciones pueden revelar patrones matizados que las características individuales podrían pasar por alto. Por ejemplo, la interacción entre Bedrooms y Bathrooms puede ser un importante predictor de los precios de las casas, ya que captura la utilidad del espacio habitable en general.

Esta interacción va más allá de considerar simplemente el número de habitaciones o baños por separado. Una casa con 3 dormitorios y 2 baños podría valorarse de manera diferente a una casa con 2 dormitorios y 3 baños, aunque el número total de habitaciones sea el mismo. La característica de interacción puede capturar esta diferencia sutil, proporcionando potencialmente al modelo información más precisa para la predicción del precio.

Además, las interacciones también pueden ser valiosas entre otras características. Por ejemplo, la interacción entre LotSize y Neighborhood podría revelar que los tamaños de lotes más grandes son más valiosos en ciertos vecindarios que en otros. De manera similar, una interacción entre HouseAge y Condition podría ayudar al modelo a comprender cómo varía el impacto de la antigüedad de una casa en su precio dependiendo de su condición general.

Ejemplo de Código: Creación de una Característica de Interacción

# Create an interaction feature between Bedrooms and Bathrooms
df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']

# View the first few rows to see the new feature
print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())

En este ejemplo:

Creamos una característica de interacción que multiplica el número de dormitorios y baños. Esta característica captura la idea de que la combinación de estas dos variables puede influir en el precio de la casa más que cualquiera de ellas por separado.

Esto es lo que hace cada línea:

  1. df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']Esta línea crea una nueva columna llamada 'BedroomBathroomInteraction' en el dataframe (df). Se calcula multiplicando los valores en la columna 'Bedrooms' con los valores correspondientes en la columna 'Bathrooms'.
  2. print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())Esta línea imprime las primeras filas del dataframe, mostrando solo las columnas 'Bedrooms', 'Bathrooms' y la nueva columna 'BedroomBathroomInteraction'. Esto te permite ver el resultado de la creación de la característica de interacción.

El propósito de esta característica de interacción es capturar el efecto combinado de dormitorios y baños en los precios de las casas. Esto puede ser más informativo que considerar estas características por separado, ya que refleja la utilidad del espacio habitable en general de la casa.

El Poder de la Ingeniería de Características

La ingeniería de características es uno de los aspectos más críticos para construir modelos de machine learning potentes. Al crear nuevas características, transformar las existentes y codificar variables categóricas de manera efectiva, puedes mejorar significativamente el rendimiento de tus modelos. Las características que hemos discutido aquí—como Edad de la CasaTamaño del Lote por DormitorioTransformaciones Logarítmicas y Características de Interacción—son solo algunos ejemplos de cómo puedes transformar datos brutos en entradas significativas para tu modelo.

2. Ingeniería de Características para la Predicción de Precios de Viviendas

Ahora que hemos limpiado el conjunto de datos y realizado una exploración inicial, es momento de sumergirnos en el proceso crucial de ingeniería de características. Este paso es donde el arte y la ciencia de la ciencia de datos realmente brillan, ya que transformamos datos crudos en características que representan de manera más precisa los patrones y relaciones subyacentes en nuestro problema de predicción de precios de viviendas.

La ingeniería de características no se trata solo de manipular datos; se trata de descubrir conocimientos ocultos y crear un conjunto de datos más rico y informativo para que nuestro modelo aprenda. Al elaborar cuidadosamente nuevas características y refinar las existentes, podemos mejorar significativamente la capacidad de nuestro modelo para captar relaciones complejas y matices en el mercado de viviendas que de otro modo pasarían desapercibidos.

En el ámbito de la predicción de precios de viviendas, la ingeniería de características puede involucrar una amplia gama de técnicas. Por ejemplo, podríamos crear características compuestas que combinen múltiples atributos, como un "índice de lujo" que considere acabados de alta calidad, singularidad arquitectónica y electrodomésticos de primera categoría. También podríamos desarrollar características que capturen tendencias del mercado incorporando datos históricos de precios e indicadores económicos locales, permitiendo a nuestro modelo comprender mejor la naturaleza dinámica de la valoración de bienes raíces.

En esta sección, exploraremos varias técnicas clave de ingeniería de características que son particularmente relevantes para nuestra tarea de predicción de precios de viviendas:

  • Creación de nuevas características: Derivaremos información significativa a partir de puntos de datos existentes, como calcular la edad de una casa a partir de su año de construcción o determinar el precio por pie cuadrado.
  • Codificación de variables categóricas: Transformaremos datos no numéricos, como nombres de vecindarios o tipos de propiedades, en un formato que nuestros algoritmos de machine learning puedan procesar eficazmente.
  • Transformación de características numéricas: Aplicaremos operaciones matemáticas a nuestros datos numéricos para captar mejor sus relaciones con los precios de las viviendas, como usar escalado logarítmico para características muy sesgadas como el tamaño del lote o el precio de venta.

Al dominar estas técnicas, podremos crear un conjunto de características que no solo represente las características obvias de una propiedad, sino que también capture dinámicas de mercado sutiles, tendencias de vecindario y otros factores que influyen en los precios de las viviendas. Este conjunto de características mejorado servirá como la base para construir un modelo predictivo altamente preciso y robusto.

2.1 Creación de Nuevas Características

La creación de nuevas características es un aspecto crucial de la ingeniería de características que implica derivar información significativa a partir de puntos de datos existentes. En el contexto de bienes raíces, este proceso es particularmente valioso, ya que nos permite captar factores complejos que influyen en los precios de las viviendas, más allá de las características evidentes como el metraje cuadrado y el número de habitaciones. Al sintetizar nuevas características, podemos proporcionar a nuestros modelos predictivos entradas más matizadas e informativas, permitiéndoles comprender mejor las complejidades de la valoración de propiedades.

Por ejemplo, podríamos crear características que reflejen la calidad de la ubicación de la propiedad combinando datos sobre comodidades cercanas, tasas de criminalidad y calificaciones de distritos escolares. Otro ejemplo podría ser un "índice de lujo" que considere acabados de alta gama, singularidad arquitectónica y electrodomésticos premium. También podríamos desarrollar características que capturen tendencias de mercado incorporando datos históricos de precios e indicadores económicos locales. Estas características elaboradas nos permiten encapsular conocimientos del dominio y dinámicas de mercado sutiles que pueden no ser evidentes en los datos crudos.

Además, la creación de características puede ayudar a abordar relaciones no lineales entre variables. Por ejemplo, el impacto de la edad de una propiedad en su precio podría no ser lineal: las casas muy antiguas podrían ser valiosas debido a su importancia histórica, mientras que las casas moderadamente antiguas podrían ser menos deseables. Al crear características que capturen estas relaciones matizadas, permitimos que nuestros modelos aprendan patrones de precios más precisos y sofisticados.

Ejemplo: Edad de la Casa

Una característica útil a crear es la edad de la casa, que se puede derivar de la columna YearBuilt. Generalmente, las casas más nuevas tienden a tener precios más altos debido a materiales mejores y diseños modernos.

Ejemplo de Código: Creación de la Característica Edad de la Casa

import pandas as pd

# Assuming the dataset has a YearBuilt column and the current year is 2024
df['HouseAge'] = 2024 - df['YearBuilt']

# View the first few rows to see the new feature
print(df[['YearBuilt', 'HouseAge']].head())

Este código crea una nueva característica llamada 'HouseAge' calculando la diferencia entre el año actual (asumido como 2024) y el año en que se construyó la casa. A continuación, se desglosa lo que hace el código:

  • Primero, importa la biblioteca pandas, que se utiliza comúnmente para la manipulación de datos en Python.
  • Asume que el conjunto de datos (representado por 'df') ya tiene una columna llamada 'YearBuilt' que contiene el año en que se construyó cada casa.
  • El código crea una nueva columna 'HouseAge' restando el valor de 'YearBuilt' de 2024 (el año actual asumido). Este cálculo da la edad de cada casa en años.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto la columna 'YearBuilt' como la nueva columna 'HouseAge'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque la edad de una casa puede ser un factor significativo en la determinación de su precio. Las casas más nuevas suelen tener precios más altos debido a diseños y materiales modernos, mientras que las casas muy antiguas podrían ser valiosas por razones históricas.

Al calcular la edad de la casa, añadimos una característica que puede ayudar al modelo a comprender cómo el paso del tiempo afecta los precios de las viviendas.

Ejemplo: Tamaño del Lote por Dormitorio

Otra característica que podemos crear es el Tamaño del Lote por Dormitorio, que representa la cantidad de terreno asociada con cada dormitorio. Esta característica puede ofrecer información sobre cómo la distribución del espacio en una propiedad afecta su valor.

Ejemplo de Código: Creación de la Característica Tamaño del Lote por Dormitorio

# Assuming the dataset has LotSize and Bedrooms columns
df['LotSizePerBedroom'] = df['LotSize'] / df['Bedrooms']

# View the first few rows to see the new feature
print(df[['LotSize', 'Bedrooms', 'LotSizePerBedroom']].head())

En este ejemplo, calculamos el tamaño del lote por dormitorio, lo cual puede proporcionar al modelo información más detallada sobre la distribución del espacio en la casa.

Este código crea una nueva característica llamada 'LotSizePerBedroom' dividiendo el 'LotSize' por el número de 'Bedrooms' para cada casa en el conjunto de datos. A continuación, se desglosa lo que hace el código:

  • Asume que el conjunto de datos (representado por 'df') ya tiene columnas llamadas 'LotSize' y 'Bedrooms'.
  • Crea una nueva columna 'LotSizePerBedroom' dividiendo el valor de 'LotSize' entre el valor de 'Bedrooms' para cada fila en el dataframe.
  • Finalmente, imprime las primeras filas del dataframe, mostrando las columnas 'LotSize', 'Bedrooms' y la recién creada 'LotSizePerBedroom'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque proporciona información sobre cómo la distribución del espacio en una propiedad afecta su valor. El tamaño del lote por dormitorio puede ser un factor importante en la determinación del precio de una casa, ya que representa la cantidad de terreno asociada a cada dormitorio. Esta nueva característica proporciona al modelo información más detallada sobre la distribución del espacio en la casa, lo que puede ayudar a mejorar la precisión predictiva en los precios de las viviendas.

2.2 Codificación de Variables Categóricas

En el ámbito del aprendizaje automático para la predicción de precios de viviendas, a menudo nos encontramos con variables categóricas, es decir, características que tienen un conjunto finito de valores posibles. Ejemplos incluyen Ubicación (Código Postal)Tipo de Edificio o Estilo Arquitectónico. Estas variables presentan un desafío particular, ya que la mayoría de los algoritmos de aprendizaje automático están diseñados para trabajar con datos numéricos. Por lo tanto, necesitamos transformar estas características categóricas en un formato numérico que nuestros modelos puedan procesar eficazmente.

Este proceso de transformación se conoce como codificación y es un paso crucial en la preparación de nuestros datos para el análisis. Existen varios métodos de codificación disponibles, cada uno con sus propias ventajas y casos de uso ideales. Dos de las técnicas más comúnmente utilizadas son one-hot encoding y label encoding.

One-Hot Encoding es un método particularmente adecuado para variables categóricas sin un orden o jerarquía inherente. Esta técnica crea nuevas columnas binarias para cada categoría única dentro de una característica. Por ejemplo, si estamos trabajando con la característica Barrio, el one-hot encoding crearía columnas separadas para cada barrio en nuestro conjunto de datos. Una casa ubicada en un barrio específico tendría un '1' en la columna correspondiente y '0' en todas las demás columnas de barrios.

Este enfoque es especialmente valioso al trabajar con características como Código Postal o Estilo Arquitectónico, donde no existe un orden jerárquico entre categorías. El one-hot encoding permite que nuestro modelo trate cada categoría de manera independiente, lo cual puede ser crucial para capturar los efectos particulares de diferentes barrios o estilos en los precios de las viviendas.

Sin embargo, es importante tener en cuenta que el one-hot encoding puede aumentar significativamente la dimensionalidad de nuestro conjunto de datos, especialmente cuando se trata de categorías con muchos valores únicos. Esto puede llevar al "problema de la dimensionalidad" y puede requerir técnicas adicionales de selección de características para gestionar eficazmente el número aumentado de características.

Ejemplo de Código: One-Hot Encoding

# One-hot encode the 'Neighborhood' column
df_encoded = pd.get_dummies(df, columns=['Neighborhood'])

# View the first few rows of the encoded dataframe
print(df_encoded.head())

En este ejemplo:

La función get_dummies() crea nuevas columnas binarias para cada vecindario en el conjunto de datos. El modelo ahora puede usar esta información para diferenciar entre casas en distintos vecindarios.

Este código muestra cómo realizar one-hot encoding en una variable categórica, específicamente en la columna 'Neighborhood' de un conjunto de datos. A continuación, se explica lo que hace el código:

  1. df_encoded = pd.get_dummies(df, columns=['Neighborhood'])
    Esta línea utiliza la función get_dummies() de pandas para crear columnas binarias para cada valor único en la columna 'Neighborhood'. Cada nueva columna representa un vecindario específico, y contendrá un 1 si una casa está en ese vecindario, y un 0 en caso contrario.
  2. print(df_encoded.head())
    Esta línea imprime las primeras filas del dataframe recién codificado, permitiéndote ver el resultado del one-hot encoding.

El one-hot encoding es particularmente útil para variables categóricas como 'Neighborhood', donde no hay un orden o jerarquía inherente entre las categorías. Esto permite que el modelo trate cada vecindario como una característica independiente, lo cual es crucial para capturar los efectos específicos de diferentes vecindarios en los precios de las viviendas.

Sin embargo, es importante notar que este método puede aumentar significativamente el número de columnas en tu conjunto de datos, especialmente si la variable categórica tiene muchos valores únicos. Esto podría llevar al "problema de la dimensionalidad" y requerir técnicas adicionales de selección de características para manejar el incremento en el número de características de manera efectiva.

Label Encoding

Otra opción es el label encoding, que convierte cada categoría en un entero único. Este método es particularmente útil cuando las categorías tienen un orden o jerarquía inherente. Por ejemplo, al trabajar con una característica como Condition (por ejemplo, pobre, promedio, buena, excelente), el label encoding puede capturar la naturaleza ordinal de los datos.

El label encoding asigna un entero único a cada categoría, preservando el orden relativo. Por ejemplo, 'pobre' podría codificarse como 1, 'promedio' como 2, 'buena' como 3 y 'excelente' como 4. Esta representación numérica permite que el modelo comprenda la progresión o jerarquía dentro de la característica.

Sin embargo, es importante notar que el label encoding debe usarse con cautela. Aunque funciona bien para datos ordinales, aplicarlo a categorías nominales (aquellas sin un orden natural) puede introducir relaciones no deseadas en los datos. Por ejemplo, codificar 'rojo', 'azul' y 'verde' como 1, 2 y 3 respectivamente podría llevar al modelo a suponer incorrectamente que 'verde' es más similar a 'azul' que a 'rojo'.

Al usar label encoding, es fundamental documentar el esquema de codificación y considerar su impacto en la interpretación del modelo. En algunos casos, una combinación de label encoding para características ordinales y one-hot encoding para características nominales puede proporcionar los mejores resultados.

Ejemplo de Código: Label Encoding

from sklearn.preprocessing import LabelEncoder

# Label encode the 'Condition' column
label_encoder = LabelEncoder()
df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])

# View the first few rows to see the encoded column
print(df[['Condition', 'ConditionEncoded']].head())

En este ejemplo:

Usamos LabelEncoder para convertir la columna Condition en valores numéricos. Este enfoque es adecuado porque las condiciones de las casas pueden ordenarse en términos de calidad, de pobre a excelente.

Desglose del código:

  • from sklearn.preprocessing import LabelEncoderEsta línea importa la clase LabelEncoder de scikit-learn, que se utiliza para convertir etiquetas categóricas en forma numérica.
  • label_encoder = LabelEncoder()Esto crea una instancia de la clase LabelEncoder.
  • df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])Esta línea aplica la codificación de etiquetas a la columna 'Condition'. El método fit_transform() aprende el esquema de codificación a partir de los datos y luego lo aplica, creando una nueva columna 'ConditionEncoded' con las etiquetas numéricas.
  • print(df[['Condition', 'ConditionEncoded']].head())Esto imprime las primeras filas tanto de la columna original 'Condition' como de la nueva columna 'ConditionEncoded', permitiéndote ver el resultado de la codificación.

Este enfoque es particularmente útil para variables categóricas ordinales como las condiciones de las casas, donde existe un orden natural (por ejemplo, pobre, promedio, bueno, excelente). La codificación preserva este orden en la representación numérica.

2.3 Transformación de Características Numéricas

La transformación de características numéricas es un paso crucial para preparar los datos para los modelos de machine learning, especialmente cuando se trata de distribuciones sesgadas. Este proceso puede mejorar significativamente la capacidad del modelo para detectar patrones y relaciones dentro de los datos. Dos técnicas de transformación ampliamente utilizadas son el escalado logarítmico y la normalización.

Transformación Logarítmica

La transformación logarítmica es particularmente efectiva para características que presentan un amplio rango de valores o están fuertemente sesgadas. En el contexto de la predicción de precios de casas, características como SalePrice y LotSize suelen mostrar esta característica. Al aplicar una función logarítmica a estas variables, podemos comprimir la escala de valores grandes mientras ampliamos la escala de valores más pequeños. Esto tiene varios beneficios:

  • Reducción del sesgo: Acerca la distribución a una distribución normal, lo cual es un supuesto de muchas técnicas estadísticas.
  • Mitigación del impacto de los valores atípicos: Los valores extremos se acercan al resto de los datos, reduciendo su influencia desproporcionada en el modelo.
  • Mejora de la linealidad: En algunos casos, puede ayudar a linearizar las relaciones entre variables, facilitando su captura por modelos lineales.

Por ejemplo, una casa con un precio de $1,000,000 y otra con un precio de $100,000 tendrían valores transformados logarítmicamente de aproximadamente 13.82 y 11.51 respectivamente, reduciendo la diferencia absoluta y manteniendo la relación relativa.

Sin embargo, es importante tener en cuenta que las transformaciones logarítmicas deben aplicarse con prudencia. Son más efectivas cuando los datos tienen un sesgo positivo y todos los valores son positivos. Además, interpretar los resultados de un modelo que usa características transformadas logarítmicamente requiere una consideración cuidadosa, ya que los efectos ya no están en la escala original.

Ejemplo de Código: Transformación Logarítmica

import numpy as np

# Apply a logarithmic transformation to SalePrice and LotSize
df['LogSalePrice'] = np.log(df['SalePrice'])
df['LogLotSize'] = np.log(df['LotSize'])

# View the first few rows to see the transformed features
print(df[['SalePrice', 'LogSalePrice', 'LotSize', 'LogLotSize']].head())

En este ejemplo:

Aplicamos np.log() a las columnas SalePrice y LotSize, transformándolas en un formato más cercano a una distribución normal. Esto puede ayudar al modelo a desempeñarse mejor al reducir la asimetría.

Este código muestra cómo aplicar una transformación logarítmica a características numéricas en un conjunto de datos, específicamente en las columnas 'SalePrice' y 'LotSize'. Aquí tienes un desglose de lo que hace el código:

  • Primero, importa la biblioteca numpy como 'np', la cual proporciona funciones matemáticas, incluida la función de logaritmo.
  • Luego, crea dos nuevas columnas en el dataframe:
    • 'LogSalePrice': Se crea aplicando el logaritmo natural (np.log()) a la columna 'SalePrice'.
    • 'LogLotSize': De manera similar, se crea aplicando el logaritmo natural a la columna 'LotSize'.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto las versiones originales como las transformadas con logaritmo de 'SalePrice' y 'LotSize'.

El propósito de esta transformación es reducir la asimetría en la distribución de los datos y potencialmente mejorar el rendimiento de los modelos de machine learning. La transformación logarítmica puede ser particularmente útil para características como precios de venta y tamaños de lote, que a menudo tienen rangos amplios y pueden estar sesgados positivamente.

Normalización

La normalización es una técnica crucial en la ingeniería de características que reescala los valores de las características numéricas a un rango estándar, típicamente entre 0 y 1. Este proceso es especialmente importante cuando se trabaja con características que tienen escalas o unidades de medida significativamente diferentes. Por ejemplo, en nuestro modelo de predicción de precios de casas, características como LotSize (que podría estar en miles de pies cuadrados) y Bedrooms (generalmente un número entero pequeño) existen en escalas muy diferentes.

La importancia de la normalización se hace evidente cuando consideramos cómo los algoritmos de machine learning procesan los datos. Muchos algoritmos, como los métodos basados en descenso de gradiente, son sensibles a la escala de las características de entrada. Cuando las características están en diferentes escalas, aquellas con magnitudes mayores pueden dominar el proceso de aprendizaje, lo que podría llevar a un rendimiento del modelo sesgado o subóptimo. Al normalizar todas las características a una escala común, aseguramos que cada característica contribuya proporcionalmente al proceso de aprendizaje del modelo.

Además, la normalización puede mejorar la velocidad de convergencia de los algoritmos de optimización utilizados en el entrenamiento de modelos de machine learning. Ayuda a crear un espacio de características más uniforme, lo que puede conducir a un entrenamiento del modelo más rápido y estable. Esto es particularmente beneficioso cuando se utilizan algoritmos como redes neuronales o máquinas de soporte vectorial.

En el contexto de nuestro modelo de predicción de precios de casas, normalizar características como LotSize y Bedrooms permite que el modelo las trate de manera equitativa, a pesar de sus diferencias inherentes en escala. Esto puede llevar a predicciones más precisas y a una mejor comprensión del impacto real de cada característica en los precios de las casas.

Ejemplo de Código: Normalización de Características Numéricas

from sklearn.preprocessing import MinMaxScaler

# Define the numerical columns to normalize
numerical_columns = ['LotSize', 'HouseAge', 'SalePrice']

# Initialize the MinMaxScaler
scaler = MinMaxScaler()

# Apply normalization
df[numerical_columns] = scaler.fit_transform(df[numerical_columns])

# View the first few rows of the normalized dataframe
print(df[numerical_columns].head())

En este ejemplo:

Usamos MinMaxScaler de Scikit-learn para normalizar las columnas numéricas seleccionadas. Esto asegura que todas las características numéricas estén en la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning.

Este código demuestra cómo normalizar características numéricas en un conjunto de datos usando MinMaxScaler de scikit-learn. Aquí tienes un desglose de lo que hace el código:

  1. Importa MinMaxScaler desde sklearn.preprocessing.
  2. Define una lista de columnas numéricas para normalizar: 'LotSize', 'HouseAge' y 'SalePrice'.
  3. Inicializa el MinMaxScaler.
  4. Aplica la normalización a las columnas seleccionadas usando fit_transform(). Esto escala los valores a un rango entre 0 y 1.
  5. Imprime las primeras filas del dataframe normalizado para ver los resultados.

El propósito de esta normalización es llevar todas las características numéricas a la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning, especialmente aquellos sensibles a la escala de las características de entrada. Esto es particularmente útil al trabajar con características que tienen escalas o unidades de medida significativamente diferentes, como el tamaño del lote y la antigüedad de la casa.

Características de Interacción

Las características de interacción se crean combinando dos o más características existentes para capturar relaciones complejas entre ellas que puedan influir significativamente en la variable objetivo. En el contexto de la predicción de precios de casas, estas interacciones pueden revelar patrones matizados que las características individuales podrían pasar por alto. Por ejemplo, la interacción entre Bedrooms y Bathrooms puede ser un importante predictor de los precios de las casas, ya que captura la utilidad del espacio habitable en general.

Esta interacción va más allá de considerar simplemente el número de habitaciones o baños por separado. Una casa con 3 dormitorios y 2 baños podría valorarse de manera diferente a una casa con 2 dormitorios y 3 baños, aunque el número total de habitaciones sea el mismo. La característica de interacción puede capturar esta diferencia sutil, proporcionando potencialmente al modelo información más precisa para la predicción del precio.

Además, las interacciones también pueden ser valiosas entre otras características. Por ejemplo, la interacción entre LotSize y Neighborhood podría revelar que los tamaños de lotes más grandes son más valiosos en ciertos vecindarios que en otros. De manera similar, una interacción entre HouseAge y Condition podría ayudar al modelo a comprender cómo varía el impacto de la antigüedad de una casa en su precio dependiendo de su condición general.

Ejemplo de Código: Creación de una Característica de Interacción

# Create an interaction feature between Bedrooms and Bathrooms
df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']

# View the first few rows to see the new feature
print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())

En este ejemplo:

Creamos una característica de interacción que multiplica el número de dormitorios y baños. Esta característica captura la idea de que la combinación de estas dos variables puede influir en el precio de la casa más que cualquiera de ellas por separado.

Esto es lo que hace cada línea:

  1. df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']Esta línea crea una nueva columna llamada 'BedroomBathroomInteraction' en el dataframe (df). Se calcula multiplicando los valores en la columna 'Bedrooms' con los valores correspondientes en la columna 'Bathrooms'.
  2. print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())Esta línea imprime las primeras filas del dataframe, mostrando solo las columnas 'Bedrooms', 'Bathrooms' y la nueva columna 'BedroomBathroomInteraction'. Esto te permite ver el resultado de la creación de la característica de interacción.

El propósito de esta característica de interacción es capturar el efecto combinado de dormitorios y baños en los precios de las casas. Esto puede ser más informativo que considerar estas características por separado, ya que refleja la utilidad del espacio habitable en general de la casa.

El Poder de la Ingeniería de Características

La ingeniería de características es uno de los aspectos más críticos para construir modelos de machine learning potentes. Al crear nuevas características, transformar las existentes y codificar variables categóricas de manera efectiva, puedes mejorar significativamente el rendimiento de tus modelos. Las características que hemos discutido aquí—como Edad de la CasaTamaño del Lote por DormitorioTransformaciones Logarítmicas y Características de Interacción—son solo algunos ejemplos de cómo puedes transformar datos brutos en entradas significativas para tu modelo.

2. Ingeniería de Características para la Predicción de Precios de Viviendas

Ahora que hemos limpiado el conjunto de datos y realizado una exploración inicial, es momento de sumergirnos en el proceso crucial de ingeniería de características. Este paso es donde el arte y la ciencia de la ciencia de datos realmente brillan, ya que transformamos datos crudos en características que representan de manera más precisa los patrones y relaciones subyacentes en nuestro problema de predicción de precios de viviendas.

La ingeniería de características no se trata solo de manipular datos; se trata de descubrir conocimientos ocultos y crear un conjunto de datos más rico y informativo para que nuestro modelo aprenda. Al elaborar cuidadosamente nuevas características y refinar las existentes, podemos mejorar significativamente la capacidad de nuestro modelo para captar relaciones complejas y matices en el mercado de viviendas que de otro modo pasarían desapercibidos.

En el ámbito de la predicción de precios de viviendas, la ingeniería de características puede involucrar una amplia gama de técnicas. Por ejemplo, podríamos crear características compuestas que combinen múltiples atributos, como un "índice de lujo" que considere acabados de alta calidad, singularidad arquitectónica y electrodomésticos de primera categoría. También podríamos desarrollar características que capturen tendencias del mercado incorporando datos históricos de precios e indicadores económicos locales, permitiendo a nuestro modelo comprender mejor la naturaleza dinámica de la valoración de bienes raíces.

En esta sección, exploraremos varias técnicas clave de ingeniería de características que son particularmente relevantes para nuestra tarea de predicción de precios de viviendas:

  • Creación de nuevas características: Derivaremos información significativa a partir de puntos de datos existentes, como calcular la edad de una casa a partir de su año de construcción o determinar el precio por pie cuadrado.
  • Codificación de variables categóricas: Transformaremos datos no numéricos, como nombres de vecindarios o tipos de propiedades, en un formato que nuestros algoritmos de machine learning puedan procesar eficazmente.
  • Transformación de características numéricas: Aplicaremos operaciones matemáticas a nuestros datos numéricos para captar mejor sus relaciones con los precios de las viviendas, como usar escalado logarítmico para características muy sesgadas como el tamaño del lote o el precio de venta.

Al dominar estas técnicas, podremos crear un conjunto de características que no solo represente las características obvias de una propiedad, sino que también capture dinámicas de mercado sutiles, tendencias de vecindario y otros factores que influyen en los precios de las viviendas. Este conjunto de características mejorado servirá como la base para construir un modelo predictivo altamente preciso y robusto.

2.1 Creación de Nuevas Características

La creación de nuevas características es un aspecto crucial de la ingeniería de características que implica derivar información significativa a partir de puntos de datos existentes. En el contexto de bienes raíces, este proceso es particularmente valioso, ya que nos permite captar factores complejos que influyen en los precios de las viviendas, más allá de las características evidentes como el metraje cuadrado y el número de habitaciones. Al sintetizar nuevas características, podemos proporcionar a nuestros modelos predictivos entradas más matizadas e informativas, permitiéndoles comprender mejor las complejidades de la valoración de propiedades.

Por ejemplo, podríamos crear características que reflejen la calidad de la ubicación de la propiedad combinando datos sobre comodidades cercanas, tasas de criminalidad y calificaciones de distritos escolares. Otro ejemplo podría ser un "índice de lujo" que considere acabados de alta gama, singularidad arquitectónica y electrodomésticos premium. También podríamos desarrollar características que capturen tendencias de mercado incorporando datos históricos de precios e indicadores económicos locales. Estas características elaboradas nos permiten encapsular conocimientos del dominio y dinámicas de mercado sutiles que pueden no ser evidentes en los datos crudos.

Además, la creación de características puede ayudar a abordar relaciones no lineales entre variables. Por ejemplo, el impacto de la edad de una propiedad en su precio podría no ser lineal: las casas muy antiguas podrían ser valiosas debido a su importancia histórica, mientras que las casas moderadamente antiguas podrían ser menos deseables. Al crear características que capturen estas relaciones matizadas, permitimos que nuestros modelos aprendan patrones de precios más precisos y sofisticados.

Ejemplo: Edad de la Casa

Una característica útil a crear es la edad de la casa, que se puede derivar de la columna YearBuilt. Generalmente, las casas más nuevas tienden a tener precios más altos debido a materiales mejores y diseños modernos.

Ejemplo de Código: Creación de la Característica Edad de la Casa

import pandas as pd

# Assuming the dataset has a YearBuilt column and the current year is 2024
df['HouseAge'] = 2024 - df['YearBuilt']

# View the first few rows to see the new feature
print(df[['YearBuilt', 'HouseAge']].head())

Este código crea una nueva característica llamada 'HouseAge' calculando la diferencia entre el año actual (asumido como 2024) y el año en que se construyó la casa. A continuación, se desglosa lo que hace el código:

  • Primero, importa la biblioteca pandas, que se utiliza comúnmente para la manipulación de datos en Python.
  • Asume que el conjunto de datos (representado por 'df') ya tiene una columna llamada 'YearBuilt' que contiene el año en que se construyó cada casa.
  • El código crea una nueva columna 'HouseAge' restando el valor de 'YearBuilt' de 2024 (el año actual asumido). Este cálculo da la edad de cada casa en años.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto la columna 'YearBuilt' como la nueva columna 'HouseAge'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque la edad de una casa puede ser un factor significativo en la determinación de su precio. Las casas más nuevas suelen tener precios más altos debido a diseños y materiales modernos, mientras que las casas muy antiguas podrían ser valiosas por razones históricas.

Al calcular la edad de la casa, añadimos una característica que puede ayudar al modelo a comprender cómo el paso del tiempo afecta los precios de las viviendas.

Ejemplo: Tamaño del Lote por Dormitorio

Otra característica que podemos crear es el Tamaño del Lote por Dormitorio, que representa la cantidad de terreno asociada con cada dormitorio. Esta característica puede ofrecer información sobre cómo la distribución del espacio en una propiedad afecta su valor.

Ejemplo de Código: Creación de la Característica Tamaño del Lote por Dormitorio

# Assuming the dataset has LotSize and Bedrooms columns
df['LotSizePerBedroom'] = df['LotSize'] / df['Bedrooms']

# View the first few rows to see the new feature
print(df[['LotSize', 'Bedrooms', 'LotSizePerBedroom']].head())

En este ejemplo, calculamos el tamaño del lote por dormitorio, lo cual puede proporcionar al modelo información más detallada sobre la distribución del espacio en la casa.

Este código crea una nueva característica llamada 'LotSizePerBedroom' dividiendo el 'LotSize' por el número de 'Bedrooms' para cada casa en el conjunto de datos. A continuación, se desglosa lo que hace el código:

  • Asume que el conjunto de datos (representado por 'df') ya tiene columnas llamadas 'LotSize' y 'Bedrooms'.
  • Crea una nueva columna 'LotSizePerBedroom' dividiendo el valor de 'LotSize' entre el valor de 'Bedrooms' para cada fila en el dataframe.
  • Finalmente, imprime las primeras filas del dataframe, mostrando las columnas 'LotSize', 'Bedrooms' y la recién creada 'LotSizePerBedroom'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque proporciona información sobre cómo la distribución del espacio en una propiedad afecta su valor. El tamaño del lote por dormitorio puede ser un factor importante en la determinación del precio de una casa, ya que representa la cantidad de terreno asociada a cada dormitorio. Esta nueva característica proporciona al modelo información más detallada sobre la distribución del espacio en la casa, lo que puede ayudar a mejorar la precisión predictiva en los precios de las viviendas.

2.2 Codificación de Variables Categóricas

En el ámbito del aprendizaje automático para la predicción de precios de viviendas, a menudo nos encontramos con variables categóricas, es decir, características que tienen un conjunto finito de valores posibles. Ejemplos incluyen Ubicación (Código Postal)Tipo de Edificio o Estilo Arquitectónico. Estas variables presentan un desafío particular, ya que la mayoría de los algoritmos de aprendizaje automático están diseñados para trabajar con datos numéricos. Por lo tanto, necesitamos transformar estas características categóricas en un formato numérico que nuestros modelos puedan procesar eficazmente.

Este proceso de transformación se conoce como codificación y es un paso crucial en la preparación de nuestros datos para el análisis. Existen varios métodos de codificación disponibles, cada uno con sus propias ventajas y casos de uso ideales. Dos de las técnicas más comúnmente utilizadas son one-hot encoding y label encoding.

One-Hot Encoding es un método particularmente adecuado para variables categóricas sin un orden o jerarquía inherente. Esta técnica crea nuevas columnas binarias para cada categoría única dentro de una característica. Por ejemplo, si estamos trabajando con la característica Barrio, el one-hot encoding crearía columnas separadas para cada barrio en nuestro conjunto de datos. Una casa ubicada en un barrio específico tendría un '1' en la columna correspondiente y '0' en todas las demás columnas de barrios.

Este enfoque es especialmente valioso al trabajar con características como Código Postal o Estilo Arquitectónico, donde no existe un orden jerárquico entre categorías. El one-hot encoding permite que nuestro modelo trate cada categoría de manera independiente, lo cual puede ser crucial para capturar los efectos particulares de diferentes barrios o estilos en los precios de las viviendas.

Sin embargo, es importante tener en cuenta que el one-hot encoding puede aumentar significativamente la dimensionalidad de nuestro conjunto de datos, especialmente cuando se trata de categorías con muchos valores únicos. Esto puede llevar al "problema de la dimensionalidad" y puede requerir técnicas adicionales de selección de características para gestionar eficazmente el número aumentado de características.

Ejemplo de Código: One-Hot Encoding

# One-hot encode the 'Neighborhood' column
df_encoded = pd.get_dummies(df, columns=['Neighborhood'])

# View the first few rows of the encoded dataframe
print(df_encoded.head())

En este ejemplo:

La función get_dummies() crea nuevas columnas binarias para cada vecindario en el conjunto de datos. El modelo ahora puede usar esta información para diferenciar entre casas en distintos vecindarios.

Este código muestra cómo realizar one-hot encoding en una variable categórica, específicamente en la columna 'Neighborhood' de un conjunto de datos. A continuación, se explica lo que hace el código:

  1. df_encoded = pd.get_dummies(df, columns=['Neighborhood'])
    Esta línea utiliza la función get_dummies() de pandas para crear columnas binarias para cada valor único en la columna 'Neighborhood'. Cada nueva columna representa un vecindario específico, y contendrá un 1 si una casa está en ese vecindario, y un 0 en caso contrario.
  2. print(df_encoded.head())
    Esta línea imprime las primeras filas del dataframe recién codificado, permitiéndote ver el resultado del one-hot encoding.

El one-hot encoding es particularmente útil para variables categóricas como 'Neighborhood', donde no hay un orden o jerarquía inherente entre las categorías. Esto permite que el modelo trate cada vecindario como una característica independiente, lo cual es crucial para capturar los efectos específicos de diferentes vecindarios en los precios de las viviendas.

Sin embargo, es importante notar que este método puede aumentar significativamente el número de columnas en tu conjunto de datos, especialmente si la variable categórica tiene muchos valores únicos. Esto podría llevar al "problema de la dimensionalidad" y requerir técnicas adicionales de selección de características para manejar el incremento en el número de características de manera efectiva.

Label Encoding

Otra opción es el label encoding, que convierte cada categoría en un entero único. Este método es particularmente útil cuando las categorías tienen un orden o jerarquía inherente. Por ejemplo, al trabajar con una característica como Condition (por ejemplo, pobre, promedio, buena, excelente), el label encoding puede capturar la naturaleza ordinal de los datos.

El label encoding asigna un entero único a cada categoría, preservando el orden relativo. Por ejemplo, 'pobre' podría codificarse como 1, 'promedio' como 2, 'buena' como 3 y 'excelente' como 4. Esta representación numérica permite que el modelo comprenda la progresión o jerarquía dentro de la característica.

Sin embargo, es importante notar que el label encoding debe usarse con cautela. Aunque funciona bien para datos ordinales, aplicarlo a categorías nominales (aquellas sin un orden natural) puede introducir relaciones no deseadas en los datos. Por ejemplo, codificar 'rojo', 'azul' y 'verde' como 1, 2 y 3 respectivamente podría llevar al modelo a suponer incorrectamente que 'verde' es más similar a 'azul' que a 'rojo'.

Al usar label encoding, es fundamental documentar el esquema de codificación y considerar su impacto en la interpretación del modelo. En algunos casos, una combinación de label encoding para características ordinales y one-hot encoding para características nominales puede proporcionar los mejores resultados.

Ejemplo de Código: Label Encoding

from sklearn.preprocessing import LabelEncoder

# Label encode the 'Condition' column
label_encoder = LabelEncoder()
df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])

# View the first few rows to see the encoded column
print(df[['Condition', 'ConditionEncoded']].head())

En este ejemplo:

Usamos LabelEncoder para convertir la columna Condition en valores numéricos. Este enfoque es adecuado porque las condiciones de las casas pueden ordenarse en términos de calidad, de pobre a excelente.

Desglose del código:

  • from sklearn.preprocessing import LabelEncoderEsta línea importa la clase LabelEncoder de scikit-learn, que se utiliza para convertir etiquetas categóricas en forma numérica.
  • label_encoder = LabelEncoder()Esto crea una instancia de la clase LabelEncoder.
  • df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])Esta línea aplica la codificación de etiquetas a la columna 'Condition'. El método fit_transform() aprende el esquema de codificación a partir de los datos y luego lo aplica, creando una nueva columna 'ConditionEncoded' con las etiquetas numéricas.
  • print(df[['Condition', 'ConditionEncoded']].head())Esto imprime las primeras filas tanto de la columna original 'Condition' como de la nueva columna 'ConditionEncoded', permitiéndote ver el resultado de la codificación.

Este enfoque es particularmente útil para variables categóricas ordinales como las condiciones de las casas, donde existe un orden natural (por ejemplo, pobre, promedio, bueno, excelente). La codificación preserva este orden en la representación numérica.

2.3 Transformación de Características Numéricas

La transformación de características numéricas es un paso crucial para preparar los datos para los modelos de machine learning, especialmente cuando se trata de distribuciones sesgadas. Este proceso puede mejorar significativamente la capacidad del modelo para detectar patrones y relaciones dentro de los datos. Dos técnicas de transformación ampliamente utilizadas son el escalado logarítmico y la normalización.

Transformación Logarítmica

La transformación logarítmica es particularmente efectiva para características que presentan un amplio rango de valores o están fuertemente sesgadas. En el contexto de la predicción de precios de casas, características como SalePrice y LotSize suelen mostrar esta característica. Al aplicar una función logarítmica a estas variables, podemos comprimir la escala de valores grandes mientras ampliamos la escala de valores más pequeños. Esto tiene varios beneficios:

  • Reducción del sesgo: Acerca la distribución a una distribución normal, lo cual es un supuesto de muchas técnicas estadísticas.
  • Mitigación del impacto de los valores atípicos: Los valores extremos se acercan al resto de los datos, reduciendo su influencia desproporcionada en el modelo.
  • Mejora de la linealidad: En algunos casos, puede ayudar a linearizar las relaciones entre variables, facilitando su captura por modelos lineales.

Por ejemplo, una casa con un precio de $1,000,000 y otra con un precio de $100,000 tendrían valores transformados logarítmicamente de aproximadamente 13.82 y 11.51 respectivamente, reduciendo la diferencia absoluta y manteniendo la relación relativa.

Sin embargo, es importante tener en cuenta que las transformaciones logarítmicas deben aplicarse con prudencia. Son más efectivas cuando los datos tienen un sesgo positivo y todos los valores son positivos. Además, interpretar los resultados de un modelo que usa características transformadas logarítmicamente requiere una consideración cuidadosa, ya que los efectos ya no están en la escala original.

Ejemplo de Código: Transformación Logarítmica

import numpy as np

# Apply a logarithmic transformation to SalePrice and LotSize
df['LogSalePrice'] = np.log(df['SalePrice'])
df['LogLotSize'] = np.log(df['LotSize'])

# View the first few rows to see the transformed features
print(df[['SalePrice', 'LogSalePrice', 'LotSize', 'LogLotSize']].head())

En este ejemplo:

Aplicamos np.log() a las columnas SalePrice y LotSize, transformándolas en un formato más cercano a una distribución normal. Esto puede ayudar al modelo a desempeñarse mejor al reducir la asimetría.

Este código muestra cómo aplicar una transformación logarítmica a características numéricas en un conjunto de datos, específicamente en las columnas 'SalePrice' y 'LotSize'. Aquí tienes un desglose de lo que hace el código:

  • Primero, importa la biblioteca numpy como 'np', la cual proporciona funciones matemáticas, incluida la función de logaritmo.
  • Luego, crea dos nuevas columnas en el dataframe:
    • 'LogSalePrice': Se crea aplicando el logaritmo natural (np.log()) a la columna 'SalePrice'.
    • 'LogLotSize': De manera similar, se crea aplicando el logaritmo natural a la columna 'LotSize'.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto las versiones originales como las transformadas con logaritmo de 'SalePrice' y 'LotSize'.

El propósito de esta transformación es reducir la asimetría en la distribución de los datos y potencialmente mejorar el rendimiento de los modelos de machine learning. La transformación logarítmica puede ser particularmente útil para características como precios de venta y tamaños de lote, que a menudo tienen rangos amplios y pueden estar sesgados positivamente.

Normalización

La normalización es una técnica crucial en la ingeniería de características que reescala los valores de las características numéricas a un rango estándar, típicamente entre 0 y 1. Este proceso es especialmente importante cuando se trabaja con características que tienen escalas o unidades de medida significativamente diferentes. Por ejemplo, en nuestro modelo de predicción de precios de casas, características como LotSize (que podría estar en miles de pies cuadrados) y Bedrooms (generalmente un número entero pequeño) existen en escalas muy diferentes.

La importancia de la normalización se hace evidente cuando consideramos cómo los algoritmos de machine learning procesan los datos. Muchos algoritmos, como los métodos basados en descenso de gradiente, son sensibles a la escala de las características de entrada. Cuando las características están en diferentes escalas, aquellas con magnitudes mayores pueden dominar el proceso de aprendizaje, lo que podría llevar a un rendimiento del modelo sesgado o subóptimo. Al normalizar todas las características a una escala común, aseguramos que cada característica contribuya proporcionalmente al proceso de aprendizaje del modelo.

Además, la normalización puede mejorar la velocidad de convergencia de los algoritmos de optimización utilizados en el entrenamiento de modelos de machine learning. Ayuda a crear un espacio de características más uniforme, lo que puede conducir a un entrenamiento del modelo más rápido y estable. Esto es particularmente beneficioso cuando se utilizan algoritmos como redes neuronales o máquinas de soporte vectorial.

En el contexto de nuestro modelo de predicción de precios de casas, normalizar características como LotSize y Bedrooms permite que el modelo las trate de manera equitativa, a pesar de sus diferencias inherentes en escala. Esto puede llevar a predicciones más precisas y a una mejor comprensión del impacto real de cada característica en los precios de las casas.

Ejemplo de Código: Normalización de Características Numéricas

from sklearn.preprocessing import MinMaxScaler

# Define the numerical columns to normalize
numerical_columns = ['LotSize', 'HouseAge', 'SalePrice']

# Initialize the MinMaxScaler
scaler = MinMaxScaler()

# Apply normalization
df[numerical_columns] = scaler.fit_transform(df[numerical_columns])

# View the first few rows of the normalized dataframe
print(df[numerical_columns].head())

En este ejemplo:

Usamos MinMaxScaler de Scikit-learn para normalizar las columnas numéricas seleccionadas. Esto asegura que todas las características numéricas estén en la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning.

Este código demuestra cómo normalizar características numéricas en un conjunto de datos usando MinMaxScaler de scikit-learn. Aquí tienes un desglose de lo que hace el código:

  1. Importa MinMaxScaler desde sklearn.preprocessing.
  2. Define una lista de columnas numéricas para normalizar: 'LotSize', 'HouseAge' y 'SalePrice'.
  3. Inicializa el MinMaxScaler.
  4. Aplica la normalización a las columnas seleccionadas usando fit_transform(). Esto escala los valores a un rango entre 0 y 1.
  5. Imprime las primeras filas del dataframe normalizado para ver los resultados.

El propósito de esta normalización es llevar todas las características numéricas a la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning, especialmente aquellos sensibles a la escala de las características de entrada. Esto es particularmente útil al trabajar con características que tienen escalas o unidades de medida significativamente diferentes, como el tamaño del lote y la antigüedad de la casa.

Características de Interacción

Las características de interacción se crean combinando dos o más características existentes para capturar relaciones complejas entre ellas que puedan influir significativamente en la variable objetivo. En el contexto de la predicción de precios de casas, estas interacciones pueden revelar patrones matizados que las características individuales podrían pasar por alto. Por ejemplo, la interacción entre Bedrooms y Bathrooms puede ser un importante predictor de los precios de las casas, ya que captura la utilidad del espacio habitable en general.

Esta interacción va más allá de considerar simplemente el número de habitaciones o baños por separado. Una casa con 3 dormitorios y 2 baños podría valorarse de manera diferente a una casa con 2 dormitorios y 3 baños, aunque el número total de habitaciones sea el mismo. La característica de interacción puede capturar esta diferencia sutil, proporcionando potencialmente al modelo información más precisa para la predicción del precio.

Además, las interacciones también pueden ser valiosas entre otras características. Por ejemplo, la interacción entre LotSize y Neighborhood podría revelar que los tamaños de lotes más grandes son más valiosos en ciertos vecindarios que en otros. De manera similar, una interacción entre HouseAge y Condition podría ayudar al modelo a comprender cómo varía el impacto de la antigüedad de una casa en su precio dependiendo de su condición general.

Ejemplo de Código: Creación de una Característica de Interacción

# Create an interaction feature between Bedrooms and Bathrooms
df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']

# View the first few rows to see the new feature
print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())

En este ejemplo:

Creamos una característica de interacción que multiplica el número de dormitorios y baños. Esta característica captura la idea de que la combinación de estas dos variables puede influir en el precio de la casa más que cualquiera de ellas por separado.

Esto es lo que hace cada línea:

  1. df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']Esta línea crea una nueva columna llamada 'BedroomBathroomInteraction' en el dataframe (df). Se calcula multiplicando los valores en la columna 'Bedrooms' con los valores correspondientes en la columna 'Bathrooms'.
  2. print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())Esta línea imprime las primeras filas del dataframe, mostrando solo las columnas 'Bedrooms', 'Bathrooms' y la nueva columna 'BedroomBathroomInteraction'. Esto te permite ver el resultado de la creación de la característica de interacción.

El propósito de esta característica de interacción es capturar el efecto combinado de dormitorios y baños en los precios de las casas. Esto puede ser más informativo que considerar estas características por separado, ya que refleja la utilidad del espacio habitable en general de la casa.

El Poder de la Ingeniería de Características

La ingeniería de características es uno de los aspectos más críticos para construir modelos de machine learning potentes. Al crear nuevas características, transformar las existentes y codificar variables categóricas de manera efectiva, puedes mejorar significativamente el rendimiento de tus modelos. Las características que hemos discutido aquí—como Edad de la CasaTamaño del Lote por DormitorioTransformaciones Logarítmicas y Características de Interacción—son solo algunos ejemplos de cómo puedes transformar datos brutos en entradas significativas para tu modelo.

2. Ingeniería de Características para la Predicción de Precios de Viviendas

Ahora que hemos limpiado el conjunto de datos y realizado una exploración inicial, es momento de sumergirnos en el proceso crucial de ingeniería de características. Este paso es donde el arte y la ciencia de la ciencia de datos realmente brillan, ya que transformamos datos crudos en características que representan de manera más precisa los patrones y relaciones subyacentes en nuestro problema de predicción de precios de viviendas.

La ingeniería de características no se trata solo de manipular datos; se trata de descubrir conocimientos ocultos y crear un conjunto de datos más rico y informativo para que nuestro modelo aprenda. Al elaborar cuidadosamente nuevas características y refinar las existentes, podemos mejorar significativamente la capacidad de nuestro modelo para captar relaciones complejas y matices en el mercado de viviendas que de otro modo pasarían desapercibidos.

En el ámbito de la predicción de precios de viviendas, la ingeniería de características puede involucrar una amplia gama de técnicas. Por ejemplo, podríamos crear características compuestas que combinen múltiples atributos, como un "índice de lujo" que considere acabados de alta calidad, singularidad arquitectónica y electrodomésticos de primera categoría. También podríamos desarrollar características que capturen tendencias del mercado incorporando datos históricos de precios e indicadores económicos locales, permitiendo a nuestro modelo comprender mejor la naturaleza dinámica de la valoración de bienes raíces.

En esta sección, exploraremos varias técnicas clave de ingeniería de características que son particularmente relevantes para nuestra tarea de predicción de precios de viviendas:

  • Creación de nuevas características: Derivaremos información significativa a partir de puntos de datos existentes, como calcular la edad de una casa a partir de su año de construcción o determinar el precio por pie cuadrado.
  • Codificación de variables categóricas: Transformaremos datos no numéricos, como nombres de vecindarios o tipos de propiedades, en un formato que nuestros algoritmos de machine learning puedan procesar eficazmente.
  • Transformación de características numéricas: Aplicaremos operaciones matemáticas a nuestros datos numéricos para captar mejor sus relaciones con los precios de las viviendas, como usar escalado logarítmico para características muy sesgadas como el tamaño del lote o el precio de venta.

Al dominar estas técnicas, podremos crear un conjunto de características que no solo represente las características obvias de una propiedad, sino que también capture dinámicas de mercado sutiles, tendencias de vecindario y otros factores que influyen en los precios de las viviendas. Este conjunto de características mejorado servirá como la base para construir un modelo predictivo altamente preciso y robusto.

2.1 Creación de Nuevas Características

La creación de nuevas características es un aspecto crucial de la ingeniería de características que implica derivar información significativa a partir de puntos de datos existentes. En el contexto de bienes raíces, este proceso es particularmente valioso, ya que nos permite captar factores complejos que influyen en los precios de las viviendas, más allá de las características evidentes como el metraje cuadrado y el número de habitaciones. Al sintetizar nuevas características, podemos proporcionar a nuestros modelos predictivos entradas más matizadas e informativas, permitiéndoles comprender mejor las complejidades de la valoración de propiedades.

Por ejemplo, podríamos crear características que reflejen la calidad de la ubicación de la propiedad combinando datos sobre comodidades cercanas, tasas de criminalidad y calificaciones de distritos escolares. Otro ejemplo podría ser un "índice de lujo" que considere acabados de alta gama, singularidad arquitectónica y electrodomésticos premium. También podríamos desarrollar características que capturen tendencias de mercado incorporando datos históricos de precios e indicadores económicos locales. Estas características elaboradas nos permiten encapsular conocimientos del dominio y dinámicas de mercado sutiles que pueden no ser evidentes en los datos crudos.

Además, la creación de características puede ayudar a abordar relaciones no lineales entre variables. Por ejemplo, el impacto de la edad de una propiedad en su precio podría no ser lineal: las casas muy antiguas podrían ser valiosas debido a su importancia histórica, mientras que las casas moderadamente antiguas podrían ser menos deseables. Al crear características que capturen estas relaciones matizadas, permitimos que nuestros modelos aprendan patrones de precios más precisos y sofisticados.

Ejemplo: Edad de la Casa

Una característica útil a crear es la edad de la casa, que se puede derivar de la columna YearBuilt. Generalmente, las casas más nuevas tienden a tener precios más altos debido a materiales mejores y diseños modernos.

Ejemplo de Código: Creación de la Característica Edad de la Casa

import pandas as pd

# Assuming the dataset has a YearBuilt column and the current year is 2024
df['HouseAge'] = 2024 - df['YearBuilt']

# View the first few rows to see the new feature
print(df[['YearBuilt', 'HouseAge']].head())

Este código crea una nueva característica llamada 'HouseAge' calculando la diferencia entre el año actual (asumido como 2024) y el año en que se construyó la casa. A continuación, se desglosa lo que hace el código:

  • Primero, importa la biblioteca pandas, que se utiliza comúnmente para la manipulación de datos en Python.
  • Asume que el conjunto de datos (representado por 'df') ya tiene una columna llamada 'YearBuilt' que contiene el año en que se construyó cada casa.
  • El código crea una nueva columna 'HouseAge' restando el valor de 'YearBuilt' de 2024 (el año actual asumido). Este cálculo da la edad de cada casa en años.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto la columna 'YearBuilt' como la nueva columna 'HouseAge'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque la edad de una casa puede ser un factor significativo en la determinación de su precio. Las casas más nuevas suelen tener precios más altos debido a diseños y materiales modernos, mientras que las casas muy antiguas podrían ser valiosas por razones históricas.

Al calcular la edad de la casa, añadimos una característica que puede ayudar al modelo a comprender cómo el paso del tiempo afecta los precios de las viviendas.

Ejemplo: Tamaño del Lote por Dormitorio

Otra característica que podemos crear es el Tamaño del Lote por Dormitorio, que representa la cantidad de terreno asociada con cada dormitorio. Esta característica puede ofrecer información sobre cómo la distribución del espacio en una propiedad afecta su valor.

Ejemplo de Código: Creación de la Característica Tamaño del Lote por Dormitorio

# Assuming the dataset has LotSize and Bedrooms columns
df['LotSizePerBedroom'] = df['LotSize'] / df['Bedrooms']

# View the first few rows to see the new feature
print(df[['LotSize', 'Bedrooms', 'LotSizePerBedroom']].head())

En este ejemplo, calculamos el tamaño del lote por dormitorio, lo cual puede proporcionar al modelo información más detallada sobre la distribución del espacio en la casa.

Este código crea una nueva característica llamada 'LotSizePerBedroom' dividiendo el 'LotSize' por el número de 'Bedrooms' para cada casa en el conjunto de datos. A continuación, se desglosa lo que hace el código:

  • Asume que el conjunto de datos (representado por 'df') ya tiene columnas llamadas 'LotSize' y 'Bedrooms'.
  • Crea una nueva columna 'LotSizePerBedroom' dividiendo el valor de 'LotSize' entre el valor de 'Bedrooms' para cada fila en el dataframe.
  • Finalmente, imprime las primeras filas del dataframe, mostrando las columnas 'LotSize', 'Bedrooms' y la recién creada 'LotSizePerBedroom'. Esto permite verificar que la nueva característica se creó correctamente.

Este paso de ingeniería de características es valioso porque proporciona información sobre cómo la distribución del espacio en una propiedad afecta su valor. El tamaño del lote por dormitorio puede ser un factor importante en la determinación del precio de una casa, ya que representa la cantidad de terreno asociada a cada dormitorio. Esta nueva característica proporciona al modelo información más detallada sobre la distribución del espacio en la casa, lo que puede ayudar a mejorar la precisión predictiva en los precios de las viviendas.

2.2 Codificación de Variables Categóricas

En el ámbito del aprendizaje automático para la predicción de precios de viviendas, a menudo nos encontramos con variables categóricas, es decir, características que tienen un conjunto finito de valores posibles. Ejemplos incluyen Ubicación (Código Postal)Tipo de Edificio o Estilo Arquitectónico. Estas variables presentan un desafío particular, ya que la mayoría de los algoritmos de aprendizaje automático están diseñados para trabajar con datos numéricos. Por lo tanto, necesitamos transformar estas características categóricas en un formato numérico que nuestros modelos puedan procesar eficazmente.

Este proceso de transformación se conoce como codificación y es un paso crucial en la preparación de nuestros datos para el análisis. Existen varios métodos de codificación disponibles, cada uno con sus propias ventajas y casos de uso ideales. Dos de las técnicas más comúnmente utilizadas son one-hot encoding y label encoding.

One-Hot Encoding es un método particularmente adecuado para variables categóricas sin un orden o jerarquía inherente. Esta técnica crea nuevas columnas binarias para cada categoría única dentro de una característica. Por ejemplo, si estamos trabajando con la característica Barrio, el one-hot encoding crearía columnas separadas para cada barrio en nuestro conjunto de datos. Una casa ubicada en un barrio específico tendría un '1' en la columna correspondiente y '0' en todas las demás columnas de barrios.

Este enfoque es especialmente valioso al trabajar con características como Código Postal o Estilo Arquitectónico, donde no existe un orden jerárquico entre categorías. El one-hot encoding permite que nuestro modelo trate cada categoría de manera independiente, lo cual puede ser crucial para capturar los efectos particulares de diferentes barrios o estilos en los precios de las viviendas.

Sin embargo, es importante tener en cuenta que el one-hot encoding puede aumentar significativamente la dimensionalidad de nuestro conjunto de datos, especialmente cuando se trata de categorías con muchos valores únicos. Esto puede llevar al "problema de la dimensionalidad" y puede requerir técnicas adicionales de selección de características para gestionar eficazmente el número aumentado de características.

Ejemplo de Código: One-Hot Encoding

# One-hot encode the 'Neighborhood' column
df_encoded = pd.get_dummies(df, columns=['Neighborhood'])

# View the first few rows of the encoded dataframe
print(df_encoded.head())

En este ejemplo:

La función get_dummies() crea nuevas columnas binarias para cada vecindario en el conjunto de datos. El modelo ahora puede usar esta información para diferenciar entre casas en distintos vecindarios.

Este código muestra cómo realizar one-hot encoding en una variable categórica, específicamente en la columna 'Neighborhood' de un conjunto de datos. A continuación, se explica lo que hace el código:

  1. df_encoded = pd.get_dummies(df, columns=['Neighborhood'])
    Esta línea utiliza la función get_dummies() de pandas para crear columnas binarias para cada valor único en la columna 'Neighborhood'. Cada nueva columna representa un vecindario específico, y contendrá un 1 si una casa está en ese vecindario, y un 0 en caso contrario.
  2. print(df_encoded.head())
    Esta línea imprime las primeras filas del dataframe recién codificado, permitiéndote ver el resultado del one-hot encoding.

El one-hot encoding es particularmente útil para variables categóricas como 'Neighborhood', donde no hay un orden o jerarquía inherente entre las categorías. Esto permite que el modelo trate cada vecindario como una característica independiente, lo cual es crucial para capturar los efectos específicos de diferentes vecindarios en los precios de las viviendas.

Sin embargo, es importante notar que este método puede aumentar significativamente el número de columnas en tu conjunto de datos, especialmente si la variable categórica tiene muchos valores únicos. Esto podría llevar al "problema de la dimensionalidad" y requerir técnicas adicionales de selección de características para manejar el incremento en el número de características de manera efectiva.

Label Encoding

Otra opción es el label encoding, que convierte cada categoría en un entero único. Este método es particularmente útil cuando las categorías tienen un orden o jerarquía inherente. Por ejemplo, al trabajar con una característica como Condition (por ejemplo, pobre, promedio, buena, excelente), el label encoding puede capturar la naturaleza ordinal de los datos.

El label encoding asigna un entero único a cada categoría, preservando el orden relativo. Por ejemplo, 'pobre' podría codificarse como 1, 'promedio' como 2, 'buena' como 3 y 'excelente' como 4. Esta representación numérica permite que el modelo comprenda la progresión o jerarquía dentro de la característica.

Sin embargo, es importante notar que el label encoding debe usarse con cautela. Aunque funciona bien para datos ordinales, aplicarlo a categorías nominales (aquellas sin un orden natural) puede introducir relaciones no deseadas en los datos. Por ejemplo, codificar 'rojo', 'azul' y 'verde' como 1, 2 y 3 respectivamente podría llevar al modelo a suponer incorrectamente que 'verde' es más similar a 'azul' que a 'rojo'.

Al usar label encoding, es fundamental documentar el esquema de codificación y considerar su impacto en la interpretación del modelo. En algunos casos, una combinación de label encoding para características ordinales y one-hot encoding para características nominales puede proporcionar los mejores resultados.

Ejemplo de Código: Label Encoding

from sklearn.preprocessing import LabelEncoder

# Label encode the 'Condition' column
label_encoder = LabelEncoder()
df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])

# View the first few rows to see the encoded column
print(df[['Condition', 'ConditionEncoded']].head())

En este ejemplo:

Usamos LabelEncoder para convertir la columna Condition en valores numéricos. Este enfoque es adecuado porque las condiciones de las casas pueden ordenarse en términos de calidad, de pobre a excelente.

Desglose del código:

  • from sklearn.preprocessing import LabelEncoderEsta línea importa la clase LabelEncoder de scikit-learn, que se utiliza para convertir etiquetas categóricas en forma numérica.
  • label_encoder = LabelEncoder()Esto crea una instancia de la clase LabelEncoder.
  • df['ConditionEncoded'] = label_encoder.fit_transform(df['Condition'])Esta línea aplica la codificación de etiquetas a la columna 'Condition'. El método fit_transform() aprende el esquema de codificación a partir de los datos y luego lo aplica, creando una nueva columna 'ConditionEncoded' con las etiquetas numéricas.
  • print(df[['Condition', 'ConditionEncoded']].head())Esto imprime las primeras filas tanto de la columna original 'Condition' como de la nueva columna 'ConditionEncoded', permitiéndote ver el resultado de la codificación.

Este enfoque es particularmente útil para variables categóricas ordinales como las condiciones de las casas, donde existe un orden natural (por ejemplo, pobre, promedio, bueno, excelente). La codificación preserva este orden en la representación numérica.

2.3 Transformación de Características Numéricas

La transformación de características numéricas es un paso crucial para preparar los datos para los modelos de machine learning, especialmente cuando se trata de distribuciones sesgadas. Este proceso puede mejorar significativamente la capacidad del modelo para detectar patrones y relaciones dentro de los datos. Dos técnicas de transformación ampliamente utilizadas son el escalado logarítmico y la normalización.

Transformación Logarítmica

La transformación logarítmica es particularmente efectiva para características que presentan un amplio rango de valores o están fuertemente sesgadas. En el contexto de la predicción de precios de casas, características como SalePrice y LotSize suelen mostrar esta característica. Al aplicar una función logarítmica a estas variables, podemos comprimir la escala de valores grandes mientras ampliamos la escala de valores más pequeños. Esto tiene varios beneficios:

  • Reducción del sesgo: Acerca la distribución a una distribución normal, lo cual es un supuesto de muchas técnicas estadísticas.
  • Mitigación del impacto de los valores atípicos: Los valores extremos se acercan al resto de los datos, reduciendo su influencia desproporcionada en el modelo.
  • Mejora de la linealidad: En algunos casos, puede ayudar a linearizar las relaciones entre variables, facilitando su captura por modelos lineales.

Por ejemplo, una casa con un precio de $1,000,000 y otra con un precio de $100,000 tendrían valores transformados logarítmicamente de aproximadamente 13.82 y 11.51 respectivamente, reduciendo la diferencia absoluta y manteniendo la relación relativa.

Sin embargo, es importante tener en cuenta que las transformaciones logarítmicas deben aplicarse con prudencia. Son más efectivas cuando los datos tienen un sesgo positivo y todos los valores son positivos. Además, interpretar los resultados de un modelo que usa características transformadas logarítmicamente requiere una consideración cuidadosa, ya que los efectos ya no están en la escala original.

Ejemplo de Código: Transformación Logarítmica

import numpy as np

# Apply a logarithmic transformation to SalePrice and LotSize
df['LogSalePrice'] = np.log(df['SalePrice'])
df['LogLotSize'] = np.log(df['LotSize'])

# View the first few rows to see the transformed features
print(df[['SalePrice', 'LogSalePrice', 'LotSize', 'LogLotSize']].head())

En este ejemplo:

Aplicamos np.log() a las columnas SalePrice y LotSize, transformándolas en un formato más cercano a una distribución normal. Esto puede ayudar al modelo a desempeñarse mejor al reducir la asimetría.

Este código muestra cómo aplicar una transformación logarítmica a características numéricas en un conjunto de datos, específicamente en las columnas 'SalePrice' y 'LotSize'. Aquí tienes un desglose de lo que hace el código:

  • Primero, importa la biblioteca numpy como 'np', la cual proporciona funciones matemáticas, incluida la función de logaritmo.
  • Luego, crea dos nuevas columnas en el dataframe:
    • 'LogSalePrice': Se crea aplicando el logaritmo natural (np.log()) a la columna 'SalePrice'.
    • 'LogLotSize': De manera similar, se crea aplicando el logaritmo natural a la columna 'LotSize'.
  • Finalmente, imprime las primeras filas del dataframe, mostrando tanto las versiones originales como las transformadas con logaritmo de 'SalePrice' y 'LotSize'.

El propósito de esta transformación es reducir la asimetría en la distribución de los datos y potencialmente mejorar el rendimiento de los modelos de machine learning. La transformación logarítmica puede ser particularmente útil para características como precios de venta y tamaños de lote, que a menudo tienen rangos amplios y pueden estar sesgados positivamente.

Normalización

La normalización es una técnica crucial en la ingeniería de características que reescala los valores de las características numéricas a un rango estándar, típicamente entre 0 y 1. Este proceso es especialmente importante cuando se trabaja con características que tienen escalas o unidades de medida significativamente diferentes. Por ejemplo, en nuestro modelo de predicción de precios de casas, características como LotSize (que podría estar en miles de pies cuadrados) y Bedrooms (generalmente un número entero pequeño) existen en escalas muy diferentes.

La importancia de la normalización se hace evidente cuando consideramos cómo los algoritmos de machine learning procesan los datos. Muchos algoritmos, como los métodos basados en descenso de gradiente, son sensibles a la escala de las características de entrada. Cuando las características están en diferentes escalas, aquellas con magnitudes mayores pueden dominar el proceso de aprendizaje, lo que podría llevar a un rendimiento del modelo sesgado o subóptimo. Al normalizar todas las características a una escala común, aseguramos que cada característica contribuya proporcionalmente al proceso de aprendizaje del modelo.

Además, la normalización puede mejorar la velocidad de convergencia de los algoritmos de optimización utilizados en el entrenamiento de modelos de machine learning. Ayuda a crear un espacio de características más uniforme, lo que puede conducir a un entrenamiento del modelo más rápido y estable. Esto es particularmente beneficioso cuando se utilizan algoritmos como redes neuronales o máquinas de soporte vectorial.

En el contexto de nuestro modelo de predicción de precios de casas, normalizar características como LotSize y Bedrooms permite que el modelo las trate de manera equitativa, a pesar de sus diferencias inherentes en escala. Esto puede llevar a predicciones más precisas y a una mejor comprensión del impacto real de cada característica en los precios de las casas.

Ejemplo de Código: Normalización de Características Numéricas

from sklearn.preprocessing import MinMaxScaler

# Define the numerical columns to normalize
numerical_columns = ['LotSize', 'HouseAge', 'SalePrice']

# Initialize the MinMaxScaler
scaler = MinMaxScaler()

# Apply normalization
df[numerical_columns] = scaler.fit_transform(df[numerical_columns])

# View the first few rows of the normalized dataframe
print(df[numerical_columns].head())

En este ejemplo:

Usamos MinMaxScaler de Scikit-learn para normalizar las columnas numéricas seleccionadas. Esto asegura que todas las características numéricas estén en la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning.

Este código demuestra cómo normalizar características numéricas en un conjunto de datos usando MinMaxScaler de scikit-learn. Aquí tienes un desglose de lo que hace el código:

  1. Importa MinMaxScaler desde sklearn.preprocessing.
  2. Define una lista de columnas numéricas para normalizar: 'LotSize', 'HouseAge' y 'SalePrice'.
  3. Inicializa el MinMaxScaler.
  4. Aplica la normalización a las columnas seleccionadas usando fit_transform(). Esto escala los valores a un rango entre 0 y 1.
  5. Imprime las primeras filas del dataframe normalizado para ver los resultados.

El propósito de esta normalización es llevar todas las características numéricas a la misma escala, lo que puede mejorar el rendimiento de los algoritmos de machine learning, especialmente aquellos sensibles a la escala de las características de entrada. Esto es particularmente útil al trabajar con características que tienen escalas o unidades de medida significativamente diferentes, como el tamaño del lote y la antigüedad de la casa.

Características de Interacción

Las características de interacción se crean combinando dos o más características existentes para capturar relaciones complejas entre ellas que puedan influir significativamente en la variable objetivo. En el contexto de la predicción de precios de casas, estas interacciones pueden revelar patrones matizados que las características individuales podrían pasar por alto. Por ejemplo, la interacción entre Bedrooms y Bathrooms puede ser un importante predictor de los precios de las casas, ya que captura la utilidad del espacio habitable en general.

Esta interacción va más allá de considerar simplemente el número de habitaciones o baños por separado. Una casa con 3 dormitorios y 2 baños podría valorarse de manera diferente a una casa con 2 dormitorios y 3 baños, aunque el número total de habitaciones sea el mismo. La característica de interacción puede capturar esta diferencia sutil, proporcionando potencialmente al modelo información más precisa para la predicción del precio.

Además, las interacciones también pueden ser valiosas entre otras características. Por ejemplo, la interacción entre LotSize y Neighborhood podría revelar que los tamaños de lotes más grandes son más valiosos en ciertos vecindarios que en otros. De manera similar, una interacción entre HouseAge y Condition podría ayudar al modelo a comprender cómo varía el impacto de la antigüedad de una casa en su precio dependiendo de su condición general.

Ejemplo de Código: Creación de una Característica de Interacción

# Create an interaction feature between Bedrooms and Bathrooms
df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']

# View the first few rows to see the new feature
print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())

En este ejemplo:

Creamos una característica de interacción que multiplica el número de dormitorios y baños. Esta característica captura la idea de que la combinación de estas dos variables puede influir en el precio de la casa más que cualquiera de ellas por separado.

Esto es lo que hace cada línea:

  1. df['BedroomBathroomInteraction'] = df['Bedrooms'] * df['Bathrooms']Esta línea crea una nueva columna llamada 'BedroomBathroomInteraction' en el dataframe (df). Se calcula multiplicando los valores en la columna 'Bedrooms' con los valores correspondientes en la columna 'Bathrooms'.
  2. print(df[['Bedrooms', 'Bathrooms', 'BedroomBathroomInteraction']].head())Esta línea imprime las primeras filas del dataframe, mostrando solo las columnas 'Bedrooms', 'Bathrooms' y la nueva columna 'BedroomBathroomInteraction'. Esto te permite ver el resultado de la creación de la característica de interacción.

El propósito de esta característica de interacción es capturar el efecto combinado de dormitorios y baños en los precios de las casas. Esto puede ser más informativo que considerar estas características por separado, ya que refleja la utilidad del espacio habitable en general de la casa.

El Poder de la Ingeniería de Características

La ingeniería de características es uno de los aspectos más críticos para construir modelos de machine learning potentes. Al crear nuevas características, transformar las existentes y codificar variables categóricas de manera efectiva, puedes mejorar significativamente el rendimiento de tus modelos. Las características que hemos discutido aquí—como Edad de la CasaTamaño del Lote por DormitorioTransformaciones Logarítmicas y Características de Interacción—son solo algunos ejemplos de cómo puedes transformar datos brutos en entradas significativas para tu modelo.