Saltar al contenido
BásicoArturo Lorenzo·22 de agosto de 2026·5 min

Tu primer modelo de machine learning en 30 líneas de Python

Cuatro pasos: datos, split, entrenar, evaluar. Todo modelo de ML sigue este flujo.

Machine learning suena a magia negra. Redes neuronales, GPUs, tensores, gradientes. Todo muy intimidante. Pero la realidad es que el 80% de los problemas de ML en empresas se resuelven con modelos clásicos que caben en 30 líneas de código. Sin deep learning, sin clusters, sin GPU. Un random forest y datos decentes.

Vamos a construir un modelo que prediga si un cliente va a cancelar su suscripción (churn). Es un problema real que tienen todas las empresas con un modelo de suscripción: Netflix, Spotify, tu gimnasio. Y lo vamos a resolver con scikit-learn en menos líneas de las que tiene un email de empresa.

### El problema: predecir churn

Imagina que trabajas en una empresa SaaS. Tienes 5.000 clientes, y cada mes un 8% se da de baja. Tu jefe quiere saber QUIÉN se va a dar de baja el mes que viene para poder ofrecerles un descuento antes de que lo hagan. Eso es clasificación binaria: para cada cliente, predecir 0 (se queda) o 1 (se va).

### Los datos: qué necesitamos

Un modelo necesita dos cosas: features (las características de cada cliente que podrían predecir su comportamiento) y un target (lo que queremos predecir). En nuestro caso:

  • Features (X): antigüedad en meses, gasto mensual, número de tickets de soporte, frecuencia de uso semanal, tipo de plan
  • Target (y): churn — 1 si canceló en los últimos 30 días, 0 si no
1import pandas as pd
2from sklearn.model_selection import train_test_split
3from sklearn.ensemble import RandomForestClassifier
4from sklearn.metrics import classification_report, accuracy_score
5
6# --- 1. CARGAR DATOS ---
7# En un caso real esto viene de tu data warehouse
8# Aquí lo simulamos con make_classification
9from sklearn.datasets import make_classification
10import numpy as np
11
12np.random.seed(42)
13X, y = make_classification(
14 n_samples=5000,
15 n_features=5,
16 n_informative=3,
17 n_redundant=1,
18 weights=[0.92, 0.08], # 8% de churn, realista
19 random_state=42
20)
21
22# Darles nombre a las features para que tenga sentido
23df = pd.DataFrame(X, columns=[
24 'antiguedad_meses',
25 'gasto_mensual',
26 'tickets_soporte',
27 'uso_semanal',
28 'tipo_plan'
29])
30df['churn'] = y
31print(f"Clientes: {len(df)} | Churn: {y.sum()} ({y.mean()*100:.1f}%)")

En producción, estos datos vienen de tu warehouse. Aquí los simulamos para que puedas ejecutar el código tal cual.

### El split: nunca evalúes con los datos de entrenamiento

La regla de oro del ML: separas los datos en dos grupos ANTES de entrenar. El modelo aprende con uno (train) y lo evalúas con el otro (test), que nunca ha visto. Es como estudiar con un examen y luego hacer un examen DIFERENTE. Si evalúas con los mismos datos que usaste para entrenar, el modelo "se sabe las respuestas" y la nota es mentira.

1# --- 2. SPLIT ---
2X = df.drop('churn', axis=1)
3y = df['churn']
4
5X_train, X_test, y_train, y_test = train_test_split(
6 X, y,
7 test_size=0.2, # 20% para test
8 random_state=42, # reproducibilidad
9 stratify=y # mantener la proporción de churn en ambos
10)
11
12print(f"Train: {len(X_train)} | Test: {len(X_test)}")
13print(f"Churn en train: {y_train.mean()*100:.1f}%")
14print(f"Churn en test: {y_test.mean()*100:.1f}%")

stratify=y es clave cuando las clases están desbalanceadas: asegura que el 8% de churn se mantiene en ambos conjuntos.

El error más común de principiantes: evaluar con los datos de entrenamiento y celebrar un 99% de accuracy. Eso no demuestra nada — el modelo se ha memorizado las respuestas. Siempre evalúa con datos que el modelo NO ha visto.

### Entrenar: una línea

Aquí viene la parte que parece que debería ser complicada y no lo es. Entrenar un modelo en scikit-learn es llamar a .fit(). Una línea. El random forest es un buen modelo por defecto: funciona bien sin tuning, maneja features de distinto tipo y no se deja engañar fácilmente por outliers.

1# --- 3. ENTRENAR ---
2model = RandomForestClassifier(
3 n_estimators=100, # 100 árboles
4 random_state=42
5)
6model.fit(X_train, y_train)
7
8# Eso es todo. El modelo ya "sabe" los patrones.
9print("Modelo entrenado ✓")

Una línea entrena 100 árboles de decisión y los combina. Eso es un random forest.

Un árbol puede equivocarse. 100 árboles votando se equivocan mucho menos. Eso es el "ensemble".

### Evaluar: las métricas que importan

Accuracy (% de aciertos totales) es la métrica más conocida, pero en problemas desbalanceados es engañosa. Si el 92% de tus clientes NO cancelan, un modelo que siempre dice "no cancela" tiene un 92% de accuracy sin haber aprendido nada. Lo que importa es: de los que dije que iban a cancelar, ¿cuántos acerté? (precision) y de los que realmente cancelaron, ¿cuántos pillé? (recall).

1# --- 4. EVALUAR ---
2y_pred = model.predict(X_test)
3
4print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
5print()
6print(classification_report(y_test, y_pred, target_names=['se queda', 'churn']))
7
8# Salida típica:
9# precision recall f1-score support
10# se queda 0.97 0.99 0.98 920
11# churn 0.82 0.65 0.73 80
12# accuracy 0.96 1000

Precision: "de los que marqué como churn, ¿cuántos lo eran?". Recall: "de los que eran churn, ¿cuántos encontré?".

En churn, recall importa más que precision. Preferimos enviar un descuento a alguien que no iba a cancelar (falso positivo barato) que perder un cliente sin haberlo intentado (falso negativo caro). Ajusta el threshold de predicción para subir recall aunque baje precision.

### Interpretar: qué ha aprendido el modelo

Una ventaja del random forest sobre las redes neuronales: puedes ver qué features importan. Esto es oro para el equipo de negocio — no solo predices, sino que explicas POR QUÉ un cliente tiene riesgo.

1# --- BONUS: importancia de features ---
2importancias = pd.Series(
3 model.feature_importances_,
4 index=X.columns
5).sort_values(ascending=False)
6
7print("\nImportancia de cada feature:")
8print(importancias.to_string())
9
10# Ejemplo de output:
11# uso_semanal 0.35
12# antiguedad_meses 0.25
13# gasto_mensual 0.20
14# tickets_soporte 0.15
15# tipo_plan 0.05

feature_importances_ te dice qué variables pesan más en la decisión. Aquí "uso_semanal" es la clave.

### El código completo: 30 líneas

1"""Modelo de churn — versión completa en 30 líneas."""
2import pandas as pd
3import numpy as np
4from sklearn.datasets import make_classification
5from sklearn.model_selection import train_test_split
6from sklearn.ensemble import RandomForestClassifier
7from sklearn.metrics import classification_report
8
9# 1. Datos
10X, y = make_classification(n_samples=5000, n_features=5,
11 n_informative=3, weights=[0.92, 0.08], random_state=42)
12df = pd.DataFrame(X, columns=['antiguedad', 'gasto', 'tickets', 'uso', 'plan'])
13df['churn'] = y
14
15# 2. Split
16X_train, X_test, y_train, y_test = train_test_split(
17 df.drop('churn', axis=1), df['churn'],
18 test_size=0.2, stratify=df['churn'], random_state=42)
19
20# 3. Entrenar
21model = RandomForestClassifier(n_estimators=100, random_state=42)
22model.fit(X_train, y_train)
23
24# 4. Evaluar
25y_pred = model.predict(X_test)
26print(classification_report(y_test, y_pred, target_names=['stay', 'churn']))
27
28# 5. Interpretar
29print(pd.Series(model.feature_importances_,
30 index=X_train.columns).sort_values(ascending=False))

30 líneas. Sin magia, sin GPU, sin TensorFlow. Esto resuelve el 80% de los problemas de clasificación en empresa.

### Qué viene después

Este es el flujo básico. En un proyecto real tendrás que hacer feature engineering (crear mejores variables), cross-validation (evaluar de forma más robusta), hyperparameter tuning (ajustar los parámetros del modelo) y pensar en cómo servir el modelo en producción. Pero el esqueleto siempre es el mismo: datos → split → entrenar → evaluar.

Si te ha picado la curiosidad, el siguiente paso natural es probar con datos reales de tu empresa o con datasets públicos de Kaggle. Cambia el modelo (LogisticRegression, GradientBoosting), cambia las features, ajusta el threshold. El aprendizaje de verdad viene de experimentar, no de leer.

Consejo de veterano: antes de complicar el modelo, complica los datos. Feature engineering bueno con un random forest básico gana al mejor XGBoost con features malos. Primero invierte tiempo en entender el problema y crear variables que lo representen bien.

$ whoami

Regístrate gratis para dar like, guardar posts en carpetas y recibir nuevos artículos por email.

Leer está bien. Ejecutar está mejor.

## comentarios

¿Te ha servido? ¿Añadirías algo? ¿Lo has vivido de otra forma en tu trabajo? Cuéntalo.

Inicia sesión para comentar y responder.

cargando comentarios...