Assignment UT3-7-1: Feature Engineering con Pandas - Fill in the Blanks¶
📋 Lo que necesitas saber ANTES de empezar¶
- Conceptos básicos de Python y pandas
- Idea general de qué es feature engineering
- Curiosidad por crear nuevas variables a partir de datos existentes
🏠 Parte 1: Setup y Carga de Datos¶
📋 CONTEXTO DE NEGOCIO (CRISP-DM: Business Understanding)
🔗 Referencias oficiales:
🏠 Caso de negocio:
- Problema: Una empresa inmobiliaria necesita predecir precios de viviendas con mayor precisión
- Objetivo: Crear features derivadas que capturen patrones no obvios en los datos
- Variables: Precio, superficie, habitaciones, año construcción, ubicación, etc.
- Valor para el negocio: Mejorar predicciones de precios para optimizar inversiones
# Importar librerías que vamos a usar
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.feature_selection import mutual_info_regression
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
import warnings
warnings.filterwarnings('ignore')
# Configuración
np.random.seed(42)
plt.style.use('_______') # establecer estilo visual (ej: 'default', 'seaborn', 'classic')
sns.set_palette("_______") # definir paleta de colores (ej: 'husl', 'Set1', 'viridis')
plt.rcParams['figure.figsize'] = (12, 8)
print("✅ Entorno configurado correctamente")
💡 PISTAS:
- 🎨 Estilos de matplotlib
- 🌈 Paletas de seaborn
- 💭 ¿Qué estilo se ve más profesional para análisis de datos?
🏠 Paso 2: Crear Dataset Sintético de Viviendas¶
# === CREAR DATASET SINTÉTICO DE VIVIENDAS ===
# 1. Generar datos base
np.random.seed(42)
n_samples = 1000
data = {
'price': np.random.normal(200000, 50000, n_samples),
'sqft': np.random.normal(120, 30, n_samples),
'bedrooms': np.random.choice([1, 2, 3, 4, 5], n_samples),
'bathrooms': np.random.choice([1, 2, 3], n_samples),
'year_built': np.random.choice(range(1980, 2024), n_samples),
'garage_spaces': np.random.choice([0, 1, 2, 3], n_samples),
'lot_size': np.random.normal(8000, 2000, n_samples),
'distance_to_city': np.random.normal(15, 8, n_samples),
'school_rating': np.random.uniform(1, 10, n_samples),
'crime_rate': np.random.uniform(0, 100, n_samples)
}
df = pd._______(data) # función para crear DataFrame desde diccionario
# Asegurar valores positivos
df['price'] = np.abs(df['price'])
df['sqft'] = np.abs(df['sqft'])
df['lot_size'] = np.abs(df['lot_size'])
df['distance_to_city'] = np.abs(df['distance_to_city'])
print("🏠 DATASET: Viviendas Sintéticas")
print(f" 📊 Forma: {df.shape}")
print(f" 📋 Columnas: {list(df.columns)}")
# 2. Explorar los datos básicamente
print("\n🔍 Primeras 5 filas:")
print(df._____()) # método para mostrar las primeras filas del DataFrame
# 3. Estadísticas básicas
print("\n📊 ESTADÍSTICAS BÁSICAS:")
print(df._____()) # método que calcula estadísticas descriptivas
💡 PISTAS:
- 📚 ¿Qué función de pandas crea DataFrame desde diccionario? Documentación
- 👀 ¿Cuál método muestra las primeras filas? Documentación
- 📊 ¿Cuál método calcula estadísticas descriptivas? Documentación
⚙️ Paso 3: Crear Features Derivadas¶
# === CREAR FEATURES DERIVADAS ===
print("⚙️ CREANDO FEATURES DERIVADAS")
print("-" * 50)
# Crear copia del dataset para trabajar
df_enhanced = df.copy()
# 1. RATIOS Y PROPORCIONES (Ejemplos básicos)
print("🔢 1. CREANDO RATIOS Y PROPORCIONES")
# Feature 1: Precio por pie cuadrado
df_enhanced['price_per_sqft'] = df_enhanced['price'] / df_enhanced['sqft']
print("✅ price_per_sqft: Precio por pie cuadrado")
# Feature 2: Superficie por habitación
df_enhanced['sqft_per_bedroom'] = df_enhanced['sqft'] / df_enhanced['bedrooms']
print("✅ sqft_per_bedroom: Superficie por habitación")
# TODO: Crea al menos 2 ratios más que consideres relevantes
# PISTAS: ¿Qué otros ratios podrían ser útiles?
# - ¿Ratio entre habitaciones y baños?
# - ¿Densidad de construcción (superficie/lote)?
# - ¿Precio por habitación?
# - ¿Ratio entre distancia a ciudad y rating de escuela?
# Tu código aquí:
# df_enhanced['mi_ratio_1'] = _______
# df_enhanced['mi_ratio_2'] = _______
# 2. VARIABLES TEMPORALES (Ejemplo básico)
print("\n📅 2. CREANDO VARIABLES TEMPORALES")
# Feature 3: Antigüedad de la propiedad
current_year = 2024
df_enhanced['property_age'] = current_year - df_enhanced['year_built']
print("✅ property_age: Antigüedad de la propiedad")
# TODO: Crea variables temporales adicionales
# PISTAS: ¿Qué información temporal podría ser útil?
# - ¿Categorías de antigüedad (nuevo, moderno, antiguo)?
# - ¿Es propiedad nueva? (binario)
# - ¿Década de construcción?
# - ¿Es construcción reciente vs histórica?
# Tu código aquí:
# df_enhanced['age_category'] = pd._______(...)
# df_enhanced['is_new_property'] = _______
# 3. TRANSFORMACIONES MATEMÁTICAS (Ejemplo básico)
print("\n🧮 3. APLICANDO TRANSFORMACIONES MATEMÁTICAS")
# Feature 4: Log del precio (para normalizar distribución)
df_enhanced['log_price'] = np._______(df_enhanced['price']) # función para logaritmo natural
print("✅ log_price: Logaritmo del precio")
# TODO: Aplica otras transformaciones matemáticas
# PISTAS: ¿Qué transformaciones podrían ayudar?
# - ¿Raíz cuadrada de superficie?
# - ¿Superficie al cuadrado?
# - ¿Log de otras variables?
# - ¿Transformaciones para normalizar distribuciones sesgadas?
# Tu código aquí:
# df_enhanced['sqrt_sqft'] = _______
# df_enhanced['sqft_squared'] = _______
# 4. FEATURES COMPUESTAS (Tu turno!)
print("\n🎯 4. CREANDO FEATURES COMPUESTAS")
# TODO: Crea features que combinen múltiples variables
# PISTAS: ¿Qué conceptos complejos podrías capturar?
# - ¿Score de lujo (precio alto + superficie grande + amenities)?
# - ¿Score de ubicación (distancia baja + escuela alta + crimen bajo)?
# - ¿Score de eficiencia (superficie por habitación + precio por m²)?
# - ¿Indicadores de calidad (antigüedad + amenities + ubicación)?
# Tu código aquí:
# df_enhanced['luxury_score'] = _______
# df_enhanced['location_score'] = _______
print(f"\n📊 RESUMEN DE FEATURES CREADAS:")
print(f"Dataset original: {df.shape[1]} columnas")
print(f"Dataset con features: {df_enhanced.shape[1]} columnas")
print(f"Features creadas: {df_enhanced.shape[1] - df.shape[1]}")
💡 PISTAS:
- 📊 ¿Qué función de pandas crea categorías? Documentación
- 🔢 ¿Qué tipo de datos usar para variables binarias? ('int', 'float', 'bool')
- 📈 ¿Qué función de numpy calcula logaritmo natural? Documentación
- 🔢 ¿Qué función de numpy calcula raíz cuadrada? Documentación
📊 Paso 4: Análisis de Distribución de Features¶
# === ANÁLISIS DE DISTRIBUCIÓN DE FEATURES ===
print("📊 ANÁLISIS DE DISTRIBUCIÓN DE FEATURES")
print("-" * 50)
# 1. ANÁLISIS DE DISTRIBUCIÓN DE NUEVAS FEATURES
print("🔍 1. DISTRIBUCIÓN DE FEATURES DERIVADAS")
# Seleccionar solo las nuevas features creadas
new_features = ['price_per_sqft', 'sqft_per_bedroom', 'bedroom_bathroom_ratio',
'building_density', 'property_age', 'log_price', 'sqrt_sqft', 'sqft_squared']
print("📈 Estadísticas de nuevas features:")
print(df_enhanced[new_features].______().round(2)) # método para estadísticas descriptivas
# 2. VISUALIZACIÓN DE DISTRIBUCIONES
print("\n📊 2. VISUALIZANDO DISTRIBUCIONES")
# Crear subplots para visualizar distribuciones
fig, axes = plt.subplots(2, 4, figsize=(16, 8))
axes = axes.ravel() # convertir a array 1D
for i, feature in enumerate(new_features):
# Histograma de la feature
df_enhanced[feature].hist(bins=30, ax=axes[i], alpha=0.7, color='skyblue')
axes[i].set_title(f'Distribución de {feature}')
axes[i].set_xlabel(feature)
axes[i].set_ylabel('Frecuencia')
axes[i].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 3. DETECCIÓN DE OUTLIERS
print("\n🚨 3. DETECCIÓN DE OUTLIERS")
def detect_outliers_iqr(df, column):
"""Detectar outliers usando método IQR"""
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]
return outliers, lower_bound, upper_bound
# Detectar outliers en features numéricas importantes
numeric_features = ['price_per_sqft', 'sqft_per_bedroom', 'property_age']
for feature in numeric_features:
outliers, lower, upper = detect_outliers_iqr(df_enhanced, feature)
print(f"🔍 {feature}:")
print(f" 📊 Total outliers: {len(outliers)} ({len(outliers)/len(df_enhanced)*100:.1f}%)")
print(f" 📏 Rango normal: [{lower:.2f}, {upper:.2f}]")
💡 PISTAS:
- 📊 ¿Qué método calcula estadísticas descriptivas? Documentación
- 📈 ¿Qué función de matplotlib crea histogramas? Documentación
- 🔍 ¿Qué función calcula percentiles? Documentación
- 📏 ¿Qué es el método IQR para detectar outliers? Explicación
🎯 Paso 5: Evaluación de Importancia de Features¶
# === EVALUACIÓN DE IMPORTANCIA DE FEATURES ===
print("🎯 EVALUACIÓN DE IMPORTANCIA DE FEATURES")
print("-" * 50)
# 1. PREPARAR DATOS PARA EVALUACIÓN
print("🔧 1. PREPARANDO DATOS PARA EVALUACIÓN")
# Seleccionar features numéricas para evaluación
numeric_features = ['sqft', 'bedrooms', 'bathrooms', 'year_built', 'garage_spaces',
'lot_size', 'distance_to_city', 'school_rating', 'crime_rate',
'price_per_sqft', 'sqft_per_bedroom', 'bedroom_bathroom_ratio',
'building_density', 'property_age', 'log_price', 'sqrt_sqft', 'sqft_squared']
# Preparar X e y
X = df_enhanced[numeric_features].fillna(0) # llenar valores faltantes con 0
y = df_enhanced['price']
print(f"📊 Features evaluadas: {len(numeric_features)}")
print(f"📊 Muestras: {X.shape[0]}")
# 2. MUTUAL INFORMATION
print("\n📈 2. CALCULANDO MUTUAL INFORMATION")
# Calcular mutual information
mi_scores = mutual_info_regression(X, y, random_state=42)
# Crear DataFrame con resultados
mi_df = pd.DataFrame({
'feature': numeric_features,
'mutual_info': mi_scores
}).sort_values('mutual_info', ascending=False)
print("🔝 Top 10 features por Mutual Information:")
print(mi_df.head(10).round(4))
# 3. RANDOM FOREST IMPORTANCE
print("\n🌲 3. CALCULANDO IMPORTANCIA CON RANDOM FOREST")
# Entrenar Random Forest
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X, y)
# Obtener importancia de features
rf_importance = pd.DataFrame({
'feature': numeric_features,
'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)
print("🔝 Top 10 features por Random Forest:")
print(rf_importance.head(10).round(4))
# 4. VISUALIZACIÓN COMPARATIVA
print("\n📊 4. VISUALIZACIÓN COMPARATIVA")
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
# Mutual Information
top_mi = mi_df.head(10)
ax1.barh(range(len(top_mi)), top_mi['mutual_info'], color='skyblue')
ax1.set_yticks(range(len(top_mi)))
ax1.set_yticklabels(top_mi['feature'])
ax1.set_xlabel('Mutual Information')
ax1.set_title('Top 10 Features - Mutual Information')
ax1.grid(True, alpha=0.3)
# Random Forest Importance
top_rf = rf_importance.head(10)
ax2.barh(range(len(top_rf)), top_rf['importance'], color='lightgreen')
ax2.set_yticks(range(len(top_rf)))
ax2.set_yticklabels(top_rf['feature'])
ax2.set_xlabel('Feature Importance')
ax2.set_title('Top 10 Features - Random Forest')
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 5. ANÁLISIS DE CORRELACIÓN CON TARGET
print("\n🔗 5. CORRELACIÓN CON PRECIO")
# Calcular correlaciones
correlations = df_enhanced[numeric_features + ['price']].corr()['price'].drop('price')
correlations = correlations.sort_values(key=abs, ascending=False)
print("🔝 Top 10 correlaciones con precio:")
print(correlations.head(10).round(4))
💡 PISTAS:
- 📊 ¿Qué función calcula mutual information? Documentación
- 🌲 ¿Qué atributo del Random Forest contiene la importancia? Documentación
- 🔗 ¿Qué método calcula correlaciones? Documentación
- 📈 ¿Qué función de matplotlib crea gráficos de barras horizontales? Documentación
🚀 Paso 6: Investigación Libre - Tu Turno¶
# === INVESTIGACIÓN LIBRE ===
# Aquí tienes libertad para explorar y crear tus propias features
print("🚀 INVESTIGACIÓN LIBRE - CREA TUS PROPIAS FEATURES")
print("=" * 60)
# 🎯 DESAFÍO 1: Features de Dominio Inmobiliario
print("🎯 DESAFÍO 1: Features de Dominio Inmobiliario")
print("-" * 40)
# TODO: Crea al menos 3 features nuevas basadas en tu conocimiento del mercado inmobiliario
# PISTAS ESPECÍFICAS:
# - ¿Cómo afecta la relación entre superficie y lote? (¿es eficiente el uso del espacio?)
# - ¿Qué pasa con propiedades que tienen muchas habitaciones pero poca superficie?
# - ¿Cómo combinar distancia a ciudad, crimen y rating de escuela en un score de ubicación?
# - ¿Hay patrones relacionados con la década de construcción vs precio?
# Tu código aquí:
# df_enhanced['space_efficiency'] = _______ # ¿superficie/lote?
# df_enhanced['crowded_property'] = _______ # ¿habitaciones/superficie?
# df_enhanced['location_score'] = _______ # ¿combinar distancia, crimen, escuela?
print("💡 PISTAS AVANZADAS:")
print("- Piensa en outliers: ¿qué hace única a una propiedad?")
print("- Considera interacciones: ¿cómo se relacionan múltiples variables?")
print("- Usa conocimiento del dominio: ¿qué buscan los compradores?")
# 🎯 DESAFÍO 2: Features de Interacción
print("\n🎯 DESAFÍO 2: Features de Interacción")
print("-" * 40)
# TODO: Crea features que capturen interacciones entre variables
# PISTAS:
# - ¿Cómo interactúa el precio por m² con la antigüedad?
# - ¿Qué pasa cuando una propiedad es nueva Y tiene muchas habitaciones?
# - ¿Cómo afecta la combinación de distancia y rating de escuela?
# Tu código aquí:
# df_enhanced['price_age_interaction'] = _______
# df_enhanced['new_large_property'] = _______
# df_enhanced['distance_school_interaction'] = _______
# 🎯 DESAFÍO 3: Evalúa el Impacto de tus Features
print("\n🎯 DESAFÍO 3: Evalúa el Impacto")
print("-" * 40)
# TODO: Analiza qué tan útiles son tus nuevas features
# 1. Calcula correlaciones con el precio
# 2. Visualiza distribuciones
# 3. Compara con features originales
# Tu código aquí:
# nuevas_features = ['space_efficiency', 'crowded_property', 'location_score']
# correlaciones = df_enhanced[nuevas_features + ['price']].corr()['price']
# print("Correlaciones de mis features:")
# print(correlaciones)
# Visualizar distribuciones
# fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# for i, feature in enumerate(nuevas_features):
# df_enhanced[feature].hist(bins=30, ax=axes[i], alpha=0.7)
# axes[i].set_title(f'Distribución de {feature}')
# plt.tight_layout()
# plt.show()
# 🎯 DESAFÍO 4: Documenta tu Proceso
print("\n🎯 DESAFÍO 4: Documenta tu Proceso")
print("-" * 40)
# TODO: Explica el razonamiento detrás de cada feature
print("📝 REFLEXIÓN OBLIGATORIA:")
print("1. ¿Qué features creaste y cuál fue tu razonamiento?")
print("2. ¿Qué patrones esperabas encontrar?")
print("3. ¿Los resultados coinciden con tus expectativas?")
print("4. ¿Cuál fue tu feature más creativa y por qué?")
print("5. ¿Qué otras features podrías crear con más tiempo?")
# TODO: Escribe tus respuestas aquí:
# print("Mis respuestas:")
# print("1. ...")
# print("2. ...")
# print("3. ...")
# print("4. ...")
# print("5. ...")
💡 PISTAS PARA INVESTIGACIÓN:
- 🏠 Dominio inmobiliario: Piensa en qué factores realmente afectan el precio de una casa
- 📊 Visualización: Usa
plt.scatter()
oplt.hist()
para explorar tus features - 🔍 Correlación: Usa
.corr()
para medir la relación con el precio - 📚 Documentación: Pandas Feature Engineering
- 🎯 Creatividad: No hay respuestas "correctas", solo diferentes perspectivas
🧪 Paso 7: Dataset de Prueba - Ames Housing¶
# === PROBAR TUS SKILLS CON DATOS REALES ===
print("🧪 PROBANDO CON DATOS REALES - AMES HOUSING")
print("=" * 60)
# Cargar dataset real de Ames Housing (más pequeño para práctica)
# Este dataset tiene características similares pero datos reales
ames_data = {
'SalePrice': [215000, 105000, 172000, 244000, 189900],
'GrLivArea': [1710, 856, 1262, 1710, 1362],
'BedroomAbvGr': [3, 3, 3, 3, 3],
'FullBath': [2, 1, 2, 2, 1],
'YearBuilt': [2003, 1961, 1958, 2000, 1992],
'GarageCars': [2, 1, 2, 2, 1],
'LotArea': [8450, 9600, 11250, 9550, 10140],
'Neighborhood': ['CollgCr', 'Veenker', 'Crawfor', 'NoRidge', 'Mitchel']
}
ames_df = pd.DataFrame(ames_data)
print("🏠 DATASET REAL: Ames Housing (muestra)")
print(f" 📊 Forma: {ames_df.shape}")
print(f" 📋 Columnas: {list(ames_df.columns)}")
print("\n🔍 Primeras filas:")
print(ames_df.head())
# TODO: Aplica las técnicas que aprendiste a este dataset real
# 1. Crea las mismas features que hiciste antes
# 2. ¿Qué features adicionales podrías crear?
# 3. ¿Cómo se comparan los resultados?
# Tu código aquí:
# ames_df['price_per_sqft'] = _______
# ames_df['property_age'] = _______
# ames_df['space_efficiency'] = _______
print("\n💡 DESAFÍO:")
print("- ¿Qué features funcionan mejor con datos reales?")
print("- ¿Hay diferencias entre datos sintéticos y reales?")
print("- ¿Qué nuevas features podrías crear con 'Neighborhood'?")
🎯 Resumen y Reflexión Final¶
✅ Lo que aprendiste:¶
- Crear features derivadas usando operaciones matemáticas básicas
- Evaluar distribución de nuevas variables con estadísticas descriptivas
- Calcular importancia usando mutual information y random forest
- Visualizar patrones en los datos con histogramas y gráficos
- Documentar proceso de creación de features
- Aplicar técnicas a datasets reales
🤔 Preguntas para reflexionar:¶
- ¿Cuáles fueron las features más importantes según tu análisis?
- ¿Qué sorpresas encontraste en los datos?
- ¿Cómo podrías mejorar el proceso de feature engineering?
- ¿Qué otras técnicas de feature engineering conoces?
- ¿Qué diferencias notaste entre datos sintéticos y reales?