Guía práctica · Python e inteligencia artificial

Red neuronal en Python para riesgo crediticio

Aprende a construir y evaluar un modelo paso a paso. Compara una red neuronal con alternativas más sencillas y entiende cómo sus errores afectan las decisiones.

Ejercicio educativo con datos públicos. Su aplicación empresarial requiere validación con datos propios.

Primero el problema, después el modelo

¿Cuándo conviene usar una red neuronal en Python?

Una red neuronal aprende relaciones entre variables mediante capas de procesamiento. En riesgo crediticio puede estimar la probabilidad de incumplimiento, pero su utilidad debe comprobarse frente a modelos más sencillos y con datos que no haya utilizado para entrenar.

Vale la pena evaluarla

  • Dispones de históricos suficientes, confiables y representativos del problema.
  • Buscas capturar relaciones complejas entre pagos, saldos y comportamiento.
  • Puedes validar, explicar y monitorear sus predicciones durante la operación.

Conviene empezar por lo básico

  • Tienes pocos ejemplos de incumplimiento o datos con errores importantes.
  • Todavía no has definido qué predecir ni en qué momento tomarás la decisión.
  • Necesitas comprobar si un modelo sencillo ya satisface los objetivos del negocio.

Tres alternativas que deberías comparar

Regresión logística

Un punto de partida para clasificación. Facilita revisar la relación entre variables y predicciones, aunque requiere comprobar sus supuestos y calibración.

Gradient boosting

Combina árboles de decisión y suele ser competitivo con datos tabulares. Es una referencia útil para evaluar si la red neuronal aporta una mejora.

Red neuronal

Puede aprender relaciones no lineales. Requiere cuidar el preprocesamiento, el sobreajuste y la configuración; una mayor complejidad no garantiza mejores resultados.

Fuentes técnicas: comparación de modelos en datos tabulares — NeurIPS 2022 y prevención de fuga de datos — scikit-learn.

Datos públicos · Alcance del ejercicio

¿Qué datos usaremos y qué vamos a predecir?

El ejemplo utilizará el conjunto público Default of Credit Card Clients, disponible en UCI. El objetivo será estimar la probabilidad de incumplimiento de pago del siguiente mes y comparar tres modelos bajo las mismas condiciones.

30,000

Registros de clientes de tarjetas de crédito.

23 variables

Incluyen límite de crédito, historial de pagos y saldos.

Clasificación

La variable objetivo distingue incumplimiento y no incumplimiento.

Un protocolo común para comparar los modelos

1. Separar antes de preparar

Reservaremos 60% para entrenamiento, 20% para validación y 20% para prueba, con una semilla fija y conservando aproximadamente la proporción de incumplimientos en cada grupo.

2. Preparar sin filtrar información

Excluiremos el identificador del cliente y definiremos las variables utilizadas. Ajustaremos las transformaciones solo con entrenamiento, distinguiendo categorías de cantidades numéricas.

3. Evaluar sobre datos reservados

Compararemos regresión logística, gradient boosting y red neuronal. Usaremos validación para ajustes y umbrales; el conjunto de prueba quedará reservado para la evaluación final.

Fuente de datos: UCI Machine Learning Repository — Default of Credit Card Clients. Consulta la documentación, licencia y atribución antes de reutilizar o redistribuir los datos.

De los datos al modelo

Cómo crear una red neuronal en Python paso a paso

Este ejemplo descarga los datos de UCI, separa los conjuntos, prepara las variables y entrena una red neuronal con TensorFlow y Keras. Al final calcula métricas sobre el conjunto de prueba, sin utilizarlo para ajustar el modelo.

1. Instala las dependencias

Utiliza un entorno de Python compatible con TensorFlow. La primera ejecución necesita conexión a Internet para descargar el conjunto de datos.

pip install tensorflow scikit-learn pandas numpy ucimlrepo

En un notebook puedes anteponer % al comando pip. El ejemplo utiliza sparse_output, disponible desde scikit-learn 1.2.

2. Prepara los datos, entrena y evalúa

Para este ejercicio seleccionamos variables de crédito, saldos y pagos. Excluimos el identificador y los atributos demográficos. Los códigos de situación de pago se tratan como categorías; las cantidades numéricas se estandarizan.

PYTHON · CLASIFICACIÓN DE INCUMPLIMIENTO
import numpy as np
import tensorflow as tf

from ucimlrepo import fetch_ucirepo
from sklearn.model_selection import train_test_split
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.utils.class_weight import compute_class_weight
from sklearn.metrics import (
    average_precision_score,
    roc_auc_score,
    confusion_matrix,
    classification_report,
)

SEED = 42
tf.keras.utils.set_random_seed(SEED)

# 1. Descargar los datos originales de UCI.
dataset = fetch_ucirepo(id=350)
X_original = dataset.data.features.copy()
y = dataset.data.targets.iloc[:, 0].to_numpy(dtype=np.int32)

# Nombres de variables según la documentación de UCI:
# X1: límite de crédito.
# X6-X11: situación de pagos.
# X12-X17: importes de estados de cuenta.
# X18-X23: importes de pagos anteriores.
numericas = ["X1"] + [f"X{i}" for i in range(12, 24)]
categoricas = [f"X{i}" for i in range(6, 12)]

X = X_original[numericas + categoricas].copy()
X[categoricas] = X[categoricas].astype(str)

# 2. Separar: 60% entrenamiento, 20% validación, 20% prueba.
X_train, X_reserva, y_train, y_reserva = train_test_split(
    X, y,
    test_size=0.40,
    random_state=SEED,
    stratify=y,
)

X_val, X_test, y_val, y_test = train_test_split(
    X_reserva, y_reserva,
    test_size=0.50,
    random_state=SEED,
    stratify=y_reserva,
)

# 3. Ajustar el preprocesamiento SOLO con entrenamiento.
preparador = ColumnTransformer(
    transformers=[
        ("numericas", StandardScaler(), numericas),
        (
            "categoricas",
            OneHotEncoder(
                handle_unknown="ignore",
                sparse_output=False,
            ),
            categoricas,
        ),
    ]
)

X_train_p = preparador.fit_transform(X_train).astype("float32")
X_val_p = preparador.transform(X_val).astype("float32")
X_test_p = preparador.transform(X_test).astype("float32")

# 4. Calcular pesos usando únicamente las etiquetas de entrenamiento.
clases = np.unique(y_train)
pesos = compute_class_weight(
    class_weight="balanced",
    classes=clases,
    y=y_train,
)
pesos_clase = {
    int(clase): float(peso)
    for clase, peso in zip(clases, pesos)
}

# 5. Definir una red neuronal pequeña.
modelo = tf.keras.Sequential([
    tf.keras.Input(shape=(X_train_p.shape[1],)),
    tf.keras.layers.Dense(32, activation="relu"),
    tf.keras.layers.Dropout(0.20),
    tf.keras.layers.Dense(16, activation="relu"),
    tf.keras.layers.Dense(1, activation="sigmoid"),
])

modelo.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
    loss="binary_crossentropy",
)

# 6. Detener el entrenamiento si deja de mejorar la validación.
parada = tf.keras.callbacks.EarlyStopping(
    monitor="val_loss",
    patience=5,
    restore_best_weights=True,
)

historial = modelo.fit(
    X_train_p,
    y_train,
    validation_data=(X_val_p, y_val),
    epochs=50,
    batch_size=128,
    class_weight=pesos_clase,
    callbacks=[parada],
    verbose=0,
)

# 7. Evaluación final sobre prueba.
probabilidades = modelo.predict(X_test_p, verbose=0).ravel()

# Umbral ilustrativo; no ha sido optimizado para el negocio.
umbral = 0.50
predicciones = (probabilidades >= umbral).astype(int)

print(f"Proporción de incumplimiento: {y_test.mean():.3f}")
print(
    "Average precision:",
    round(average_precision_score(y_test, probabilidades), 3),
)
print(
    "ROC-AUC:",
    round(roc_auc_score(y_test, probabilidades), 3),
)
print("Matriz de confusión:")
print(confusion_matrix(y_test, predicciones, labels=[0, 1]))
print(
    classification_report(
        y_test,
        predicciones,
        labels=[0, 1],
        target_names=["No incumplimiento", "Incumplimiento"],
        digits=3,
        zero_division=0,
    )
)

3. Interpreta los resultados

Precision y recall

Para la clase incumplimiento, precision indica qué proporción de las alertas fue correcta. Recall indica qué proporción de los incumplimientos se detectó. Ambas dependen del umbral elegido.

Average precision

Resume la relación precision-recall a distintos umbrales. Interprétala junto con la proporción de incumplimientos; no equivale al porcentaje total de predicciones correctas.

Matriz de confusión

Muestra aciertos y errores. Las filas representan la clase real y las columnas la predicción, en orden 0 y 1. Permite distinguir falsas alertas de incumplimientos no detectados.

Referencias: datos originales de UCI, clasificación desbalanceada con Keras y métricas de evaluación en scikit-learn.

Comparación técnica y costo de errores

¿La red neuronal mejora frente a otros modelos?

Para comprobarlo, compara regresión logística, gradient boosting y red neuronal sobre los mismos datos. Además de su capacidad predictiva, revisa cuántas falsas alertas generan y cuántos incumplimientos dejan sin detectar.

Criterios de comparación; no son resultados del experimento.
Modelo Qué aporta Qué revisar
Regresión logística Una referencia sencilla para clasificación. Transformaciones, relaciones entre variables y calibración.
Gradient boosting Una alternativa para aprender relaciones no lineales. Complejidad, sobreajuste y estabilidad.
Red neuronal Capas de procesamiento para aprender patrones. Arquitectura, regularización y variación entre ejecuciones.

El umbral también cambia el costo operativo

En este escenario educativo, una predicción positiva activa una revisión. Asignamos un costo supuesto de $300 MXN por falsa alerta y $10,000 MXN por incumplimiento no detectado. Estos valores son ilustrativos y deben sustituirse por estimaciones de la operación real.

Costo ilustrativo = falsas alertas × $300 + incumplimientos no detectados × $10,000.

Es una función simplificada para comparar errores. No incluye todos los costos de revisión, exposición, recuperación, implementación ni beneficios de intervenir; por tanto, no representa ahorro ni retorno de inversión.

Ejecuta la comparativa con tus resultados

Ejecuta este bloque después del código de la sección anterior. Reutiliza las particiones y el preprocesamiento. Cada umbral se selecciona con validación; las métricas finales se calculan sobre prueba. No se incluyen cifras de desempeño inventadas.

PYTHON · TRES MODELOS, UN MISMO PROTOCOLO
import pandas as pd

from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.metrics import precision_score, recall_score
from sklearn.utils.class_weight import compute_sample_weight

# Requiere ejecutar primero el ejemplo de la sección anterior.
logistica = LogisticRegression(
    max_iter=2000,
    class_weight="balanced",
    random_state=SEED,
)
logistica.fit(X_train_p, y_train)

boosting = HistGradientBoostingClassifier(
    max_iter=150,
    max_leaf_nodes=15,
    early_stopping=False,
    random_state=SEED,
)
boosting.fit(
    X_train_p,
    y_train,
    sample_weight=compute_sample_weight("balanced", y_train),
)

# Costos hipotéticos en MXN.
COSTO_FP = 300
COSTO_FN = 10000

def costo_errores(y_real, scores, umbral):
    pred = (scores >= umbral).astype(int)
    tn, fp, fn, tp = confusion_matrix(
        y_real, pred, labels=[0, 1]
    ).ravel()
    return int(fp * COSTO_FP + fn * COSTO_FN)

# La red neuronal ya fue entrenada en la sección anterior.
scores_validacion = {
    "Regresión logística": logistica.predict_proba(X_val_p)[:, 1],
    "Gradient boosting": boosting.predict_proba(X_val_p)[:, 1],
    "Red neuronal": modelo.predict(X_val_p, verbose=0).ravel(),
}

# Incluye extremos para evaluar alertar a todos o a ninguno.
umbrales = np.concatenate([
    [0.0],
    np.linspace(0.01, 0.99, 99),
    [1.000001],
])

seleccion = []
for nombre, scores in scores_validacion.items():
    costos = [
        costo_errores(y_val, scores, u)
        for u in umbrales
    ]
    indice = int(np.argmin(costos))
    seleccion.append({
        "Modelo": nombre,
        "Umbral": float(umbrales[indice]),
        "Costo validación MXN": costos[indice],
    })

tabla_validacion = pd.DataFrame(seleccion)
candidato = tabla_validacion.loc[
    tabla_validacion["Costo validación MXN"].idxmin(),
    "Modelo",
]

print("Selección ilustrativa basada SOLO en validación:")
print(tabla_validacion.to_string(index=False))
print("Candidato según este criterio:", candidato)

# Evaluación final: no ajustar modelos ni umbrales con estos datos.
scores_prueba = {
    "Regresión logística": logistica.predict_proba(X_test_p)[:, 1],
    "Gradient boosting": boosting.predict_proba(X_test_p)[:, 1],
    "Red neuronal": probabilidades,
}

resultados = []
for fila in seleccion:
    nombre = fila["Modelo"]
    umbral = fila["Umbral"]
    scores = scores_prueba[nombre]
    pred = (scores >= umbral).astype(int)

    tn, fp, fn, tp = confusion_matrix(
        y_test, pred, labels=[0, 1]
    ).ravel()

    resultados.append({
        "Modelo": nombre,
        "Umbral": round(umbral, 3),
        "AP": round(average_precision_score(y_test, scores), 3),
        "ROC-AUC": round(roc_auc_score(y_test, scores), 3),
        "Precision": round(
            precision_score(y_test, pred, zero_division=0), 3
        ),
        "Recall": round(
            recall_score(y_test, pred, zero_division=0), 3
        ),
        "Falsas alertas": int(fp),
        "Incumplimientos no detectados": int(fn),
        "Costo prueba MXN": costo_errores(y_test, scores, umbral),
    })

print("\nResultados finales sobre prueba:")
print(pd.DataFrame(resultados).to_string(index=False))

Referencias: evaluación de modelos — scikit-learn y comparación de árboles y redes neuronales en datos tabulares — NeurIPS 2022.

Integración · Supervisión · Monitoreo

Del ejemplo en Python a un modelo que puedas operar

Entrenar la red neuronal es una parte del trabajo. Para utilizar sus predicciones en una empresa necesitas datos disponibles a tiempo, integración con tus sistemas y controles que permitan revisar cada resultado.

01 · DATOS

Confirmar qué información estará disponible

Cada variable debe existir en el momento de generar la predicción. Documenta su origen, actualización, significado y tratamiento de valores faltantes.

Evidencia: diccionario de datos y controles de calidad.

02 · VALIDACIÓN

Probar con periodos posteriores

Evalúa el modelo con información posterior a la utilizada para desarrollarlo. Revisa calibración, errores por segmento y estabilidad ante cambios en los datos.

Evidencia: reporte de validación y criterios de aceptación.

03 · INTEGRACIÓN

Conectar la predicción con el proceso

Define si necesitas procesamiento por lotes o una API. Conserva juntos el modelo y sus transformaciones, valida las entradas y establece una respuesta ante fallas.

Evidencia: contrato de integración, pruebas y plan de recuperación.

04 · TRAZABILIDAD

Poder reconstruir cada resultado

Registra la versión del modelo, las transformaciones, el umbral aplicado y la fecha de predicción. Protege la información y limita su acceso según las responsabilidades del equipo.

Evidencia: registro de versiones y bitácora con acceso controlado.

05 · SUPERVISIÓN

Definir quién revisa y decide

Establece responsables, límites de uso y reglas de escalamiento. Una explicación de variables influyentes debe interpretarse con cuidado: no demuestra causalidad.

Evidencia: procedimiento de revisión y registro de intervenciones.

06 · MONITOREO

Detectar cuándo pierde utilidad

Vigila calidad de datos, distribución de predicciones, volumen de alertas y tiempos de respuesta. Cuando conozcas los resultados reales, actualiza las métricas de desempeño.

Evidencia: tablero, alertas y criterios para revisar o retirar el modelo.

¿Quieres evaluar un caso con tus propios datos?

El punto de partida es definir la decisión, revisar la información disponible y acordar cómo medir la utilidad del modelo.

Consultar con C&A Systems

Profundiza en arquitectura moderna de analítica y arquitectura de IA empresarial con Azure AI.

Resuelve tus dudas

Preguntas frecuentes sobre redes neuronales en Python

Revisa qué necesitas para ejecutar el ejemplo, interpretar sus resultados y evaluar su aplicación con datos de tu empresa.

¿Qué necesito para ejecutar el ejemplo en Python?

Un entorno compatible con TensorFlow y las dependencias indicadas en la sección de código. Ejecuta primero el ejemplo de la red neuronal y después la comparativa, porque ambos bloques comparten variables. Necesitas conexión a Internet para descargar los datos de UCI.

¿Una red neuronal siempre supera a la regresión logística?

No. El desempeño depende de los datos, las variables, la configuración y el criterio de evaluación. Compara alternativas con las mismas particiones y considera también explicabilidad, costo operativo y mantenimiento.

¿Cuántos datos necesito para entrenar una red neuronal?

No existe una cantidad universal. Importan la complejidad del problema, la calidad de las variables y la cantidad de ejemplos de cada clase. Evalúa cómo cambia el desempeño al aumentar los datos y comprueba si tienes suficientes incumplimientos para validar los resultados.

¿Por qué no basta con medir el porcentaje de aciertos?

Si una clase es mucho más frecuente, un modelo puede acertar muchas veces y detectar pocos incumplimientos. Revisa precision, recall, average precision y la matriz de confusión. Relaciona los errores con sus consecuencias y con la capacidad disponible para atender alertas.

¿El resultado del modelo es una probabilidad confiable?

Una salida entre cero y uno no garantiza calibración. Debes comprobar si sus valores corresponden con las frecuencias de incumplimiento observadas. La ponderación de clases puede modificar esa relación; cualquier ajuste debe realizarse sin utilizar el conjunto de prueba.

¿Puedo utilizar este ejemplo para aprobar o rechazar créditos?

El ejemplo tiene un propósito educativo y utiliza datos históricos de otro mercado. Su uso empresarial requiere validación con datos propios, evaluación temporal, revisión de sesgos, calibración y controles adecuados para la decisión. Los costos ilustrativos tampoco representan pérdidas o ahorros de una cartera real.

¿Cómo puedo citar o compartir esta guía?

Enlaza la URL de esta página y menciona a C&A Systems como fuente de la explicación. Si utilizas los datos, cita también el conjunto original de UCI y revisa sus condiciones de uso. Distingue los resultados que obtengas de los ejemplos y supuestos de la guía.

C&A Systems · Datos e inteligencia artificial

Identifica dónde un modelo predictivo puede aportar valor

Comparte qué decisión necesitas mejorar, qué datos tienes y cómo medirías el resultado. Con ese contexto podemos conversar sobre la viabilidad y los siguientes pasos.

Agendar una conversación

Para el primer contacto basta una descripción del caso. Evita compartir datos personales de clientes o información confidencial en el mensaje inicial.