5. Estructura y flujo de un proyecto de Machine Learning

Objetivo general

En este modulo mostramos los pasos fundamentales que se repiten en cualquier proyecto de Scikit-learn. A diferencia del ejemplo de frutas, ahora organizamos un flujo de trabajo mas completo y cercano a lo que ocurre en la practica.

5.1 Cargar y explorar datos

En proyectos reales los datos llegan desde archivos CSV, bases de datos o APIs. Para simplificar, crearemos un dataset directamente en Pandas, que facilita el analisis tabular.

import pandas as pd

# Creamos un dataset sencillo (ejemplo: notas de estudiantes)
datos = {
    "horas_estudio": [1, 2, 3, 4, 5, 6, 7, 8],
    "horas_sueno":   [8, 7, 6, 6, 5, 5, 4, 4],
    "aprobado":      [0, 0, 0, 1, 1, 1, 1, 1]  # 0 = no, 1 = si
}

df = pd.DataFrame(datos)
print(df)

Explicación del código:

  • import pandas as pd: Importamos la librería Pandas, que es una herramienta fundamental para la manipulación y el análisis de datos en Python. La abreviamos como pd por convención.
  • datos = {...}: Creamos un diccionario de Python para almacenar nuestros datos. Cada clave del diccionario representa una columna de nuestra tabla de datos, y los valores son listas de datos para cada columna.
  • df = pd.DataFrame(datos): Utilizamos la función DataFrame() de Pandas para convertir nuestro diccionario en una tabla de datos, que llamamos df (una abreviatura común para DataFrame). Un DataFrame es una estructura de datos de dos dimensiones, similar a una hoja de cálculo, con filas y columnas.
  • print(df): Imprimimos el DataFrame para ver su contenido.

Salida esperada:

   horas_estudio  horas_sueno  aprobado
0              1            8         0
1              2            7         0
2              3            6         0
3              4            6         1
4              5            5         1
5              6            5         1
6              7            4         1
7              8            4         1

5.2 Division en conjuntos de entrenamiento y prueba

Separar los datos en entrenamiento y prueba es clave para medir generalizacion. Utilizamos train_test_split para dividir caracteristicas (X) y etiquetas (y).

En la jerga técnica, decimos que las características de un fenómeno son parte del conjunto de características (denotado por X, una variable aleatoria independiente). La variable a predecir es la variable dependiente (porque depende de las características), típicamente denotada por y. Un algoritmo supervisado aprende la relación entre X e y y es capaz de predecir una nueva y dada una X que no pertenece al conjunto de entrenamiento.

from sklearn.model_selection import train_test_split

X = df[["horas_estudio", "horas_sueno"]]  # caracteristicas
y = df["aprobado"]                        # etiqueta

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42
)

print("Entrenamiento:", X_train.shape, y_train.shape)
print("Prueba:", X_test.shape, y_test.shape)

Explicación del código:

  • from sklearn.model_selection import train_test_split: Importamos la función train_test_split de Scikit-learn, que nos permite dividir nuestros datos en conjuntos de entrenamiento y prueba.
  • X = df[["horas_estudio", "horas_sueno"]]: Creamos una variable X que contiene las características de nuestro conjunto de datos (las columnas "horas_estudio" y "horas_sueno").
  • y = df["aprobado"]: Creamos una variable y que contiene las etiquetas de nuestro conjunto de datos (la columna "aprobado").
  • X_train, X_test, y_train, y_test = train_test_split(...): Llamamos a la función train_test_split para dividir nuestros datos. Le pasamos las características (X) y las etiquetas (y), y le especificamos el tamaño del conjunto de prueba (test_size=0.25, que significa que el 25% de los datos se utilizará para la prueba y el 75% para el entrenamiento). El parámetro random_state se utiliza para garantizar que la división sea siempre la misma cada vez que ejecutamos el código.
  • print(...): Imprimimos las dimensiones de los conjuntos de datos de entrenamiento y prueba para ver cómo se han dividido.

Los conjuntos generados almacenan:

  • X_train: observaciones de entrenamiento con sus caracteristicas (horas de estudio y horas de sueno).
  • y_train: etiqueta asociada a cada fila de entrenamiento (0 = no aprobo, 1 = si aprobo).
  • X_test: observaciones reservadas para evaluar el modelo una vez entrenado.
  • y_test: etiquetas reales de las filas de prueba, usadas para comparar contra las predicciones.

5.3 Entrenar un modelo sencillo

Con los conjuntos de entrenamiento y prueba listos ya podemos entrenar un primer clasificador. Usaremos LogisticRegression, que modela la probabilidad de aprobar a partir de las horas dedicadas.

from sklearn.linear_model import LogisticRegression

modelo = LogisticRegression()
modelo.fit(X_train, y_train)

print("Modelo entrenado:", modelo)

Explicacion del codigo:

  • from sklearn.linear_model import LogisticRegression: Importamos el modelo de regresion logistica, adecuado para problemas de clasificacion binaria como este.
  • modelo = LogisticRegression(): Creamos una instancia del modelo con sus parametros por defecto.
  • modelo.fit(X_train, y_train): Ajustamos el modelo con los datos de entrenamiento para que aprenda la relacion entre las caracteristicas y el resultado.
  • print("Modelo entrenado:", modelo): Confirmamos que el modelo quedo listo para usarse.

5.4 Evaluar y usar el modelo

Para saber que tan bien generaliza el modelo medimos su precision sobre el conjunto de prueba y ademas realizamos una prediccion nueva.

from sklearn.metrics import accuracy_score

y_pred = modelo.predict(X_test)
print("Precision del modelo:", accuracy_score(y_test, y_pred))

nuevo = pd.DataFrame([[5, 6]], columns=X.columns)
print("Aprobo el nuevo caso?", modelo.predict(nuevo)[0])

Explicacion del codigo:

  • from sklearn.metrics import accuracy_score: Importamos una metrica simple que calcula la proporcion de aciertos.
  • modelo.predict(X_test): Generamos predicciones para los ejemplos reservados para prueba.
  • accuracy_score(y_test, y_pred): Comparamos predicciones con los resultados reales para obtener la precision.
  • modelo.predict(nuevo): Estimamos el resultado para un estudiante con horas de estudio y sueno especificas.

5.5 Lo que aprendemos con este flujo

  • Organizar los datos en matrices de caracteristicas y vectores de etiquetas.
  • Dividir entre entrenamiento y prueba para estimar el rendimiento.
  • Entrenar un modelo base y medir su precision de manera objetiva.
  • Planificar mejoras futuras incorporando nuevas tecnicas y mas datos.

5.6 Limitaciones y proximos pasos

  • Los datos son artificiales y escasos; en proyectos reales se trabaja con conjuntos mas amplios.
  • La regresion logistica es solo un ejemplo; se puede reemplazar por otros clasificadores como SVC o RandomForest.
  • Mas adelante se agregan tecnicas como validacion cruzada, ajuste de hiperparametros y visualizacion de resultados.

Codigo completo del flujo

# Tema 5: Estructura y flujo de un proyecto de ML (programa integrado)

# 5.1 Cargar y explorar datos

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

datos = {
    "horas_estudio": [1, 2, 3, 4, 5, 6, 7, 8],
    "horas_sueno":   [8, 7, 6, 6, 5, 5, 4, 4],
    "aprobado":      [0, 0, 0, 1, 1, 1, 1, 1]
}

df = pd.DataFrame(datos)
print("Datos:\n", df, "\n")

# 5.2 Division en entrenamiento y prueba
X = df[["horas_estudio", "horas_sueno"]]
y = df["aprobado"]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42
)

print("Entrenamiento:", X_train.shape, y_train.shape)
print("Prueba:", X_test.shape, y_test.shape, "\n")

# 5.3 Entrenar un modelo sencillo
modelo = LogisticRegression()
modelo.fit(X_train, y_train)

# 5.4 Evaluar y usar el modelo
y_pred = modelo.predict(X_test)
print("Precision del modelo:", accuracy_score(y_test, y_pred))
nuevo_df = pd.DataFrame([[5, 6]], columns=X.columns)
print("Aprobo el nuevo caso?", modelo.predict(nuevo_df)[0])