sk_churn_model.py en Python
Un modelo de punta a punta: dividir, preprocesar por tipo de columna, grid search, reporte.
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.metrics import classification_report, roc_auc_score
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
NUMERICAS = [0, 1, 2]
CATEGORICAS = [3]
def crear_datos(filas=600, semilla=0):
"""Antigüedad, gasto mensual, llamadas a soporte y un plan."""
rng = np.random.default_rng(semilla)
antiguedad = rng.integers(1, 72, size=filas)
gasto = rng.normal(70, 25, size=filas).clip(10, None)
llamadas = rng.poisson(1.2, size=filas)
plan = rng.choice(["basico", "plus", "pro"], size=filas)
riesgo = (0.03 * llamadas + 0.02 * (gasto / 50) - 0.02 * (antiguedad / 12)
+ (plan == "basico") * 0.15)
abandono = (rng.random(filas) < riesgo.clip(0.02, 0.9)).astype(int)
X = np.empty((filas, 4), dtype=object)
X[:, 0], X[:, 1], X[:, 2], X[:, 3] = antiguedad, gasto, llamadas, plan
return X, abandono
def armar_pipeline():
numerico = Pipeline([
("impute", SimpleImputer(strategy="median")),
("scale", StandardScaler()),
])
preparador = ColumnTransformer([
("numeric", numerico, NUMERICAS),
("categorical", OneHotEncoder(handle_unknown="ignore"), CATEGORICAS),
])
return Pipeline([
("prepare", preparador),
("model", RandomForestClassifier(random_state=0)),
])
def main():
X, y = crear_datos()
X_entreno, X_prueba, y_entreno, y_prueba = train_test_split(
X, y, test_size=0.25, random_state=0, stratify=y)
malla = {
"model__n_estimators": [100, 300],
"model__max_depth": [4, 8, None],
"model__min_samples_leaf": [1, 5],
}
busqueda = GridSearchCV(armar_pipeline(), malla, cv=4, scoring="roc_auc",
n_jobs=1)
busqueda.fit(X_entreno, y_entreno)
print("mejores parámetros")
for clave, valor in sorted(busqueda.best_params_.items()):
print(f" {clave:28} {valor}")
print(f"auc valid. cruzada {busqueda.best_score_:.3f}")
mejor = busqueda.best_estimator_
probabilidades = mejor.predict_proba(X_prueba)[:, 1]
print(f"auc datos apartados {roc_auc_score(y_prueba, probabilidades):.3f}")
print(classification_report(y_prueba, mejor.predict(X_prueba), digits=3))
nombres = mejor.named_steps["prepare"].get_feature_names_out()
pesos = mejor.named_steps["model"].feature_importances_
orden = np.argsort(pesos)[::-1]
print("lo que importó")
for i in orden[:5]:
print(f" {nombres[i]:28} {pesos[i]:.3f}")
if __name__ == "__main__":
main()
Cómo funciona
- El ColumnTransformer mantiene separados los caminos numérico y categórico.
- GridSearchCV valida en cruzado cada combinación dentro del pipeline.
- El conjunto reservado se evalúa una vez, al final, y nunca se ajusta contra él.
Palabras clave y builtins usados aquí
asdefforifintobjectprintreturnsorted
El intento, en números
- Líneas
- 79
- Caracteres a escribir
- 2503
- Tokens
- 666
- Ritmo de tres estrellas
- 115 tpm
Al ritmo de tres estrellas de 115 tokens por minuto, este intento toma unos 347 segundos.
Paso 1 de 1 en Bis; paso 25 de 25 en Machine learning con scikit-learn.