Spaces:
Sleeping
Sleeping
File size: 21,333 Bytes
1fb0787 1ed0844 1fb0787 abb123d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
import streamlit as st
import pandas as pd
import numpy as np
import plotly.graph_objects as go
from scipy.optimize import minimize, differential_evolution
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
import seaborn as sns
import io
# Configuración inicial
# Configuración de la aplicación
st.set_page_config(page_title="Optimización Avanzada", page_icon="📊",layout="wide")
# Display the image above the title
st.image('cannabis.jpg', use_container_width=True)
st.title("Optimización Avanzada con Diseño Experimental Box-Behnken")
st.write("Aplicación con regresión cuadrática y estrategias de optimización mejoradas.")
# Crear las pestañas
tabs = st.selectbox("Selecciona una opción", ["Fundamento Teórico", "Aplicación Interactiva"])
if tabs == "Fundamento Teórico":
st.header("Fundamento Teórico")
# Imagen del proceso
st.subheader("Proceso de Extracción de CBD")
st.image("CBD extraction process.png", caption="Proceso de Extracción de CBD con CO2 Supercrítico", use_container_width=True)
st.write("""
El proceso de extracción de CBD utiliza tecnología de CO2 supercrítico debido a su eficiencia y capacidad para producir extractos puros. Este método incluye etapas clave como molienda, extracción, separación y refinamiento, garantizando un producto de alta calidad para aplicaciones medicinales y comerciales.
""")
# Diseño Experimental Box-Behnken
st.subheader("Diseño Experimental Box-Behnken")
st.write("""
El diseño experimental **Box-Behnken** se utiliza para modelar y optimizar procesos complejos. En este caso, se aplica para maximizar el rendimiento de CBD considerando variables clave como **Temperatura**, **Presión**, **Flujo de CO2** y **Tiempo**.
Este enfoque reduce significativamente la cantidad de experimentos necesarios, permitiendo explorar interacciones no lineales de manera eficiente.
""")
# Proceso de Producción de CBD
st.subheader("Proceso de Producción de CBD")
st.write("""
Según el documento *Optimization of Supercritical Carbon Dioxide Fluid Extraction of Medicinal Cannabis from Quebec*, el proceso de extracción con CO2 supercrítico es preferido por su alta selectividad y pureza. Las principales etapas incluyen:
1. **Preparación de la materia prima**: Molienda y acondicionamiento.
2. **Extracción supercrítica**:
- El CO2 actúa como solvente bajo condiciones controladas de presión y temperatura.
- Variables clave: presión (150-320 bar), temperatura (40-70°C), flujo de CO2 (5-15 g/min), tiempo (2-4 horas).
3. **Separación y recolección**: El CO2 se despresuriza para liberar los cannabinoides extraídos.
4. **Refinamiento posterior**: Remoción de ceras y otros compuestos no deseados.
""")
# Caso de Negocio
st.subheader("Caso de Negocio: Optimización del Rendimiento")
st.write("""
Optimizar el rendimiento del proceso de extracción permite:
- Maximizar la cantidad de CBD extraído por lote.
- Reducir costos operativos (energía, solventes, tiempo).
- Mejorar la calidad del producto final.
Este enfoque es crucial en la industria del cannabis medicinal, donde la eficiencia del proceso impacta directamente en la rentabilidad y sostenibilidad del negocio.
""")
# Método Basado en CRISP-DM
st.subheader("Metodología Basada en CRISP-DM")
st.write("""
La metodología **CRISP-DM** estructura el desarrollo del modelo en seis etapas:
1. **Comprensión del Negocio**: Definir objetivos y restricciones del proceso.
2. **Comprensión de los Datos**: Analizar datos experimentales y evaluar su calidad.
3. **Preparación de los Datos**: Limpiar y transformar datos para el modelado.
4. **Modelado**: Ajustar un modelo de regresión cuadrática para capturar relaciones no lineales.
5. **Evaluación**: Validar el modelo y analizar su desempeño.
6. **Despliegue**: Implementar el modelo en una aplicación interactiva para optimización en tiempo real.
""")
# Optimización
st.subheader("Optimización")
st.write("""
Se emplean técnicas avanzadas para maximizar el rendimiento:
- **L-BFGS-B**: Método de optimización local.
- **Evolución Diferencial**: Optimización global para evitar óptimos locales.
- **Múltiples inicios aleatorios**: Combina estrategias locales y globales para robustez.
""")
# Referencias
st.subheader("Referencias")
st.write("""
- [Optimization of Supercritical Carbon Dioxide Fluid Extraction of Medicinal Cannabis from Quebec](https://www.mdpi.com/2227-9717/11/7/1953).
- Herrero, M., Cifuentes, A., & Ibañez, E. (2006). Supercritical fluid extraction: Recent advances and applications. *Journal of Chromatography A*, 1131(1), 1–24.
- Turner, C., Mathiasson, L., & Lewis, G. (2001). Supercritical fluid extraction and chromatography. *Journal of Biochemical Analysis*, 121(3), 35–58.
""")
elif tabs == "Aplicación Interactiva":
st.header("Aplicación Interactiva")
st.write("A continuación, puedes cargar tus datos, realizar predicciones y optimizar el rendimiento del proceso de extracción de cannabinoides.")
# Opciones de selección de datos de ejemplo
st.subheader("Datos de Ejemplo")
usar_datos_exp = st.checkbox("Usar datos de ejemplo: datos_exp.csv")
usar_datos_process = st.checkbox("Usar datos de ejemplo: datos_process.csv")
# Inicializar variable de datos
data = None
# Verificar qué checkbox está seleccionado y cargar el archivo correspondiente
if usar_datos_exp and not usar_datos_process:
data = pd.read_csv("data_exp.csv")
st.success("Datos de ejemplo (datos_exp.csv) cargados exitosamente.")
st.dataframe(data, use_container_width=True) # Ajustar al ancho de la app
elif usar_datos_process and not usar_datos_exp:
data = pd.read_csv("data_process.csv")
st.success("Datos de ejemplo (datos_process.csv) cargados exitosamente.")
st.dataframe(data, use_container_width=True) # Ajustar al ancho de la app
elif usar_datos_exp and usar_datos_process:
st.error("Por favor, selecciona solo un conjunto de datos de ejemplo a la vez.")
# Opción para cargar datos personalizados
st.subheader("Carga tus Datos")
uploaded_file = st.file_uploader("Carga un archivo CSV con los datos experimentales:", type="csv")
if uploaded_file is not None:
# Leer datos cargados
data = pd.read_csv(uploaded_file)
st.success("Datos cargados exitosamente desde el archivo proporcionado.")
st.dataframe(data, use_container_width=True) # Ajustar al ancho de la app
# Validación para asegurarse de que se cargaron datos
if data is None:
st.warning("No se han cargado datos. Por favor, selecciona un archivo o usa datos de ejemplo.")
else:
st.write("### Datos listos para su análisis.")
# Definir el orden fijo de variables
variable_columns = ['Temperatura', 'Presión', 'Flujo_CO2', 'Tiempo']
# Extraer variables independientes y dependiente en el orden correcto
X = data[variable_columns]
y = data['Rendimiento']
# Generar términos cuadráticos (regresión polinómica de segundo grado)
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)
columnas_poly = poly.get_feature_names_out(X.columns)
# Ajustar modelo cuadrático
modelo = LinearRegression()
modelo.fit(X_poly, y)
# Predicciones del modelo
y_pred = modelo.predict(X_poly)
# Evaluación del modelo
st.subheader("Evaluación del Modelo Cuadrático")
st.write(f"**Error Cuadrático Medio (MSE):** {mean_squared_error(y, y_pred):.4f}")
st.write(f"**R² (Coeficiente de Determinación):** {r2_score(y, y_pred):.4f}")
# Resumen del modelo: coeficientes
# Visualización paralela usando columnas
col1, col2 = st.columns(2)
# En la columna 1, mostrar el DataFrame con términos y coeficientes, adaptado al ancho de la columna
with col1:
st.markdown("#### Términos y Coeficientes del Modelo")
# Crear un DataFrame con los coeficientes
coeficientes = pd.DataFrame({
'Término': columnas_poly,
'Coeficiente': modelo.coef_
})
coeficientes = coeficientes.sort_values(by='Coeficiente', ascending=False)
# Función para aplicar colores a los coeficientes
def color_coef(val):
color = 'red' if val > 0 else 'blue' # Los coeficientes positivos serán rojos, negativos azules
return f'background-color: {color}; color: white;'
# Aplicar estilo a la columna 'Coeficiente' para colorear los valores
styled_coef = coeficientes.style.applymap(color_coef, subset=['Coeficiente'])
# Mostrar el DataFrame estilizado y ajustado al ancho de la columna
st.dataframe(styled_coef, use_container_width=True)
# En la columna 2, mostrar el gráfico de importancia de las variables, adaptado al ancho de la columna
with col2:
st.markdown("#### Importancia de las Variables (Feature Importance)")
# Calcular la importancia de las variables (valor absoluto de los coeficientes)
coef_abs = np.abs(modelo.coef_) # Valor absoluto de los coeficientes
feature_importance = pd.DataFrame({
'Variable': columnas_poly,
'Importancia': coef_abs
}).sort_values(by='Importancia', ascending=False) # De mayor a menor
# Gráfico de barras horizontal con el eje Y invertido
fig_importance = go.Figure(go.Bar(
y=feature_importance['Variable'],
x=feature_importance['Importancia'],
orientation='h',
marker=dict(color='teal')
))
fig_importance.update_layout(
title="Importancia de las Variables en el Modelo Cuadrático",
xaxis_title="Importancia",
yaxis_title="Variables",
yaxis=dict(autorange="reversed"), # Invertir el eje Y
margin=dict(l=0, r=0, t=30, b=30) # Ajustar márgenes
)
st.plotly_chart(fig_importance, use_container_width=True)
# Superficies de respuesta dinámicas
st.subheader("Superficies de Respuesta")
# Selector de variables
eje_x = st.selectbox("Selecciona la variable para el eje X:", variable_columns, index=0)
eje_z = st.selectbox("Selecciona la variable para el eje Z:", variable_columns, index=1)
# Rango para generar puntos
x_range = np.linspace(X[eje_x].min(), X[eje_x].max(), 50)
z_range = np.linspace(X[eje_z].min(), X[eje_z].max(), 50)
X_grid, Z_grid = np.meshgrid(x_range, z_range)
# Preparar valores para las otras dos variables
otras_variables = [col for col in variable_columns if col not in [eje_x, eje_z]]
# Crear grilla de predicción con orden de columnas fijo
grid_data = []
for x_val, z_val in zip(X_grid.ravel(), Z_grid.ravel()):
# Crear un diccionario con todas las variables en el orden correcto
row_data = dict(zip(variable_columns, [
x_val if eje_x == 'Temperatura' else X['Temperatura'].mean(),
x_val if eje_x == 'Presión' else (z_val if eje_z == 'Presión' else X['Presión'].mean()),
x_val if eje_x == 'Flujo_CO2' else (z_val if eje_z == 'Flujo_CO2' else X['Flujo_CO2'].mean()),
x_val if eje_x == 'Tiempo' else (z_val if eje_z == 'Tiempo' else X['Tiempo'].mean())
]))
grid_data.append(row_data)
# Convertir a DataFrame con orden de columnas fijo
grid_df = pd.DataFrame(grid_data)[variable_columns]
# Transformar datos para predicciones
grid_poly = poly.transform(grid_df)
# Predecir valores
Y_grid = modelo.predict(grid_poly).reshape(X_grid.shape)
# Gráfico dinámico con Plotly
fig = go.Figure(data=[go.Surface(z=Y_grid, x=X_grid, y=Z_grid, colorscale='Viridis')])
fig.update_layout(
title=f"Superficie de Respuesta: {eje_x} vs {eje_z} vs Rendimiento",
scene=dict(
xaxis_title=eje_x,
yaxis_title=eje_z,
zaxis_title="Rendimiento (%)"
)
)
st.plotly_chart(fig, use_container_width=True)
# Análisis de sensibilidad
st.subheader("Análisis de Sensibilidad")
temp = st.slider("Temperatura (°C)", int(X['Temperatura'].min()), int(X['Temperatura'].max()), int(X['Temperatura'].mean()))
pres = st.slider("Presión (Bar)", int(X['Presión'].min()), int(X['Presión'].max()), int(X['Presión'].mean()))
flujo = st.slider("Flujo CO2 (g/min)", int(X['Flujo_CO2'].min()), int(X['Flujo_CO2'].max()), int(X['Flujo_CO2'].mean()))
tiempo = st.slider("Tiempo (h)", int(X['Tiempo'].min()), int(X['Tiempo'].max()), int(X['Tiempo'].mean()))
# Predicción para los valores seleccionados
entrada_sensibilidad = pd.DataFrame({'Temperatura': [temp], 'Presión': [pres], 'Flujo_CO2': [flujo], 'Tiempo': [tiempo]})
entrada_poly = poly.transform(entrada_sensibilidad)
prediccion = modelo.predict(entrada_poly)
st.write(f"**Rendimiento Predicho:** {prediccion[0]:.2f}%")
# Optimización de puntos mejorada
st.subheader("Determinación de Puntos Óptimos")
def objetivo(params):
"""Función objetivo para optimización."""
# Transformar parámetros a DataFrame
entrada = pd.DataFrame([params], columns=variable_columns)
entrada_poly = poly.transform(entrada)
return -modelo.predict(entrada_poly)[0] # Negativo para maximizar
# Métodos de Optimización
st.write("#### Comparación de Métodos de Optimización")
# Límites de las variables
limites = [(X[col].min(), X[col].max()) for col in variable_columns]
# 1. Optimización por L-BFGS-B (Método Local)
#st.write("##### Método L-BFGS-B (Optimización Local)")
x0 = [X[col].mean() for col in variable_columns]
resultado_lbfgs = minimize(
objetivo,
x0=x0,
bounds=limites,
method='L-BFGS-B'
)
# 2. Evolución Diferencial (Método Global)
#st.write("##### Evolución Diferencial (Optimización Global)")
resultado_de = differential_evolution(
objetivo,
bounds=limites,
strategy='best1bin',
popsize=15,
maxiter=100
)
# 3. Múltiples Inicios Aleatorios
#st.write("##### Múltiples Inicios Aleatorios")
def multi_start_optimize(num_starts=10):
resultados = []
for _ in range(num_starts):
# Punto inicial aleatorio
x0 = [np.random.uniform(low, high) for low, high in limites]
resultado = minimize(
objetivo,
x0=x0,
bounds=limites,
method='L-BFGS-B'
)
resultados.append((resultado, -resultado.fun))
# Encontrar el mejor resultado
return max(resultados, key=lambda x: x[1])
resultado_multi = multi_start_optimize()
# Mostrar resultados de optimización
metodos = [
("L-BFGS-B", resultado_lbfgs, -resultado_lbfgs.fun),
("Evolución Diferencial", resultado_de, -resultado_de.fun),
("Múltiples Inicios", resultado_multi[0], resultado_multi[1])
]
# Tabla comparativa de resultados
resultados_df = pd.DataFrame(columns=variable_columns + ['Rendimiento Predicho'])
for nombre, resultado, rendimiento in metodos:
if resultado.success:
fila = pd.DataFrame([list(resultado.x) + [rendimiento]],
columns=variable_columns + ['Rendimiento Predicho'])
fila.insert(0, 'Método', nombre)
resultados_df = pd.concat([resultados_df, fila], ignore_index=True)
# Mostrar tabla de resultados
#st.write("### Comparación de Resultados de Optimización")
st.dataframe(resultados_df)
# Seleccionar el mejor resultado
mejor_resultado = resultados_df.loc[resultados_df['Rendimiento Predicho'].idxmax()]
st.write("### Punto Óptimo Recomendado")
st.write(f"**Método:** {mejor_resultado['Método']}")
# Mostrar detalles del mejor punto
detalles_optimos = mejor_resultado[variable_columns].to_dict()
detalles_str = ", ".join([f"{col}: {val:.2f}" for col, val in detalles_optimos.items()])
st.write(f"**Punto Óptimo:** {detalles_str}")
st.write(f"**Rendimiento Máximo Predicho:** {mejor_resultado['Rendimiento Predicho']:.2f}%")
# Análisis de Incertidumbre
st.subheader("Análisis de Incertidumbre")
# Input para número de bootstraps
num_bootstraps = st.number_input(
"Número de Bootstraps",
min_value=10,
max_value=1000,
value=100,
step=10,
help="Número de remuestreos para el análisis de incertidumbre"
)
# Botón para realizar análisis de incertidumbre
if st.button("Realizar Análisis de Incertidumbre"):
with st.spinner('Realizando análisis de bootstrapping...'):
# Bootstrap para estimar intervalos de confianza
def bootstrap_optimize(num_bootstraps=num_bootstraps):
resultados_bootstrap = []
for _ in range(num_bootstraps):
# Muestreo con reemplazo
indices = np.random.randint(0, len(X), len(X))
X_boot = X.iloc[indices]
y_boot = y.iloc[indices]
# Ajustar modelo
poly_boot = PolynomialFeatures(degree=2, include_bias=False)
X_poly_boot = poly_boot.fit_transform(X_boot)
modelo_boot = LinearRegression()
modelo_boot.fit(X_poly_boot, y_boot)
# Definir nueva función objetivo
def objetivo_boot(params):
entrada = pd.DataFrame([params], columns=variable_columns)
entrada_poly = poly_boot.transform(entrada)
return -modelo_boot.predict(entrada_poly)[0]
# Optimizar
resultado = differential_evolution(
objetivo_boot,
bounds=limites,
strategy='best1bin',
popsize=15,
maxiter=100
)
resultados_bootstrap.append({
'Punto': resultado.x,
'Rendimiento': -resultado.fun
})
return resultados_bootstrap
# Realizar bootstrap
resultados_bootstrap = bootstrap_optimize()
# Convertir a DataFrame
bootstrap_df = pd.DataFrame(resultados_bootstrap)
# Calcular intervalos de confianza
intervalos_confianza = {}
for i, col in enumerate(variable_columns):
intervalos_confianza[col] = (
np.percentile(bootstrap_df['Punto'].apply(lambda x: x[i]), 2.5),
np.percentile(bootstrap_df['Punto'].apply(lambda x: x[i]), 97.5)
)
# Mostrar intervalos de confianza
st.write("### Intervalos de Confianza (95%)")
for col, (min_val, max_val) in intervalos_confianza.items():
st.write(f"**{col}:** [{min_val:.2f}, {max_val:.2f}]")
# Distribución de rendimientos
st.write("### Distribución de Rendimientos en Bootstrap")
fig_bootstrap = plt.figure(figsize=(10, 6))
plt.hist(bootstrap_df['Rendimiento'], bins=30, edgecolor='black')
plt.title(f'Distribución de Rendimientos Predichos (Bootstrap: {num_bootstraps})')
plt.xlabel('Rendimiento (%)')
plt.ylabel('Frecuencia')
st.pyplot(fig_bootstrap) |