Regresión Logística

La regresión logística es un algoritmo de aprendizaje supervisado que se utiliza para predecir la probabilidad de que una muestra pertenezca a una de dos clases (para problemas binarios) o más clases (para problemas multiclase). Aunque su nombre sugiere que es un método para "regresión", en realidad se utiliza principalmente para clasificación.

¿Cómo funciona?

  1. Cálculo de probabilidades:

    • Dado un conjunto de características, la regresión logística calcula una probabilidad para cada clase usando una función logística o sigmoide.
  2. Decisión final:

    • Para problemas binarios, si la probabilidad calculada es mayor o igual a un umbral (por defecto 0.5), se clasifica en una clase (por ejemplo, "spam"). De lo contrario, se clasifica en la otra clase (por ejemplo, "no spam").

Ejemplo práctico en la vida real:

Supongamos que queremos predecir si un correo electrónico es spam o no spam.

  • Las características podrían incluir:
    • Cantidad de palabras en el asunto.
    • Presencia de ciertas palabras como "oferta" o "gratis".
    • La dirección del remitente.

La regresión logística ayuda a asignar probabilidades y clasificar el correo en "spam" o "no spam" basándose en estos datos.


Código: Regresión Logística en Python

En este ejemplo, trabajaremos con datos ficticios para predecir si un estudiante aprueba un examen basado en las horas de estudio y la cantidad de clases a las que asistió.

Ver en Colab ➜

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Crear un conjunto de datos ficticio
data = {
    "horas_estudio": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    "clases_asistidas": [3, 4, 5, 6, 5, 7, 8, 8, 9, 10],
    "aprueba": [0, 0, 0, 0, 1, 1, 1, 1, 1, 1]  # 0 = No aprueba, 1 = Aprueba
}

# Convertir en un DataFrame
df = pd.DataFrame(data)

# Separar características (X) y etiquetas (y)
X = df[["horas_estudio", "clases_asistidas"]]
y = df["aprueba"]

# Dividir en datos de entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Crear y entrenar el modelo de regresión logística
model = LogisticRegression()
model.fit(X_train, y_train)

# Hacer predicciones
y_pred = model.predict(X_test)

# Evaluar el modelo
accuracy = accuracy_score(y_test, y_pred)
print(f"Precisión del modelo: {accuracy * 100:.2f}%")
print("\nReporte de clasificación:\n", classification_report(y_test, y_pred))

# Ejemplo de predicción
nuevos_datos = np.array([[6, 7]])  # Horas de estudio: 6, Clases asistidas: 7
prediccion = model.predict(nuevos_datos)
print(f"¿El estudiante aprueba? {'Sí' if prediccion[0] == 1 else 'No'}")

Salida esperada: Precisión del modelo: 100.00%

Reporte de clasificación: precision recall f1-score support

       0       1.00      1.00      1.00         1
       1       1.00      1.00      1.00         2

accuracy                           1.00         3

macro avg 1.00 1.00 1.00 3 weighted avg 1.00 1.00 1.00 3

¿El estudiante aprueba? Sí


Ejercicio práctico: Predicción de supervivencia en el Titanic

En este ejercicio, utilizarás el famoso conjunto de datos del Titanic para predecir si un pasajero sobrevivió o no. Las características clave incluyen:

  • Clase del pasajero (1ª, 2ª o 3ª clase).
  • Sexo.
  • Edad.

Código del ejercicio:

Ver en Colab ➜

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Cargar el conjunto de datos del Titanic desde seaborn
import seaborn as sns
titanic = sns.load_dataset('titanic')

# Preprocesamiento de datos
# Seleccionar solo columnas relevantes y eliminar filas con valores nulos
data = titanic[["survived", "pclass", "sex", "age"]].dropna()

# Convertir la columna 'sex' a valores numéricos
data["sex"] = data["sex"].map({"male": 0, "female": 1})

# Separar características (X) y etiquetas (y)
X = data[["pclass", "sex", "age"]]
y = data["survived"]

# Dividir en datos de entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Crear y entrenar el modelo de regresión logística
model = LogisticRegression()
model.fit(X_train, y_train)

# Hacer predicciones
y_pred = model.predict(X_test)

# Evaluar el modelo
accuracy = accuracy_score(y_test, y_pred)
print(f"Precisión del modelo: {accuracy * 100:.2f}%")
print("\nReporte de clasificación:\n", classification_report(y_test, y_pred))

# Predicción con un nuevo pasajero
nuevo_pasajero = [[3, 1, 25]]  # Clase: 3ª, Sexo: Mujer, Edad: 25 años
prediccion = model.predict(nuevo_pasajero)
print(f"¿Sobrevivió el pasajero? {'Sí' if prediccion[0] == 1 else 'No'}")

Salida esperada:

Precisión del modelo: 76.28%

Reporte de clasificación: precision recall f1-score support

       0       0.79      0.81      0.80       126
       1       0.72      0.70      0.71        89

accuracy                           0.76       215

macro avg 0.76 0.75 0.75 215 weighted avg 0.76 0.76 0.76 215

¿Sobrevivió el pasajero? Sí


Ejercicio: Predicción de diabetes usando regresión logística

La regresión logística también se puede utilizar en el ámbito de la salud, por ejemplo, para predecir si una persona tiene diabetes basándonos en características como el nivel de glucosa, la presión arterial, el índice de masa corporal (IMC), entre otros.

En este ejercicio, usaremos el conjunto de datos Pima Indians Diabetes Dataset, ampliamente utilizado para problemas de clasificación en Machine Learning.


Código: Predicción de diabetes

Ver en Colab ➜

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt

# Cargar el conjunto de datos
# Puedes descargar el archivo CSV desde: https://www.kaggle.com/datasets/uciml/pima-indians-diabetes-database
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"

# Columnas del dataset
column_names = [
    "Embarazos", "Glucosa", "Presion_Arterial", "Espesor_Piel",
    "Insulina", "IMC", "Diabetes_Pedigree", "Edad", "Resultado"
]

# Leer el archivo y asignar nombres a las columnas
data = pd.read_csv(url, header=None, names=column_names)

# Ver las primeras filas del dataset
print("Primeras filas del dataset:")
print(data.head())

# Separar características (X) y etiquetas (y)
X = data.drop(columns=["Resultado"])
y = data["Resultado"]

# Dividir el dataset en entrenamiento (70%) y prueba (30%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Crear el modelo de regresión logística
model = LogisticRegression(max_iter=500)
model.fit(X_train, y_train)

# Evaluar el modelo
y_pred = model.predict(X_test)

accuracy = accuracy_score(y_test, y_pred)
print(f"\nPrecisión del modelo: {accuracy * 100:.2f}%\n")
print("Reporte de clasificación:")
print(classification_report(y_test, y_pred))

# Matriz de confusión
conf_matrix = confusion_matrix(y_test, y_pred)
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="Blues", xticklabels=["No Diabetes", "Diabetes"], yticklabels=["No Diabetes", "Diabetes"])
plt.title("Matriz de Confusión")
plt.xlabel("Predicciones")
plt.ylabel("Valores Reales")
plt.show()

# Predicción con nuevos datos
nuevo_paciente = np.array([[2, 120, 70, 20, 80, 25.0, 0.5, 30]])  # Datos ficticios
prediccion = model.predict(nuevo_paciente)
print(f"¿El paciente tiene diabetes? {'Sí' if prediccion[0] == 1 else 'No'}")

Salida esperada

  1. Precisión del modelo: Una precisión cercana al 75-80%.
  2. Reporte de clasificación: Métricas como precisión, recall y F1-score.
  3. Matriz de confusión: Visualización de los errores y aciertos del modelo.
  4. Predicción del paciente: Una respuesta clara de si el paciente tiene diabetes o no.

Detalles del Dataset

El Pima Indians Diabetes Dataset contiene las siguientes columnas:

  • Embarazos: Número de embarazos de la paciente.
  • Glucosa: Concentración de glucosa en sangre.
  • Presión Arterial: Presión arterial diastólica (mm Hg).
  • Espesor de la Piel: Espesor del pliegue cutáneo (mm).
  • Insulina: Nivel de insulina sérica (mu U/ml).
  • IMC: Índice de masa corporal.
  • Diabetes Pedigree: Antecedentes familiares de diabetes (valor entre 0 y 2).
  • Edad: Edad de la paciente.
  • Resultado: 1 si tiene diabetes, 0 si no tiene.

Salida esperada

Primeras filas del dataset: Embarazos Glucosa Presion_Arterial Espesor_Piel Insulina IMC \ 0 6 148 72 35 0 33.6
1 1 85 66 29 0 26.6
2 8 183 64 0 0 23.3
3 1 89 66 23 94 28.1
4 0 137 40 35 168 43.1

Diabetes_Pedigree Edad Resultado
0 0.627 50 1
1 0.351 31 0
2 0.672 32 1
3 0.167 21 0
4 2.288 33 1

Precisión del modelo: 73.59%

Reporte de clasificación: precision recall f1-score support

       0       0.80      0.79      0.80       151
       1       0.62      0.62      0.62        80

accuracy                           0.74       231

macro avg 0.71 0.71 0.71 231 weighted avg 0.74 0.74 0.74 231

¿El paciente tiene diabetes? No


Desafío:

  • Modifica el código para probar diferentes umbral de decisión (por ejemplo, 0.4, 0.6 en lugar del estándar de 0.5).
  • Añade un paso de normalización o estandarización de los datos y evalúa si mejora el rendimiento del modelo.
  • Implementa técnicas como validación cruzada para asegurar la robustez de las predicciones.