Streamlit

Streamlit

Tutorial Streamlit: Modelos de Machine Learning en Streamlit

Descubre cómo integrar Scikit-Learn con Streamlit para visualizar predicciones y métricas de rendimiento de modelos de clasificación con el conjunto de datos Iris.

Aprende Streamlit y certifícate

Visualización de predicciones y métricas de rendimiento

La integración de Scikit-Learn con Streamlit permite crear aplicaciones interactivas para visualizar las predicciones de los modelos y sus métricas de rendimiento. Esto facilita la interpretación de los resultados y la comunicación con usuarios no técnicos.

Para ilustrar esta integración, utilizaremos un modelo de clasificación con el conjunto de datos Iris proporcionado por Scikit-Learn. Este conjunto contiene datos de diferentes especies de flores Iris y es ideal para demostrar modelos de clasificación.

Primero, cargamos los datos y entrenamos un modelo de Bosque Aleatorio:

import streamlit as st
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, ConfusionMatrixDisplay
from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt
import pandas as pd

# Cargar datos
iris = load_iris()
X = iris.data
y = iris.target

# Dividir datos en entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# Parámetros del modelo interactivos
st.sidebar.header("Parámetros del Modelo")
n_estimators = st.sidebar.slider("Número de árboles", min_value=10, max_value=200, value=100, step=10)
max_depth = st.sidebar.slider("Profundidad máxima", min_value=1, max_value=10, value=5, step=1)

# Entrenar modelo
model = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth)
model.fit(X_train, y_train)

Con el modelo entrenado, realizamos predicciones y calculamos las métricas de rendimiento:

# Realizar predicciones
y_pred = model.predict(X_test)
y_proba = model.predict_proba(X_test)

# Calcular métricas
report = classification_report(y_test, y_pred, output_dict=True)

Podemos mostrar el informe de clasificación de manera interactiva:

# Mostrar informe de clasificación
st.header("Informe de Clasificación")
report_df = pd.DataFrame(report).transpose()
st.dataframe(report_df.style.highlight_max(axis=0))

Para visualizar la matriz de confusión, utilizamos Matplotlib y la mostramos en la aplicación:

# Visualizar matriz de confusión
st.header("Matriz de Confusión")
fig, ax = plt.subplots()
ConfusionMatrixDisplay.from_predictions(y_test, y_pred, display_labels=iris.target_names, ax=ax)
st.pyplot(fig)

Además, podemos explorar las probabilidades de predicción para cada clase:

# Mostrar probabilidades de predicción
st.header("Probabilidades de Predicción")
proba_df = pd.DataFrame(y_proba, columns=iris.target_names)
proba_df['Predicción'] = y_pred
proba_df['Verdadero'] = y_test
st.dataframe(proba_df)

Con esta aplicación, los usuarios pueden interactuar con los parámetros del modelo, visualizar las predicciones y comprender las métricas de rendimiento en un entorno intuitivo.

Implementación de pipelines de preprocesamiento en tiempo real

La integración de pipelines de preprocesamiento de Scikit-Learn en una aplicación de Streamlit permite procesar y transformar los datos de manera interactiva y dinámica. Esto es especialmente útil cuando se desea aplicar transformaciones en tiempo real según las entradas del usuario, mejorando así la exploración y comprensión de cómo afectan los preprocesamientos al rendimiento del modelo.

Para ilustrar esta integración, construiremos una aplicación que permite al usuario ajustar parámetros de preprocesamiento y observar en tiempo real cómo cambian las predicciones de un modelo de regresión sobre el conjunto de datos California Housing.

Primero, importamos las bibliotecas necesarias y cargamos los datos:

import streamlit as st
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, MinMaxScaler, PolynomialFeatures
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.metrics import mean_squared_error
import pandas as pd
import numpy as np

Cargamos el conjunto de datos y lo dividimos en conjuntos de entrenamiento y prueba:

# Cargar datos
housing = fetch_california_housing()
X = pd.DataFrame(housing.data, columns=housing.feature_names)
y = housing.target

# División de datos
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

En la barra lateral, permitimos al usuario seleccionar los parámetros de preprocesamiento y del modelo:

# Parámetros de preprocesamiento
st.sidebar.header("Configuración del Preprocesamiento")
scaler_option = st.sidebar.selectbox("Seleccione el escalador", ("Ninguno", "StandardScaler", "MinMaxScaler"))
poly_features = st.sidebar.checkbox("Incluir Características Polinomiales")
degree = 2
if poly_features:
    degree = st.sidebar.slider("Grado del Polinomio", min_value=2, max_value=5, value=2)

# Parámetros del modelo
st.sidebar.header("Configuración del Modelo")
model_type = st.sidebar.selectbox("Seleccione el modelo", ("Regresión Lineal", "Regresión Ridge"))
alpha = 1.0
if model_type == "Regresión Ridge":
    alpha = st.sidebar.slider("Valor de alpha", min_value=0.1, max_value=10.0, value=1.0)

Definimos una función para construir el pipeline basado en las selecciones del usuario:

def build_pipeline():
    steps = []
    # Preprocesamiento
    if scaler_option == "StandardScaler":
        steps.append(("scaler", StandardScaler()))
    elif scaler_option == "MinMaxScaler":
        steps.append(("scaler", MinMaxScaler()))
    if poly_features:
        steps.append(("poly", PolynomialFeatures(degree=degree, include_bias=False)))
    # Modelo
    if model_type == "Regresión Lineal":
        steps.append(("model", LinearRegression()))
    else:
        steps.append(("model", Ridge(alpha=alpha)))
    pipeline = Pipeline(steps)
    return pipeline

Entrenamos el modelo utilizando el pipeline configurado:

# Construir y entrenar el pipeline
pipeline = build_pipeline()
pipeline.fit(X_train, y_train)

Calculamos las predicciones y evaluamos el modelo:

# Predicciones
y_pred = pipeline.predict(X_test)

# Evaluación del modelo
mse = mean_squared_error(y_test, y_pred)
st.header("Evaluación del Modelo")
st.write(f"**Error Cuadrático Medio (MSE)**: {mse:.2f}")

Para permitir predicciones en tiempo real, creamos una interfaz donde el usuario puede ingresar valores para cada característica:

st.header("Predicción en Tiempo Real")
user_input = {}
for feature in X.columns:
    min_val = float(X[feature].min())
    max_val = float(X[feature].max())
    mean_val = float(X[feature].mean())
    user_input[feature] = st.number_input(
        f"Ingrese {feature}",
        min_value=min_val,
        max_value=max_val,
        value=mean_val
    )
input_data = pd.DataFrame(user_input, index=[0])

Aplicamos el pipeline al dato ingresado por el usuario y mostramos la predicción:

# Predicción en tiempo real
prediction = pipeline.predict(input_data)
st.write(f"**Precio de vivienda predicho**: ${prediction[0]*100000:.2f}")

Para analizar cómo el pipeline transforma los datos, mostramos los pasos intermedios:

def display_intermediate_steps(input_df):
    st.subheader("Transformaciones Intermedias")
    data = input_df.copy()
    for name, step in pipeline.named_steps.items():
        if name != "model":
            data = step.transform(data)
            st.write(f"Después de **{name}**:")
            st.dataframe(pd.DataFrame(data))

Llamamos a la función para mostrar las transformaciones:

# Mostrar transformaciones
display_intermediate_steps(input_data)

También proporcionamos información sobre los coeficientes del modelo para entender su impacto:

st.header("Coeficientes del Modelo")
if poly_features:
    feature_names = pipeline.named_steps["poly"].get_feature_names_out(X.columns)
else:
    feature_names = X.columns
coefficients = pipeline.named_steps["model"].coef_
coef_df = pd.DataFrame({
    "Características": feature_names,
    "Coeficientes": coefficients
})
st.dataframe(coef_df)

Además, visualizamos la distribución de errores:

import matplotlib.pyplot as plt

st.header("Distribución de Errores")
residuals = y_test - y_pred
fig, ax = plt.subplots()
ax.hist(residuals, bins=30)
ax.set_title("Histograma de Errores")
ax.set_xlabel("Error")
ax.set_ylabel("Frecuencia")
st.pyplot(fig)

La implementación de pipelines en tiempo real en Streamlit ofrece una forma interactiva de entender el impacto del preprocesamiento y la configuración del modelo en las predicciones. Esto es particularmente útil para fines educativos y para ajustar modelos de manera eficiente mediante pruebas dinámicas.

Actualización y retraining de modelos de Scikit Learn desde la aplicación

La capacidad de actualizar y reentrenar modelos de Scikit-Learn directamente desde una aplicación de Streamlit proporciona una herramienta poderosa para adaptar modelos a datos nuevos o cambiantes en tiempo real. Esto es especialmente útil en escenarios donde los datos se actualizan con frecuencia y se requiere que el modelo refleje estos cambios sin necesidad de intervención manual externa.

A continuación, se muestra cómo implementar una aplicación de Streamlit que permite cargar nuevos datos, reentrenar el modelo y actualizar las predicciones, todo desde la interfaz de usuario.

Comenzamos importando las bibliotecas necesarias y cargando un conjunto de datos inicial. Para este ejemplo, utilizaremos el conjunto de datos California Housing para predecir el valor medio de las viviendas en diferentes áreas de California.

import streamlit as st
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
import pandas as pd
import numpy as np
import joblib
import os

Cargamos y dividimos los datos:

# Cargar el conjunto de datos
data = fetch_california_housing(as_frame=True)
X = data.data
y = data.target

# División inicial de los datos
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

Entrenamos un modelo inicial utilizando una Regresión Ridge con un pipeline que incluye escalado de características. Luego, guardamos el modelo para su uso posterior.

# Crear pipeline de preprocesamiento y modelo
pipeline = make_pipeline(StandardScaler(), Ridge())

# Entrenar el modelo
pipeline.fit(X_train, y_train)

# Guardar el modelo entrenado
joblib.dump(pipeline, 'modelo_ridge.pkl')

Diseñamos una interfaz que permite al usuario cargar nuevos datos, actualizar el modelo existente y realizar predicciones con el modelo reentrenado.

# Título de la aplicación
st.title("Actualización y Retraining de Modelos de Scikit-Learn desde Streamlit")

# Cargar el modelo existente
if os.path.exists('modelo_ridge.pkl'):
    pipeline = joblib.load('modelo_ridge.pkl')
    st.success("Modelo cargado exitosamente.")
else:
    st.warning("El modelo no existe. Entrene el modelo para comenzar.")

# Sección para cargar nuevos datos
st.header("Cargar nuevos datos para actualización")
uploaded_file = st.file_uploader("Seleccione un archivo CSV con nuevos datos", type="csv")

if uploaded_file is not None:
    # Leer los nuevos datos
    new_data = pd.read_csv(uploaded_file)

    # Verificar que las columnas coincidan
    if set(X.columns).issubset(new_data.columns):
        st.write("Datos cargados correctamente:")
        st.dataframe(new_data.head())

        # Separar características y objetivo si está presente
        X_new = new_data[X.columns]
        y_new = new_data['MedHouseVal'] if 'MedHouseVal' in new_data.columns else None

        # Botón para reentrenar el modelo
        if st.button("Reentrenar el modelo con nuevos datos"):
            if y_new is not None:
                # Combinar datos antiguos y nuevos
                X_combined = pd.concat([X_train, X_new], ignore_index=True)
                y_combined = pd.concat([y_train, y_new], ignore_index=True)

                # Reentrenar el modelo con los datos combinados
                pipeline.fit(X_combined, y_combined)

                # Guardar el modelo actualizado
                joblib.dump(pipeline, 'modelo_ridge.pkl')
                st.success("Modelo actualizado y guardado exitosamente.")
            else:
                st.error("Los datos cargados no contienen la columna objetivo 'MedHouseVal'.")
    else:
        st.error("Las columnas del archivo cargado no coinciden con las características esperadas.")

En este fragmento, permitimos al usuario cargar nuevos datos en formato CSV, verificar su conformidad y reentrenar el modelo con estos datos. Si los nuevos datos contienen la variable objetivo MedHouseVal, el modelo se reentrena y se actualiza.

Proporcionamos una sección donde el usuario puede ingresar valores para cada característica y obtener una predicción del modelo actualizado.

st.header("Realizar predicciones con el modelo actualizado")

# Entradas de usuario para cada característica
input_data = {}
for feature in X.columns:
    min_val = float(X[feature].min())
    max_val = float(X[feature].max())
    mean_val = float(X[feature].mean())
    input_value = st.number_input(
        f"Ingrese {feature}", min_value=min_val, max_value=max_val, value=mean_val
    )
    input_data[feature] = input_value

# Convertir las entradas en un DataFrame
input_df = pd.DataFrame([input_data])

# Botón para predecir
if st.button("Predecir valor medio de la vivienda"):
    prediction = pipeline.predict(input_df)
    st.write(f"**Valor medio predicho de la vivienda:** ${prediction[0]*100000:.2f}")

Esta sección permite al usuario interactuar con el modelo ingresando valores personalizados y obteniendo predicciones instantáneas.

Añadimos una funcionalidad para que el usuario pueda proporcionar el valor real si lo conoce, permitiendo que el modelo aprenda de este nuevo dato.

st.header("Proporcionar retroalimentación para mejorar el modelo")

# Entrada para el valor real
actual_value = st.number_input(
    "Ingrese el valor real de la vivienda (en cientos de miles de dólares):",
    min_value=0.0, max_value=10.0, value=1.0
)

# Botón para enviar la retroalimentación
if st.button("Enviar retroalimentación"):
    # Agregar el nuevo dato a los datos de entrenamiento
    X_train = pd.concat([X_train, input_df], ignore_index=True)
    y_train = pd.concat([y_train, pd.Series([actual_value])], ignore_index=True)

    # Reentrenar el modelo con el nuevo dato
    pipeline.fit(X_train, y_train)

    # Guardar el modelo actualizado
    joblib.dump(pipeline, 'modelo_ridge.pkl')
    st.success("Gracias por su retroalimentación. El modelo ha sido actualizado.")

Esta funcionalidad permite que el modelo se adapte continuamente a nuevos datos proporcionados por los usuarios, mejorando su precisión con el tiempo.

La capacidad de actualizar y reentrenar modelos de Scikit-Learn directamente desde una aplicación de Streamlit permite crear herramientas dinámicas y adaptativas. Esta integración facilita la incorporación de datos nuevos y la mejora continua del modelo, ofreciendo a los usuarios una experiencia interactiva y enriquecedora.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

30 % DE DESCUENTO

Plan mensual

19.00 /mes

13.30 € /mes

Precio normal mensual: 19 €
63 % DE DESCUENTO

Plan anual

10.00 /mes

7.00 € /mes

Ahorras 144 € al año
Precio normal anual: 120 €
Aprende Streamlit online

Todas las lecciones de Streamlit

Accede a todas las lecciones de Streamlit y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Streamlit y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Implementar aplicaciones interactivas con Streamlit y Scikit-Learn.
  • Utilizar un modelo de Bosque Aleatorio para clasificar datos de Iris.
  • Visualizar predicciones de modelos de clasificación.
  • Interpretar métricas de rendimiento y matriz de confusión.
  • Utilizar Matplotlib para representaciones gráficas claras.
  • Facilitar la comunicación de resultados complejos a usuarios no técnicos.