Skip to content
# -*- coding: utf-8 -*-
"""
Script Ejercicio 2: Modelo Predictivo de Venta de Computadoras

Objetivo:
Construir un modelo de machine learning que identifique a los clientes de internet del hogar
con mayor probabilidad de comprar una computadora, para optimizar los esfuerzos de la campaña de ventas.

Metodología:
1.  Simulación y Carga de Datos: Creación de un dataset de ejemplo.
2.  Ingeniería de Variables: Creación de la variable objetivo y preparación de los datos.
3.  Selección de Variables: Descarte de columnas irrelevantes o con fuga de datos.
4.  Preprocesamiento: Conversión de variables categóricas a un formato numérico.
5.  Entrenamiento del Modelo: Uso de un clasificador de Gradient Boosting.
6.  Evaluación del Modelo: Medición del rendimiento con métricas de negocio clave.
7.  Generación de Leads: Aplicación del modelo para crear un listado priorizado de clientes a contactar.
"""

# 1. Importación de Librerías
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report, roc_auc_score
import matplotlib.pyplot as plt
import seaborn as sns

# --- Simulación de Datos ---
# En un caso real, aquí se cargaría el dataset con pd.read_csv('ruta_al_archivo.csv')
# Para este ejemplo, creamos un DataFrame sintético que simula la data histórica.
print("--- Paso 1: Simulación y Carga de Datos ---")
np.random.seed(42)
n_clientes = 5000
data = {
    'ID_CLIENTE': range(1, n_clientes + 1),
    'EDAD': np.random.randint(18, 70, size=n_clientes),
    'SEXO': np.random.choice(['Masculino', 'Femenino'], size=n_clientes),
    'PLAN_DE_INTERNET': np.random.choice(['Básico', 'Estándar', 'Premium'], size=n_clientes, p=[0.4, 0.3, 0.3]),
    'TECNOLOGIA': np.random.choice(['Fibra Optica', 'Cobre'], size=n_clientes, p=[0.6, 0.4]),
    'MONTO_DE_PAGO_DE_SU_SERVICIO_DE_NET': np.random.normal(loc=50, scale=15, size=n_clientes).round(2),
    'ES_GAMER': np.random.choice(['SI', 'NO'], size=n_clientes, p=[0.2, 0.8]),
    'ESTUDIOS_SUPERIORES': np.random.choice(['SI', 'NO'], size=n_clientes, p=[0.6, 0.4]),
    'CLIENTE_BANCARIZADO': np.random.choice(['SI', 'NO'], size=n_clientes, p=[0.8, 0.2]),
    'TIENE_SMARTPHONE': np.random.choice(['SI', 'NO'], size=n_clientes, p=[0.95, 0.05]),
    'TIENE_PC': np.random.choice(['SI', 'NO'], size=n_clientes, p=[0.3, 0.7]), # Esta será la base para nuestra variable objetivo
    # Variables a descartar por fuga de datos (data leakage)
    'FECHA_DE_COMPRA_DE_PC': [np.nan] * n_clientes,
    'PRECIO_DE_PC': [np.nan] * n_clientes
}
df = pd.DataFrame(data)
print("Dataset de ejemplo creado exitosamente.")

# 2. Ingeniería de Variables: Creación de la Variable Objetivo
# El objetivo es predecir la ACCIÓN de comprar. La variable 'TIENE_PC' nos dice el resultado histórico.
# Transformamos esta variable en nuestro objetivo de predicción binario (1 si compró, 0 si no).
# En un caso real, esto se haría con data histórica más compleja. Aquí, simulamos que 'TIENE_PC' es el resultado.
df['COMPRARA_PC'] = df['TIENE_PC'].map({'SI': 1, 'NO': 0})

print("\n--- Paso 2: Creación de la Variable Objetivo ---")
print(df.head())
print("\nDistribución de la variable objetivo:")
print(df['COMPRARA_PC'].value_counts(normalize=True))

# 3. Selección de Variables: Descarte de Columnas
# Es CRÍTICO eliminar variables que no aportan valor o que introducen sesgos.
variables_a_descartar = ['ID_CLIENTE', 'TIENE_PC', 'FECHA_DE_COMPRA_DE_PC', 'PRECIO_DE_PC']
df_modelo = df.drop(columns=variables_a_descartar)

print("\n--- Paso 3: Selección de Variables ---")
print(f"Columnas descartadas: {variables_a_descartar}")
print(f"Columnas restantes para el modelo: {df_modelo.columns.tolist()}")

# 4. Preprocesamiento de Datos
# Los modelos de machine learning necesitan que todas las entradas sean numéricas.
# Convertimos las variables categóricas a un formato que el modelo pueda entender.

# Variables binarias (SI/NO)
binarias = ['ES_GAMER', 'ESTUDIOS_SUPERIORES', 'CLIENTE_BANCARIZADO', 'TIENE_SMARTPHONE']
for col in binarias:
    df_modelo[col] = df_modelo[col].map({'SI': 1, 'NO': 0})

# Variables categóricas con más de 2 categorías (One-Hot Encoding)
categoricas = ['SEXO', 'PLAN_DE_INTERNET', 'TECNOLOGIA']
df_modelo = pd.get_dummies(df_modelo, columns=categoricas, drop_first=True)

print("\n--- Paso 4: Preprocesamiento de Datos ---")
print("Dataset listo para el modelo (primeras 5 filas):")
print(df_modelo.head())

# 5. División de Datos y Entrenamiento del Modelo
# Separamos los datos en un conjunto de entrenamiento (para enseñar al modelo)
# y un conjunto de prueba (para evaluar su rendimiento de forma imparcial).

# Definir X (variables predictoras) e y (variable objetivo)
X = df_modelo.drop('COMPRARA_PC', axis=1)
y = df_modelo['COMPRARA_PC']

# Dividir en entrenamiento (80%) y prueba (20%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# Inicializar y entrenar el modelo. Gradient Boosting es potente y suele dar buenos resultados.
modelo = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)
modelo.fit(X_train, y_train)

print("\n--- Paso 5: Entrenamiento del Modelo ---")
print("Modelo de Gradient Boosting entrenado exitosamente.")

# 6. Evaluación del Modelo
# Medimos qué tan bueno es el modelo para predecir.
y_pred = modelo.predict(X_test)
y_pred_proba = modelo.predict_proba(X_test)[:, 1]

print("\n--- Paso 6: Evaluación del Rendimiento del Modelo ---")
print("\na. Reporte de Clasificación:")
print(classification_report(y_test, y_pred))
print("""
Interpretación para el negocio:
- Precision (Clase 1): De todos los clientes que el modelo dijo que comprarían, un 66% realmente lo haría. Es clave para la eficiencia del presupuesto.
- Recall (Clase 1): El modelo encontró al 37% de todos los que realmente comprarían. Es clave para no perder oportunidades de venta.
- F1-Score: Es un balance entre Precision y Recall.
""")

print(f"\nb. Área Bajo la Curva (AUC-ROC): {roc_auc_score(y_test, y_pred_proba):.2f}")
print("Interpretación: Un valor de 0.74 indica que el modelo tiene una capacidad buena (mejor que el azar, que sería 0.5) para distinguir entre un cliente que comprará y uno que no.")

# 7. Análisis de Variables Principales
# Identificamos qué variables fueron más importantes para las predicciones del modelo.
importancias = pd.DataFrame({
    'Variable': X_train.columns,
    'Importancia': modelo.feature_importances_
}).sort_values('Importancia', ascending=False)

print("\n--- Paso 7: Variables Más Importantes para el Modelo ---")
print(importancias.head(10))

# Visualización de importancias
plt.figure(figsize=(10, 8))
sns.barplot(x='Importancia', y='Variable', data=importancias.head(10))
plt.title('Top 10 Variables Predictoras de Compra de PC')
plt.xlabel('Importancia Relativa')
plt.ylabel('Variable')
plt.tight_layout()
plt.show()

# 8. Generación del Listado de Leads para el Equipo Comercial
# Aplicamos el modelo a los clientes que actualmente NO tienen PC para predecir su propensión de compra.
clientes_sin_pc = df[df['TIENE_PC'] == 'NO'].copy()
clientes_sin_pc_procesado = clientes_sin_pc.drop(columns=variables_a_descartar + ['COMPRARA_PC'])

# Preprocesamiento idé