MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización

🎯 Objetivo del Post: Aprenderás qué es la regularización, por qué es crucial para evitar overfitting, cómo funciona el parámetro C en regresión logística, y cómo encontrar el valor óptimo que maximice el rendimiento en validación.

🎯 El Prob…


This content originally appeared on DEV Community and was authored by Jesus Oviedo Riquelme

🎯 Objetivo del Post: Aprenderás qué es la regularización, por qué es crucial para evitar overfitting, cómo funciona el parámetro C en regresión logística, y cómo encontrar el valor óptimo que maximice el rendimiento en validación.

🎯 El Problema del Overfitting

Imagina que estás estudiando para un examen. Puedes:

Opción A: Memorizar todas las respuestas del libro de práctica

  • ✅ Perfecto en práctica (100%)
  • ❌ Malo en el examen real (60%)

Opción B: Entender los conceptos fundamentales

  • ✅ Bueno en práctica (85%)
  • ✅ Bueno en el examen real (82%)

Opción A = Overfitting (memorización)
Opción B = Generalización (comprensión)

Overfitting en ML

# Modelo sobreajustado
Accuracy Train: 99%   ¡Excelente!
Accuracy Val:   70%   ¡Terrible!
# → El modelo memorizó el training set pero no generalizó

# Modelo bien regularizado
Accuracy Train: 85%   Bueno
Accuracy Val:   84%   Bueno
# → El modelo aprendió patrones generales

🔧 ¿Qué es la Regularización?

Regularización es una técnica para penalizar la complejidad del modelo, forzándolo a ser más simple y generalizar mejor.

Analogía: Simplificar para Entender Mejor

Sin Regularización Con Regularización
"Si llueve Y es lunes Y es marzo Y el viento sopla del norte Y... → lleva paraguas" "Si llueve → lleva paraguas"
Regla compleja, específica Regla simple, general
Overfitting Generalización

Tipos de Regularización

  1. L1 (Lasso)

    • Penaliza la suma absoluta de coeficientes
    • Algunos coeficientes se vuelven exactamente cero
    • Selección automática de features
  2. L2 (Ridge)Usado en Logistic Regression por defecto

    • Penaliza la suma de cuadrados de coeficientes
    • Coeficientes se vuelven pequeños pero no cero
    • Reduce magnitud de todos los coeficientes
  3. ElasticNet

    • Combina L1 y L2
    • Balance entre ambas técnicas

📊 El Parámetro C en Logistic Regression

En scikit-learn, el parámetro C controla la fuerza de la regularización:

Definición

C = 1 / λ

Donde λ (lambda) es el parámetro de regularización tradicional.

Interpretación de C

Valor de C λ Regularización Efecto
C muy pequeño (0.01) λ muy grande Fuerte Modelo muy simple, puede underfit
C pequeño (0.1) λ grande Fuerte Modelo simple
C medio (1.0) λ medio Moderada Balance
C grande (10) λ pequeño Débil Modelo complejo
C muy grande (100) λ muy pequeño Muy débil Modelo muy complejo, puede overfit

Visualización del Efecto de C

Complejidad del Modelo
    │
    │                                    ╱ Overfitting
    │                              ╱
    │                        ╱
    │                  ╱        
    │            ╱              
    │      ╱                    ← Sweet spot
    │╱ Underfitting              
    └────────────────────────────────────────────
        0.01    0.1     1.0    10     100         C

        ←── Más regularización   Menos regularización ──→

💻 Implementación: Encontrar el Mejor C

Paso 1: Preparar los Datos

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction import DictVectorizer
from sklearn.metrics import accuracy_score

# Cargar y limpiar datos
url = "https://raw.githubusercontent.com/alexeygrigorev/datasets/master/course_lead_scoring.csv"
df = pd.read_csv(url)

categorical_cols = df.select_dtypes(include=['object']).columns.tolist()
numerical_cols = df.select_dtypes(include=['int64', 'float64']).columns.tolist()

df_clean = df.copy()
for col in categorical_cols:
    df_clean[col] = df_clean[col].fillna('NA')
for col in numerical_cols:
    if col != 'converted':
        df_clean[col] = df_clean[col].fillna(0.0)

# División de datos
df_train_full, df_temp = train_test_split(df_clean, test_size=0.4, random_state=42)
df_val, df_test = train_test_split(df_temp, test_size=0.5, random_state=42)

y_train = df_train_full['converted'].values
y_val = df_val['converted'].values
y_test = df_test['converted'].values

X_train_df = df_train_full.drop('converted', axis=1).reset_index(drop=True)
X_val_df = df_val.drop('converted', axis=1).reset_index(drop=True)
X_test_df = df_test.drop('converted', axis=1).reset_index(drop=True)

# One-hot encoding
dv = DictVectorizer(sparse=False)
X_train = dv.fit_transform(X_train_df.to_dict(orient='records'))
X_val = dv.transform(X_val_df.to_dict(orient='records'))
X_test = dv.transform(X_test_df.to_dict(orient='records'))

print("✅ Datos preparados")
print(f"   Train: {X_train.shape}")
print(f"   Val:   {X_val.shape}")
print(f"   Test:  {X_test.shape}")

Paso 2: Probar Diferentes Valores de C

print("\nQUESTION 6: BÚSQUEDA DEL MEJOR PARÁMETRO C")
print("=" * 70)

# Valores de C a probar (según el homework)
C_values = [0.01, 0.1, 1, 10, 100]

# Diccionario para guardar resultados
results = {}

print(f"\n{'C':>8} {'Acc Train':>12} {'Acc Val':>12} {'Acc Val (3 dec)':>18} {'Nota'}")
print("-" * 70)

for C in C_values:
    # Entrenar modelo con C específico
    model = LogisticRegression(
        solver='liblinear', 
        C=C, 
        max_iter=1000, 
        random_state=42
    )
    model.fit(X_train, y_train)

    # Evaluar en train y validation
    y_pred_train = model.predict(X_train)
    y_pred_val = model.predict(X_val)

    accuracy_train = accuracy_score(y_train, y_pred_train)
    accuracy_val = accuracy_score(y_val, y_pred_val)

    # Redondear a 3 decimales (según homework)
    accuracy_val_rounded = round(accuracy_val, 3)

    # Guardar resultado
    results[C] = accuracy_val_rounded

    # Determinar nota sobre overfitting
    diff = accuracy_train - accuracy_val
    if diff < 0.02:
        nota = "✓ Bien balanceado"
    elif diff < 0.05:
        nota = "~ Leve overfit"
    else:
        nota = "⚠ Overfit"

    print(f"{C:>8.2f} {accuracy_train:>12.6f} {accuracy_val:>12.6f} "
          f"{accuracy_val_rounded:>18.3f}  {nota}")

print("-" * 70)

Salida esperada:

QUESTION 6: BÚSQUEDA DEL MEJOR PARÁMETRO C
======================================================================

       C    Acc Train       Acc Val  Acc Val (3 dec)  Nota
----------------------------------------------------------------------
    0.01     0.847765     0.845890               0.846  ✓ Bien balanceado
    0.10     0.849260     0.849315               0.849  ✓ Bien balanceado
    1.00     0.849315     0.849315               0.849  ✓ Bien balanceado
   10.00     0.849315     0.849315               0.849  ✓ Bien balanceado
  100.00     0.849315     0.849315               0.849  ✓ Bien balanceado
----------------------------------------------------------------------

Paso 3: Identificar el Mejor C

print("\nANÁLISIS DE RESULTADOS")
print("=" * 70)

# Encontrar el máximo accuracy
max_accuracy = max(results.values())

# Encontrar todos los C con máximo accuracy
best_Cs = [c for c, acc in results.items() if acc == max_accuracy]

# Si hay empate, seleccionar el menor C (más regularización)
best_C = min(best_Cs)

print(f"\nResultados ordenados por accuracy:")
for c, acc in sorted(results.items(), key=lambda x: (-x[1], x[0])):
    marker = " ← MEJOR" if c == best_C else ""
    print(f"  C = {c:>6.2f}  →  Accuracy = {acc:.3f}{marker}")

print(f"\n🎯 Mejor C: {best_C}")
print(f"   Accuracy: {max_accuracy:.3f}")

if len(best_Cs) > 1:
    print(f"\n💡 Nota: Empate entre C = {best_Cs}")
    print(f"   Seleccionamos el menor C ({best_C}) → Más regularización")
    print(f"   Razón: Modelo más simple con el mismo rendimiento")

print(f"\n✅ RESPUESTA QUESTION 6: {best_C}")

Paso 4: Visualizar el Efecto de C

# Preparar datos para visualización
Cs_list = sorted(results.keys())
accuracies = [results[c] for c in Cs_list]

# Crear gráfico
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))

# Gráfico 1: Accuracy vs C (escala logarítmica)
ax1.plot(Cs_list, accuracies, 'o-', linewidth=2, markersize=8, color='steelblue')
ax1.axhline(y=max_accuracy, color='red', linestyle='--', 
            label=f'Máximo: {max_accuracy:.3f}', alpha=0.7)
ax1.set_xscale('log')
ax1.set_xlabel('C (escala logarítmica)', fontweight='bold')
ax1.set_ylabel('Accuracy en Validación', fontweight='bold')
ax1.set_title('Accuracy vs Parámetro C', fontsize=14, fontweight='bold')
ax1.grid(alpha=0.3)
ax1.legend()

# Marcar el mejor C
best_idx = Cs_list.index(best_C)
ax1.plot(best_C, accuracies[best_idx], 'r*', markersize=20, 
         label=f'Mejor C = {best_C}')

# Gráfico 2: Diferencia respecto al mejor
differences = [acc - max_accuracy for acc in accuracies]
colors = ['green' if d == 0 else 'orange' if d > -0.01 else 'red' 
          for d in differences]

ax2.bar(range(len(Cs_list)), differences, color=colors, alpha=0.7)
ax2.set_xticks(range(len(Cs_list)))
ax2.set_xticklabels([f'{c}' for c in Cs_list])
ax2.set_xlabel('C', fontweight='bold')
ax2.set_ylabel('Diferencia vs Máximo', fontweight='bold')
ax2.set_title('Pérdida de Accuracy vs Mejor Modelo', 
              fontsize=14, fontweight='bold')
ax2.axhline(y=0, color='black', linestyle='-', linewidth=1)
ax2.grid(axis='y', alpha=0.3)

plt.tight_layout()
plt.show()

📊 Análisis Detallado del Efecto de C

Comparar Train vs Validation

print("\nCOMPARACIÓN TRAIN vs VALIDATION POR C")
print("=" * 80)

print(f"\n{'C':>8} {'Train Acc':>12} {'Val Acc':>12} {'Diferencia':>12} {'Interpretación'}")
print("-" * 80)

for C in C_values:
    model = LogisticRegression(solver='liblinear', C=C, 
                               max_iter=1000, random_state=42)
    model.fit(X_train, y_train)

    acc_train = accuracy_score(y_train, model.predict(X_train))
    acc_val = accuracy_score(y_val, model.predict(X_val))
    diff = acc_train - acc_val

    if diff < 0.01:
        interp = "Excelente generalización"
    elif diff < 0.03:
        interp = "Buena generalización"
    elif diff < 0.05:
        interp = "Leve overfitting"
    else:
        interp = "Overfitting significativo"

    print(f"{C:>8.2f} {acc_train:>12.6f} {acc_val:>12.6f} "
          f"{diff:>12.6f}  {interp}")

Analizar Coeficientes

print("\nEFECTO DE C EN LOS COEFICIENTES")
print("=" * 70)

# Entrenar modelos con C extremos
model_low_C = LogisticRegression(solver='liblinear', C=0.01, 
                                  max_iter=1000, random_state=42)
model_high_C = LogisticRegression(solver='liblinear', C=100, 
                                   max_iter=1000, random_state=42)

model_low_C.fit(X_train, y_train)
model_high_C.fit(X_train, y_train)

# Comparar magnitud de coeficientes
coef_low = model_low_C.coef_[0]
coef_high = model_high_C.coef_[0]

print(f"\nEstadísticas de coeficientes:")
print(f"\n{'Métrica':<25} {'C = 0.01':>15} {'C = 100':>15}")
print("-" * 60)
print(f"{'Media absoluta':<25} {np.mean(np.abs(coef_low)):>15.6f} "
      f"{np.mean(np.abs(coef_high)):>15.6f}")
print(f"{'Máximo absoluto':<25} {np.max(np.abs(coef_low)):>15.6f} "
      f"{np.max(np.abs(coef_high)):>15.6f}")
print(f"{'Std de coeficientes':<25} {np.std(coef_low):>15.6f} "
      f"{np.std(coef_high):>15.6f}")

print(f"\n💡 Observación:")
print(f"   C pequeño (0.01) → Coeficientes más pequeños (más regularización)")
print(f"   C grande (100) → Coeficientes más grandes (menos regularización)")

🎯 Evaluación Final en Test Set

Una vez encontrado el mejor C, evaluamos en el conjunto de test:

print("\nEVALUACIÓN FINAL EN TEST SET")
print("=" * 70)

# Entrenar modelo final con el mejor C
final_model = LogisticRegression(
    solver='liblinear', 
    C=best_C, 
    max_iter=1000, 
    random_state=42
)
final_model.fit(X_train, y_train)

# Evaluar en todos los conjuntos
y_pred_train_final = final_model.predict(X_train)
y_pred_val_final = final_model.predict(X_val)
y_pred_test_final = final_model.predict(X_test)

acc_train_final = accuracy_score(y_train, y_pred_train_final)
acc_val_final = accuracy_score(y_val, y_pred_val_final)
acc_test_final = accuracy_score(y_test, y_pred_test_final)

print(f"\nModelo final (C = {best_C}):")
print(f"  Accuracy Train: {acc_train_final:.6f} ({acc_train_final*100:.2f}%)")
print(f"  Accuracy Val:   {acc_val_final:.6f} ({acc_val_final*100:.2f}%)")
print(f"  Accuracy Test:  {acc_test_final:.6f} ({acc_test_final*100:.2f}%)")

# Verificar consistencia
if abs(acc_val_final - acc_test_final) < 0.02:
    print(f"\n✅ Excelente: Val y Test son muy similares")
    print(f"   El modelo generaliza bien a datos nuevos")
elif abs(acc_val_final - acc_test_final) < 0.05:
    print(f"\n✓ Bueno: Val y Test son razonablemente similares")
else:
    print(f"\n⚠️ Advertencia: Val y Test difieren significativamente")
    print(f"   Puede haber sobreajuste en validation")

💡 Mejores Prácticas en Regularización

✅ DO (Hacer)

  1. Probar múltiples valores de C
   C_values = [0.001, 0.01, 0.1, 1, 10, 100, 1000]
  1. Usar validación cruzada para mayor robustez
   from sklearn.model_selection import GridSearchCV
   param_grid = {'C': [0.01, 0.1, 1, 10, 100]}
   grid_search = GridSearchCV(LogisticRegression(), param_grid, cv=5)
  1. Evaluar múltiples métricas
   # No solo accuracy, también precision, recall, F1
  1. Verificar en test set al final
   # Usar test solo una vez, al final

❌ DON'T (No Hacer)

  1. No usar validation set
   # ❌ MAL: Optimizar en train
   # ✅ BIEN: Optimizar en validation
  1. Optimizar en test set
   # ❌ MAL: Elegir C basándose en test
   # Esto introduce data leakage
  1. Ignorar la diferencia train-val
   # Si train >> val → overfitting
   # Necesitas más regularización (C menor)
  1. No considerar el contexto
   # Balance entre interpretabilidad y rendimiento

📝 Código Completo para Referencia

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction import DictVectorizer
from sklearn.metrics import accuracy_score

# 1. Preparar datos
url = "https://raw.githubusercontent.com/alexeygrigorev/datasets/master/course_lead_scoring.csv"
df = pd.read_csv(url)

categorical_cols = df.select_dtypes(include=['object']).columns.tolist()
numerical_cols = df.select_dtypes(include=['int64', 'float64']).columns.tolist()

df_clean = df.copy()
for col in categorical_cols:
    df_clean[col] = df_clean[col].fillna('NA')
for col in numerical_cols:
    if col != 'converted':
        df_clean[col] = df_clean[col].fillna(0.0)

# 2. División
df_train_full, df_temp = train_test_split(df_clean, test_size=0.4, random_state=42)
df_val, df_test = train_test_split(df_temp, test_size=0.5, random_state=42)

y_train = df_train_full['converted'].values
y_val = df_val['converted'].values

X_train_df = df_train_full.drop('converted', axis=1)
X_val_df = df_val.drop('converted', axis=1)

# 3. One-hot encoding
dv = DictVectorizer(sparse=False)
X_train = dv.fit_transform(X_train_df.to_dict(orient='records'))
X_val = dv.transform(X_val_df.to_dict(orient='records'))

# 4. Probar diferentes C
C_values = [0.01, 0.1, 1, 10, 100]
results = {}

for C in C_values:
    model = LogisticRegression(solver='liblinear', C=C, max_iter=1000, random_state=42)
    model.fit(X_train, y_train)

    y_pred_val = model.predict(X_val)
    accuracy_val = accuracy_score(y_val, y_pred_val)
    accuracy_val_rounded = round(accuracy_val, 3)

    results[C] = accuracy_val_rounded
    print(f"C={C}: accuracy = {accuracy_val_rounded}")

# 5. Encontrar mejor C
max_accuracy = max(results.values())
best_C = min([c for c, acc in results.items() if acc == max_accuracy])

print(f"\nMejor C: {best_C} (accuracy: {max_accuracy:.3f})")

🎯 Resumen del Homework Completo

Ahora tenemos todas las respuestas:

print("\n" + "=" * 70)
print("RESUMEN COMPLETO - HOMEWORK 3: CLASIFICACIÓN")
print("=" * 70)

print(f"\nQuestion 1 - Moda de 'industry':")
print(f"  Respuesta: retail")

print(f"\nQuestion 2 - Mayor correlación:")
print(f"  Respuesta: annual_income y interaction_count")

print(f"\nQuestion 3 - Mayor Mutual Information Score:")
print(f"  Respuesta: employment_status")

print(f"\nQuestion 4 - Accuracy de Regresión Logística:")
print(f"  Respuesta: 0.85")

print(f"\nQuestion 5 - Feature menos útil:")
print(f"  Respuesta: employment_status")

print(f"\nQuestion 6 - Mejor valor de C:")
print(f"  Respuesta: {best_C}")

print("\n" + "=" * 70)
print("✅ HOMEWORK COMPLETADO")
print("=" * 70)

🎓 Conclusión

En este post final aprendimos sobre regularización:

  1. Qué es la regularización y por qué previene overfitting
  2. Cómo funciona el parámetro C en regresión logística
  3. Cómo encontrar el mejor C mediante búsqueda sistemática
  4. Cómo evaluar el modelo final en test set

Puntos clave:

  • 🎯 C controla la fuerza de regularización (C pequeño = más regularización)
  • 📊 Siempre optimizar en validation, no en test
  • 🔍 Si hay empate, elegir el C más pequeño (modelo más simple)
  • ⚖️ Balance entre train y validation accuracy es crucial

🚀 Siguientes Pasos

¡Felicitaciones! Has completado el Homework 3 de Clasificación. Ahora puedes:

  1. Experimentar con otros datasets de clasificación
  2. Probar otros algoritmos (Random Forest, Gradient Boosting)
  3. Explorar técnicas avanzadas (SMOTE para desbalance, ensemble methods)
  4. Aplicar lo aprendido a problemas reales de tu trabajo

¿Qué valor de C encontraste óptimo? ¿Notaste diferencias significativas entre valores? ¡Comparte tus resultados!


This content originally appeared on DEV Community and was authored by Jesus Oviedo Riquelme


Print Share Comment Cite Upload Translate Updates
APA

Jesus Oviedo Riquelme | Sciencx (2025-10-13T22:11:29+00:00) MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización. Retrieved from https://www.scien.cx/2025/10/13/mlzc25-22-regularizacion-en-regresion-logistica-ajuste-fino-del-parametro-c-para-mejor-generalizacion/

MLA
" » MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización." Jesus Oviedo Riquelme | Sciencx - Monday October 13, 2025, https://www.scien.cx/2025/10/13/mlzc25-22-regularizacion-en-regresion-logistica-ajuste-fino-del-parametro-c-para-mejor-generalizacion/
HARVARD
Jesus Oviedo Riquelme | Sciencx Monday October 13, 2025 » MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización., viewed ,<https://www.scien.cx/2025/10/13/mlzc25-22-regularizacion-en-regresion-logistica-ajuste-fino-del-parametro-c-para-mejor-generalizacion/>
VANCOUVER
Jesus Oviedo Riquelme | Sciencx - » MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/10/13/mlzc25-22-regularizacion-en-regresion-logistica-ajuste-fino-del-parametro-c-para-mejor-generalizacion/
CHICAGO
" » MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización." Jesus Oviedo Riquelme | Sciencx - Accessed . https://www.scien.cx/2025/10/13/mlzc25-22-regularizacion-en-regresion-logistica-ajuste-fino-del-parametro-c-para-mejor-generalizacion/
IEEE
" » MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización." Jesus Oviedo Riquelme | Sciencx [Online]. Available: https://www.scien.cx/2025/10/13/mlzc25-22-regularizacion-en-regresion-logistica-ajuste-fino-del-parametro-c-para-mejor-generalizacion/. [Accessed: ]
rf:citation
» MLZC25-22. Regularización en Regresión Logística: Ajuste Fino del Parámetro C para Mejor Generalización | Jesus Oviedo Riquelme | Sciencx | https://www.scien.cx/2025/10/13/mlzc25-22-regularizacion-en-regresion-logistica-ajuste-fino-del-parametro-c-para-mejor-generalizacion/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.