scikit-learn y MLflow
En esta secci贸n veremos como todos los modelos de sklearn
tiene la misma API para entrenar todo tipo de modelos (en este caso de regresi贸n). Veremos c贸mo usar los m茅todos .fit()
y .predict()
. Adem谩s veremos c贸mo usar MLflow para guardar m茅tricas y par谩metros de todos los modelos que corramos. Si est谩s haciendo esta secci贸n en el mismo notebook de la secci贸n anterior, puedes saltar hasta Transformaci贸n de Datos.
Empezaremos cargando los datos y el preprocesador que construimos en la secci贸n anterior.
import dill
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.base import BaseEstimator, TransformerMixin
En este bloque de c贸digo vamos a copiar los transformers de la secci贸n anterior. Normalmente los importar铆amos de un archivo .py por los dejaremos en el notebook por simplicidad.
class TransformerFechas(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
columna_fecha = pd.to_datetime(X["pickup_datetime"])
fecha_df = pd.DataFrame()
fecha_df["weekday"] = columna_fecha.dt.weekday
fecha_df["hour"] = columna_fecha.dt.hour
return fecha_df
class TransformerDistancia(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X_init = X[["pickup_latitude", "pickup_longitude"]].to_numpy()
X_final = X[["dropoff_latitude", "dropoff_longitude"]].to_numpy()
# Distancia de Haversine
distancia = self.distancia_haversine(X_init=X_init, X_final=X_final)
distancia_df = pd.DataFrame()
distancia_df["distancia"] = distancia
return distancia_df
def distancia_haversine(self, X_init, X_final):
# Convertir de decimal a radianes
X_init = np.radians(X_init)
X_final = np.radians(X_final)
# haversine formula
dlat = X_final[:, 0] - X_init[:, 0]
dlon = X_final[:, 1] - X_init[:, 1]
a = np.sin(dlat / 2) ** 2 + np.cos(X_init[:, 0]) * np.cos(X_final[:, 0]) * np.sin(dlon / 2) ** 2
c = 2 * np.arcsin(np.sqrt(a))
r = 6371 # Radius of earth in kilometers. Use 3956 for miles. Determines return value units.
return c * r
Aqu铆 cargamos los datos y el preprocesador entrenado de la secci贸n anterior.
data = pd.read_csv("https://factored-workshops.s3.amazonaws.com/taxi-trip-duration.csv")
# Limitar rango de datos
tiempo_minimo = 60 # 1 minuto
tiempo_maximo = 36000 # 10 horas
data = data[
(data["trip_duration"] > tiempo_minimo) &
(data["trip_duration"] < tiempo_maximo)
]
y = data["trip_duration"]
selected_columns = [
'vendor_id',
'pickup_datetime',
'passenger_count',
'pickup_longitude',
'pickup_latitude',
'dropoff_longitude',
'dropoff_latitude',
'pickup_borough',
'dropoff_borough'
]
input_df = data[selected_columns]
train_df, val_df, y_train, y_val = train_test_split(input_df, y, random_state=0)
Ya no es necesario hacer .fit()
para aplicar las transformaciones al dataframe de entrada porque toda la informaci贸n qued贸 almacenada en el archivo preprocesser.pkl
y se carga al usar dill.load()
.
Transformaci贸n de Datos
with open("preprocesser.pkl", "rb") as f:
preprocessor = dill.load(f)
X_train = preprocessor.transform(train_df)
X_val = preprocessor.transform(val_df)
Entrenar Modelos
Baseline con DummyRegressor
DummyRegressor
Una opci贸n que nos ofrece sklearn
es entrenar modelos dummy. Estos son modelos que predicen lo mismo para todos los casos (en este caso el promedio) y nos sirven como una medida de cu谩l es el rendimiento m铆nimo para un problema. Si por alguna raz贸n nuestro modelo tiene peor desempe帽o que el modelo dummy, tenemos que revisar nuestro modelo porque probablemente tenemos errores en la implementaci贸n.
En este caso vamos a usar el DummyRegressor
que siempre predice la media de los datos de entrenamiento. La funci贸n evaluar_predicciones
es una ayuda para poder calcular varias m茅tricas de un modelo usando metricas inclu铆das de scikit-learn
.
from sklearn.metrics import mean_absolute_error, mean_absolute_percentage_error, mean_squared_error, r2_score, mean_squared_log_error
def evaluar_predicciones(y_pred, y_true):
mae = mean_absolute_error(y_pred=y_pred, y_true=y_true)
mape = mean_absolute_percentage_error(y_pred=y_pred, y_true=y_true)
rmse = mean_squared_error(y_pred=y_pred, y_true=y_true, squared=False)
print(f"MAE: {mae:.2f}")
print(f"MAPE: {mape}")
print(f"RMSE: {rmse}")
from sklearn.dummy import DummyRegressor
dummy_model = DummyRegressor(strategy="mean")
dummy_model.fit(X_train, y_train)
y_train_dummy = dummy_model.predict(X_train)
y_val_dummy = dummy_model.predict(X_val)
print("TRAIN")
evaluar_predicciones(y_pred=y_train_dummy, y_true=y_train)
print("VALIDATION")
evaluar_predicciones(y_pred=y_val_dummy, y_true=y_val)

Baseline con regresi贸n lineal
Otra buena medida es siempre empezar con un modelo lineal. As铆 tenemos una medida de c贸mo se desempe帽a un modelo sencillo.
Algo para notar es que sin importar el modelo, los modelos de sklearn
siempre siguen el mismo proceso.
1. Inicializar modelo con la clase de sklearn
.
2. Ejecutar funci贸n .fit(X_train, y_train
.
3. Ejecutar funci贸n .predict(X)
para generar las predicciones.
Esta consistencia en el proceso simplifica el uso de diferentes modelos.
from sklearn.linear_model import LinearRegression
#TODO: entrenar un modelo lineal con LinearRegression
print("TRAIN")
evaluar_predicciones(y_pred=y_train_linear, y_true=y_train)
print("VALIDATION")
evaluar_predicciones(y_pred=y_val_linear, y_true=y_val)

Checkpoint #1
Entrenar un model de regresi贸n linear usando LinearRergression de
scikit-learn
.Predecir valores del viaje para train (
y_train_linear
) y validaci贸n (y_val_linear
)
Las m茅tricas del modelo deber铆an ser similares a las imagen de arriba.
Soluci贸n Checkpoint #1
from sklearn.linear_model import LinearRegression
linear_model = LinearRegression()
linear_model.fit(X_train, y_train)
y_train_linear = linear_model.predict(X_train)
y_val_linear = linear_model.predict(X_val)
print("TRAIN")
evaluar_predicciones(y_pred=y_train_linear, y_true=y_train)
print("VALIDATION")
evaluar_predicciones(y_pred=y_val_linear, y_true=y_val)
驴C贸mo comparar modelos m谩s all谩 de un print
? MLFlow 馃檶
print
? MLFlow 馃檶Imprimiendo los resultados nos podemos dar cuenta del modelo con mejores resultados. Sin embargo, comparar los resultados usando print
es dif铆cil cuando el n煤mero de modelos empieza a crecer. Adem谩s idealmente queremos que todos los modelos queden guardados para poder retomarlos despu茅s. Para todo esto podemos usar MLflow.
MLflow es una librer铆a open-source que nos ayuda a manejar todo el ciclo de modelos de machine learning. En este caso vamos a ver c贸mo podemos usar MLflow para guardar resultados del desempe帽o de modelos para determinar cu谩l modelo es el mejor.
Vamos a correr los mismos modelos que acabamos de comparar pero esta vez vamos a usar MLflow para ver los resultados.
import mlflow
mlflow.sklearn.autolog()
mlflow.sklearn.autolog()
autom谩ticamente nos ayuda a guardar varias m茅tricas y par谩metros del modelo. Sin embargo, no incluye valores para datos de validaci贸n. Para guardar m茅tricas que no se incluyen en .autolog
vamos a usar la funci贸n mlflow.log_metric
dentro del context manager de run
.
Vamos primero a usar el modelo dummy y vamos a poner run_name="dummy" para poder
verlo con el nombre correcto en MLflow.
with mlflow.start_run(run_name="dummy") as run:
dummy_model.fit(X_train, y_train)
y_pred_val = dummy_model.predict(X_val)
val_mae = mean_absolute_error(y_pred=y_pred_val, y_true=y_val)
val_rmse = mean_squared_error(y_pred=y_pred_val, y_true=y_val, squared=False)
val_mape = mean_absolute_percentage_error(y_pred=y_pred_val, y_true=y_val)
val_r2 = r2_score(y_pred=y_pred_val, y_true=y_val)
mlflow.log_metric("val_mae", val_mae)
mlflow.log_metric("val_rmse", val_rmse)
mlflow.log_metric("val_mape", val_mape)
mlflow.log_metric("val_r2", val_r2)
Una vez termine de correr esta celda debemos abrir la interfaz de MLflow para ver los resultados. Deber铆amos encontrar una nueva carpeta llamada mlruns
en la ubicaci贸n donde corri贸 este notebook. Una vez estemos en la carpeta donde est谩 mlruns
, debemos ir a un terminal a esa ubicaci贸n y ejecutamos el comando
mlflow ui
Ah铆 nos deber铆a salir el mensaje de que est谩 iniciando un servidor y dar la ruta para acceder. (normalmente la ruta es http://127.0.0.1:5000). Copiamos esa direcci贸n en un navegador y ah铆 ya deber铆amos ver la interfaz de MLflow.

En la interfaz de MLflow estar谩n los modelos que corramos usando MLflow y podemos filtrar u ordenar por m茅tricas o par谩metros que consideramos importantes. En general, con la interfaz de MLflow tenemos una base de datos de modelos que podemos analizar f谩cilmente.
Adem谩s, si hacemos click un alguna de las runs (click en la columna Start Time) podemos ver que tenemos los datos m谩s detallados y los artifacts de cada run. Los artifacts pueden ser todo tipo de archivos (por ejemplo im谩genes y CSVs) que nos ayudan a guardar lo relevante de cada caso como el modelo o el ambiente de conda desde el que corrimos el modelo.

Ahora corramos nuevamente la regresi贸n lineal para que quede registrada en MLflow. En este caso vamos a guardar nuestro preprocesador que quede asociado a cada run usando .log_artifact
.
with mlflow.start_run(run_name="linear_regression") as run:
#TODO: Hacer fit a un modelo lineal
y_pred_val = linear_model.predict(X_val)
val_mae = mean_absolute_error(y_pred=y_pred_val, y_true=y_val)
val_rmse = mean_squared_error(y_pred=y_pred_val, y_true=y_val, squared=False)
val_mape = mean_absolute_percentage_error(y_pred=y_pred_val, y_true=y_val)
val_r2 = r2_score(y_pred=y_pred_val, y_true=y_val)
mlflow.log_metric("val_mae", val_mae)
mlflow.log_metric("val_rmse", val_rmse)
mlflow.log_metric("val_mape", val_mape)
mlflow.log_metric("val_r2", val_r2)
mlflow.log_artifact("preprocesser.pkl")
Ahora que tenemos la regresi贸n lineal y el modelo dummy en MLflow, vamos a probar con un modelo m谩s complejo como el Random Forest. Por ahora vamos a dejar los par谩metros por defecto que trae la clase RandomForestRegressor
excepto n_jobs
que lo vamos a poner con el par谩metro n_jobs=2. Poner n_jobs=2
hace que el modelo corra en paralelo en 2 procesadores.
Entrenar el random forest puede tomar algunos minutos as铆 que es un buen momento para resolver cualquier duda o tomar un descanso y estirar las piernas :)
from sklearn.ensemble import RandomForestRegressor
with mlflow.start_run(run_name="random_forest") as run:
#TODO: Hacer fit a un modelo random forest
y_pred_val = rf_model.predict(X_val)
val_mae = mean_absolute_error(y_pred=y_pred_val, y_true=y_val)
val_rmse = mean_squared_error(y_pred=y_pred_val, y_true=y_val, squared=False)
val_mape = mean_absolute_percentage_error(y_pred=y_pred_val, y_true=y_val)
val_r2 = r2_score(y_pred=y_pred_val, y_true=y_val)
mlflow.log_metric("val_mae", val_mae)
mlflow.log_metric("val_rmse", val_rmse)
mlflow.log_metric("val_mape", val_mape)
mlflow.log_metric("val_r2", val_r2)
mlflow.log_artifact("preprocesser.pkl")
Checkpoint #2
Entrenar un modelo lineal y un random forest y verificar las m茅tricas de validaci贸n en MLflow.
Soluci贸n Checkpoint #2
with mlflow.start_run(run_name="linear_regression") as run:
linear_model.fit(X_train, y_train)
y_pred_val = linear_model.predict(X_val)
log_metrics_mlflow(y_pred_val, y_val)
mlflow.log_artifact("preprocesser.pkl")
from sklearn.ensemble import RandomForestRegressor
with mlflow.start_run(run_name="random_forest") as run:
rf_model = RandomForestRegressor(n_jobs=2)
rf_model.fit(X_train, y_train)
y_pred_val = rf_model.predict(X_val)
log_metrics_mlflow(y_pred_val, y_val)
mlflow.log_artifact("preprocesser.pkl")
Con esas herramientas puedes buscar m谩s modelos de regresi贸n de sklearn o mejorar los hiperpar谩metros de los modelos que usamos para intentar mejorar las m茅tricas que obtuvimos hasta el momento. Incluso librer铆as como XGBoost o LightGBM ofrecen la opci贸n de crear modelos con la API de sklearn. A pesar de que cada modelo puede usar t茅cnicas muy diferentes, el c贸digo va a ser casi id茅ntico gracias a la consistencia en la API de scikit-learn
.
Last updated
Was this helpful?