Update app.py
Browse files
app.py
CHANGED
|
@@ -62,7 +62,7 @@ class RSM_BoxBehnken:
|
|
| 62 |
self.model = smf.ols(formula, data=self.data).fit()
|
| 63 |
print("Modelo Completo:")
|
| 64 |
print(self.model.summary())
|
| 65 |
-
return self.model, self.
|
| 66 |
|
| 67 |
def fit_simplified_model(self):
|
| 68 |
"""
|
|
@@ -73,8 +73,8 @@ class RSM_BoxBehnken:
|
|
| 73 |
self.model_simplified = smf.ols(formula, data=self.data).fit()
|
| 74 |
print("\nModelo Simplificado:")
|
| 75 |
print(self.model_simplified.summary())
|
| 76 |
-
return self.model_simplified, self.
|
| 77 |
-
|
| 78 |
def optimize(self, method='Nelder-Mead'):
|
| 79 |
"""
|
| 80 |
Encuentra los niveles 贸ptimos de los factores para maximizar la respuesta usando el modelo simplificado.
|
|
@@ -266,18 +266,20 @@ class RSM_BoxBehnken:
|
|
| 266 |
levels = self.get_levels(variable_name)
|
| 267 |
return -1 + 2 * (natural_value - levels[0]) / (levels[-1] - levels[0])
|
| 268 |
|
| 269 |
-
def
|
| 270 |
"""
|
| 271 |
Genera un diagrama de Pareto para los efectos usando estad铆sticos F,
|
| 272 |
incluyendo la l铆nea de significancia.
|
| 273 |
"""
|
| 274 |
# Calcular los estad铆sticos F para cada t茅rmino
|
| 275 |
-
|
| 276 |
-
fvalues = model.tvalues[1:]**2 # Excluir la Intercept y convertir t a F
|
| 277 |
abs_fvalues = np.abs(fvalues)
|
| 278 |
sorted_idx = np.argsort(abs_fvalues)[::-1]
|
| 279 |
sorted_fvalues = abs_fvalues[sorted_idx]
|
| 280 |
sorted_names = fvalues.index[sorted_idx]
|
|
|
|
|
|
|
|
|
|
| 281 |
|
| 282 |
# Calcular el valor cr铆tico de F para la l铆nea de significancia
|
| 283 |
alpha = 0.05 # Nivel de significancia
|
|
@@ -301,6 +303,43 @@ class RSM_BoxBehnken:
|
|
| 301 |
annotation_position="bottom right")
|
| 302 |
|
| 303 |
return fig
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
|
| 305 |
def get_simplified_equation(self):
|
| 306 |
"""
|
|
@@ -343,81 +382,9 @@ class RSM_BoxBehnken:
|
|
| 343 |
|
| 344 |
return self.data[[self.y_name, 'Predicho', 'Residual']].round(3)
|
| 345 |
|
| 346 |
-
def
|
| 347 |
"""
|
| 348 |
-
Calcula
|
| 349 |
-
"""
|
| 350 |
-
if self.model_simplified is None:
|
| 351 |
-
print("Error: Ajusta el modelo simplificado primero.")
|
| 352 |
-
return None
|
| 353 |
-
|
| 354 |
-
# ANOVA del modelo simplificado
|
| 355 |
-
anova_table = sm.stats.anova_lm(self.model_simplified, typ=2)
|
| 356 |
-
|
| 357 |
-
# Suma de cuadrados total
|
| 358 |
-
ss_total = anova_table['sum_sq'].sum()
|
| 359 |
-
|
| 360 |
-
# Crear tabla de contribuci贸n
|
| 361 |
-
contribution_table = pd.DataFrame({
|
| 362 |
-
'Fuente de Variaci贸n': [],
|
| 363 |
-
'Suma de Cuadrados': [],
|
| 364 |
-
'Grados de Libertad': [],
|
| 365 |
-
'Cuadrado Medio': [],
|
| 366 |
-
'F': [],
|
| 367 |
-
'Valor p': [],
|
| 368 |
-
'% Contribuci贸n': []
|
| 369 |
-
})
|
| 370 |
-
|
| 371 |
-
# Calcular estad铆sticos F y porcentaje de contribuci贸n para cada factor
|
| 372 |
-
ms_error = anova_table.loc['Residual', 'sum_sq'] / anova_table.loc['Residual', 'df']
|
| 373 |
-
|
| 374 |
-
for index, row in anova_table.iterrows():
|
| 375 |
-
if index != 'Residual':
|
| 376 |
-
factor_name = index
|
| 377 |
-
if factor_name == f'I({self.x1_name} ** 2)':
|
| 378 |
-
factor_name = f'{self.x1_name}^2'
|
| 379 |
-
elif factor_name == f'I({self.x2_name} ** 2)':
|
| 380 |
-
factor_name = f'{self.x2_name}^2'
|
| 381 |
-
elif factor_name == f'I({self.x3_name} ** 2)':
|
| 382 |
-
factor_name = f'{self.x3_name}^2'
|
| 383 |
-
|
| 384 |
-
ss_factor = row['sum_sq']
|
| 385 |
-
df_factor = row['df']
|
| 386 |
-
ms_factor = ss_factor / df_factor
|
| 387 |
-
f_stat = ms_factor / ms_error
|
| 388 |
-
p_value = f.sf(f_stat, df_factor, anova_table.loc['Residual', 'df'])
|
| 389 |
-
contribution_percentage = (ss_factor / ss_total) * 100
|
| 390 |
-
|
| 391 |
-
contribution_table = pd.concat([contribution_table, pd.DataFrame({
|
| 392 |
-
'Fuente de Variaci贸n': [factor_name],
|
| 393 |
-
'Suma de Cuadrados': [ss_factor],
|
| 394 |
-
'Grados de Libertad': [df_factor],
|
| 395 |
-
'Cuadrado Medio': [ms_factor],
|
| 396 |
-
'F': [f_stat],
|
| 397 |
-
'Valor p': [p_value],
|
| 398 |
-
'% Contribuci贸n': [contribution_percentage]
|
| 399 |
-
})], ignore_index=True)
|
| 400 |
-
|
| 401 |
-
# Calcular estad铆stico F global y su valor p
|
| 402 |
-
f_global = anova_table['sum_sq'][:-1].sum() / anova_table['df'][:-1].sum() / ms_error
|
| 403 |
-
p_global = f.sf(f_global, anova_table['df'][:-1].sum(), anova_table.loc['Residual', 'df'])
|
| 404 |
-
|
| 405 |
-
# Agregar fila para el estad铆stico F global
|
| 406 |
-
contribution_table = pd.concat([contribution_table, pd.DataFrame({
|
| 407 |
-
'Fuente de Variaci贸n': ['F global'],
|
| 408 |
-
'Suma de Cuadrados': [np.nan],
|
| 409 |
-
'Grados de Libertad': [np.nan],
|
| 410 |
-
'Cuadrado Medio': [np.nan],
|
| 411 |
-
'F': [f_global],
|
| 412 |
-
'Valor p': [p_global],
|
| 413 |
-
'% Contribuci贸n': [np.nan]
|
| 414 |
-
})], ignore_index=True)
|
| 415 |
-
|
| 416 |
-
return contribution_table.round(3)
|
| 417 |
-
|
| 418 |
-
def calculate_detailed_anova(self):
|
| 419 |
-
"""
|
| 420 |
-
Calcula la tabla ANOVA detallada con la descomposici贸n del error residual.
|
| 421 |
"""
|
| 422 |
if self.model_simplified is None:
|
| 423 |
print("Error: Ajusta el modelo simplificado primero.")
|
|
@@ -502,6 +469,9 @@ class RSM_BoxBehnken:
|
|
| 502 |
f_curvature,
|
| 503 |
p_curvature
|
| 504 |
]
|
|
|
|
|
|
|
|
|
|
| 505 |
|
| 506 |
# Reorganizar las filas y resetear el 铆ndice
|
| 507 |
detailed_anova_table = detailed_anova_table.reindex([0, 5, 1, 2, 3, 4]).reset_index(drop=True)
|
|
@@ -513,13 +483,11 @@ class RSM_BoxBehnken:
|
|
| 513 |
Obtiene todas las tablas generadas para ser exportadas a Excel.
|
| 514 |
"""
|
| 515 |
prediction_table = self.generate_prediction_table()
|
| 516 |
-
|
| 517 |
-
detailed_anova_table = self.calculate_detailed_anova()
|
| 518 |
|
| 519 |
return {
|
| 520 |
'Predicciones': prediction_table,
|
| 521 |
-
'
|
| 522 |
-
'ANOVA Detallada': detailed_anova_table
|
| 523 |
}
|
| 524 |
|
| 525 |
def save_figures_to_zip(self):
|
|
@@ -672,16 +640,15 @@ def load_data(x1_name, x2_name, x3_name, y_name, x1_levels_str, x2_levels_str, x
|
|
| 672 |
|
| 673 |
def fit_and_optimize_model():
|
| 674 |
if 'rsm' not in globals():
|
| 675 |
-
return [None]*
|
| 676 |
|
| 677 |
# Ajustar modelos y optimizar
|
| 678 |
-
model_completo,
|
| 679 |
-
model_simplificado,
|
| 680 |
optimization_table = rsm.optimize()
|
| 681 |
equation = rsm.get_simplified_equation()
|
| 682 |
prediction_table = rsm.generate_prediction_table()
|
| 683 |
-
|
| 684 |
-
anova_table = rsm.calculate_detailed_anova()
|
| 685 |
|
| 686 |
# Generar todas las figuras y almacenarlas
|
| 687 |
rsm.generate_all_plots()
|
|
@@ -698,13 +665,14 @@ def fit_and_optimize_model():
|
|
| 698 |
|
| 699 |
return (
|
| 700 |
model_completo.summary().as_html(),
|
| 701 |
-
|
|
|
|
| 702 |
model_simplificado.summary().as_html(),
|
| 703 |
-
|
|
|
|
| 704 |
equation_formatted,
|
| 705 |
optimization_table,
|
| 706 |
prediction_table,
|
| 707 |
-
contribution_table,
|
| 708 |
anova_table,
|
| 709 |
zip_path, # Ruta del ZIP de gr谩ficos
|
| 710 |
excel_path # Ruta del Excel de tablas
|
|
@@ -831,16 +799,17 @@ def create_gradio_interface():
|
|
| 831 |
fit_button = gr.Button("Ajustar Modelo y Optimizar")
|
| 832 |
gr.Markdown("**Modelo Completo**")
|
| 833 |
model_completo_output = gr.HTML()
|
| 834 |
-
|
|
|
|
| 835 |
gr.Markdown("**Modelo Simplificado**")
|
| 836 |
model_simplificado_output = gr.HTML()
|
| 837 |
-
|
|
|
|
| 838 |
gr.Markdown("**Ecuaci贸n del Modelo Simplificado**")
|
| 839 |
equation_output = gr.HTML()
|
| 840 |
optimization_table_output = gr.Dataframe(label="Tabla de Optimizaci贸n", interactive=False)
|
| 841 |
prediction_table_output = gr.Dataframe(label="Tabla de Predicciones", interactive=False)
|
| 842 |
-
|
| 843 |
-
anova_table_output = gr.Dataframe(label="Tabla ANOVA Detallada", interactive=False)
|
| 844 |
gr.Markdown("## Descargar Todas las Tablas")
|
| 845 |
download_excel_button = gr.DownloadButton("Descargar Tablas en Excel")
|
| 846 |
download_word_button = gr.DownloadButton("Descargar Tablas en Word")
|
|
@@ -874,13 +843,14 @@ def create_gradio_interface():
|
|
| 874 |
inputs=[],
|
| 875 |
outputs=[
|
| 876 |
model_completo_output,
|
| 877 |
-
|
|
|
|
| 878 |
model_simplificado_output,
|
| 879 |
-
|
|
|
|
| 880 |
equation_output,
|
| 881 |
optimization_table_output,
|
| 882 |
prediction_table_output,
|
| 883 |
-
contribution_table_output,
|
| 884 |
anova_table_output,
|
| 885 |
download_all_plots_button, # Ruta del ZIP de gr谩ficos
|
| 886 |
download_excel_button # Ruta del Excel de tablas
|
|
@@ -961,4 +931,5 @@ def main():
|
|
| 961 |
interface.launch(share=True)
|
| 962 |
|
| 963 |
if __name__ == "__main__":
|
| 964 |
-
main()
|
|
|
|
|
|
| 62 |
self.model = smf.ols(formula, data=self.data).fit()
|
| 63 |
print("Modelo Completo:")
|
| 64 |
print(self.model.summary())
|
| 65 |
+
return self.model, self.pareto_chart_f(self.model, "Pareto - Modelo Completo (F)"), self.pareto_chart_t(self.model, "Pareto - Modelo Completo (t)")
|
| 66 |
|
| 67 |
def fit_simplified_model(self):
|
| 68 |
"""
|
|
|
|
| 73 |
self.model_simplified = smf.ols(formula, data=self.data).fit()
|
| 74 |
print("\nModelo Simplificado:")
|
| 75 |
print(self.model_simplified.summary())
|
| 76 |
+
return self.model_simplified, self.pareto_chart_f(self.model_simplified, "Pareto - Modelo Simplificado (F)"), self.pareto_chart_t(self.model_simplified, "Pareto - Modelo Simplificado (t)")
|
| 77 |
+
|
| 78 |
def optimize(self, method='Nelder-Mead'):
|
| 79 |
"""
|
| 80 |
Encuentra los niveles 贸ptimos de los factores para maximizar la respuesta usando el modelo simplificado.
|
|
|
|
| 266 |
levels = self.get_levels(variable_name)
|
| 267 |
return -1 + 2 * (natural_value - levels[0]) / (levels[-1] - levels[0])
|
| 268 |
|
| 269 |
+
def pareto_chart_f(self, model, title):
|
| 270 |
"""
|
| 271 |
Genera un diagrama de Pareto para los efectos usando estad铆sticos F,
|
| 272 |
incluyendo la l铆nea de significancia.
|
| 273 |
"""
|
| 274 |
# Calcular los estad铆sticos F para cada t茅rmino
|
| 275 |
+
fvalues = model.fvalues[1:] # Excluir la Intercept
|
|
|
|
| 276 |
abs_fvalues = np.abs(fvalues)
|
| 277 |
sorted_idx = np.argsort(abs_fvalues)[::-1]
|
| 278 |
sorted_fvalues = abs_fvalues[sorted_idx]
|
| 279 |
sorted_names = fvalues.index[sorted_idx]
|
| 280 |
+
|
| 281 |
+
# Cambiar I() por "" en los nombres de los terminos
|
| 282 |
+
sorted_names = sorted_names.str.replace('I(','').str.replace('**2)','^2').str.replace(' * ', '路')
|
| 283 |
|
| 284 |
# Calcular el valor cr铆tico de F para la l铆nea de significancia
|
| 285 |
alpha = 0.05 # Nivel de significancia
|
|
|
|
| 303 |
annotation_position="bottom right")
|
| 304 |
|
| 305 |
return fig
|
| 306 |
+
|
| 307 |
+
def pareto_chart_t(self, model, title):
|
| 308 |
+
"""
|
| 309 |
+
Genera un diagrama de Pareto para los efectos usando estad铆sticos t,
|
| 310 |
+
incluyendo la l铆nea de significancia.
|
| 311 |
+
"""
|
| 312 |
+
# Calcular los estad铆sticos t para cada t茅rmino
|
| 313 |
+
tvalues = model.tvalues[1:] # Excluir la Intercept
|
| 314 |
+
abs_tvalues = np.abs(tvalues)
|
| 315 |
+
sorted_idx = np.argsort(abs_tvalues)[::-1]
|
| 316 |
+
sorted_tvalues = abs_tvalues[sorted_idx]
|
| 317 |
+
sorted_names = tvalues.index[sorted_idx]
|
| 318 |
+
|
| 319 |
+
# Cambiar I() por "" en los nombres de los terminos
|
| 320 |
+
sorted_names = sorted_names.str.replace('I(','').str.replace('**2)','^2').str.replace(' * ', '路')
|
| 321 |
+
|
| 322 |
+
# Calcular el valor cr铆tico de t para la l铆nea de significancia
|
| 323 |
+
alpha = 0.05 # Nivel de significancia
|
| 324 |
+
dof = model.df_resid # Grados de libertad residuales
|
| 325 |
+
t_critical = t.ppf(1 - alpha / 2, dof)
|
| 326 |
+
|
| 327 |
+
# Crear el diagrama de Pareto
|
| 328 |
+
fig = px.bar(
|
| 329 |
+
x=sorted_tvalues.round(3),
|
| 330 |
+
y=sorted_names,
|
| 331 |
+
orientation='h',
|
| 332 |
+
labels={'x': 'Estad铆stico t', 'y': 'T茅rmino'},
|
| 333 |
+
title=title
|
| 334 |
+
)
|
| 335 |
+
fig.update_yaxes(autorange="reversed")
|
| 336 |
+
|
| 337 |
+
# Agregar la l铆nea de significancia
|
| 338 |
+
fig.add_vline(x=t_critical, line_dash="dot",
|
| 339 |
+
annotation_text=f"t cr铆tico = {t_critical:.3f}",
|
| 340 |
+
annotation_position="bottom right")
|
| 341 |
+
|
| 342 |
+
return fig
|
| 343 |
|
| 344 |
def get_simplified_equation(self):
|
| 345 |
"""
|
|
|
|
| 382 |
|
| 383 |
return self.data[[self.y_name, 'Predicho', 'Residual']].round(3)
|
| 384 |
|
| 385 |
+
def calculate_anova_table(self):
|
| 386 |
"""
|
| 387 |
+
Calcula la tabla ANOVA detallada, incluyendo la contribuci贸n porcentual.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
"""
|
| 389 |
if self.model_simplified is None:
|
| 390 |
print("Error: Ajusta el modelo simplificado primero.")
|
|
|
|
| 469 |
f_curvature,
|
| 470 |
p_curvature
|
| 471 |
]
|
| 472 |
+
|
| 473 |
+
# --- Agregar % de Contribuci贸n ---
|
| 474 |
+
detailed_anova_table['% Contribuci贸n'] = (detailed_anova_table['Suma de Cuadrados'] / ss_total) * 100
|
| 475 |
|
| 476 |
# Reorganizar las filas y resetear el 铆ndice
|
| 477 |
detailed_anova_table = detailed_anova_table.reindex([0, 5, 1, 2, 3, 4]).reset_index(drop=True)
|
|
|
|
| 483 |
Obtiene todas las tablas generadas para ser exportadas a Excel.
|
| 484 |
"""
|
| 485 |
prediction_table = self.generate_prediction_table()
|
| 486 |
+
anova_table = self.calculate_anova_table()
|
|
|
|
| 487 |
|
| 488 |
return {
|
| 489 |
'Predicciones': prediction_table,
|
| 490 |
+
'ANOVA': anova_table,
|
|
|
|
| 491 |
}
|
| 492 |
|
| 493 |
def save_figures_to_zip(self):
|
|
|
|
| 640 |
|
| 641 |
def fit_and_optimize_model():
|
| 642 |
if 'rsm' not in globals():
|
| 643 |
+
return [None]*12 # Ajustar el n煤mero de outputs
|
| 644 |
|
| 645 |
# Ajustar modelos y optimizar
|
| 646 |
+
model_completo, pareto_completo_f, pareto_completo_t = rsm.fit_model()
|
| 647 |
+
model_simplificado, pareto_simplificado_f, pareto_simplificado_t = rsm.fit_simplified_model()
|
| 648 |
optimization_table = rsm.optimize()
|
| 649 |
equation = rsm.get_simplified_equation()
|
| 650 |
prediction_table = rsm.generate_prediction_table()
|
| 651 |
+
anova_table = rsm.calculate_anova_table()
|
|
|
|
| 652 |
|
| 653 |
# Generar todas las figuras y almacenarlas
|
| 654 |
rsm.generate_all_plots()
|
|
|
|
| 665 |
|
| 666 |
return (
|
| 667 |
model_completo.summary().as_html(),
|
| 668 |
+
pareto_completo_f,
|
| 669 |
+
pareto_completo_t,
|
| 670 |
model_simplificado.summary().as_html(),
|
| 671 |
+
pareto_simplificado_f,
|
| 672 |
+
pareto_simplificado_t,
|
| 673 |
equation_formatted,
|
| 674 |
optimization_table,
|
| 675 |
prediction_table,
|
|
|
|
| 676 |
anova_table,
|
| 677 |
zip_path, # Ruta del ZIP de gr谩ficos
|
| 678 |
excel_path # Ruta del Excel de tablas
|
|
|
|
| 799 |
fit_button = gr.Button("Ajustar Modelo y Optimizar")
|
| 800 |
gr.Markdown("**Modelo Completo**")
|
| 801 |
model_completo_output = gr.HTML()
|
| 802 |
+
pareto_completo_f_output = gr.Plot()
|
| 803 |
+
pareto_completo_t_output = gr.Plot()
|
| 804 |
gr.Markdown("**Modelo Simplificado**")
|
| 805 |
model_simplificado_output = gr.HTML()
|
| 806 |
+
pareto_simplificado_f_output = gr.Plot()
|
| 807 |
+
pareto_simplificado_t_output = gr.Plot()
|
| 808 |
gr.Markdown("**Ecuaci贸n del Modelo Simplificado**")
|
| 809 |
equation_output = gr.HTML()
|
| 810 |
optimization_table_output = gr.Dataframe(label="Tabla de Optimizaci贸n", interactive=False)
|
| 811 |
prediction_table_output = gr.Dataframe(label="Tabla de Predicciones", interactive=False)
|
| 812 |
+
anova_table_output = gr.Dataframe(label="Tabla ANOVA", interactive=False)
|
|
|
|
| 813 |
gr.Markdown("## Descargar Todas las Tablas")
|
| 814 |
download_excel_button = gr.DownloadButton("Descargar Tablas en Excel")
|
| 815 |
download_word_button = gr.DownloadButton("Descargar Tablas en Word")
|
|
|
|
| 843 |
inputs=[],
|
| 844 |
outputs=[
|
| 845 |
model_completo_output,
|
| 846 |
+
pareto_completo_f_output,
|
| 847 |
+
pareto_completo_t_output,
|
| 848 |
model_simplificado_output,
|
| 849 |
+
pareto_simplificado_f_output,
|
| 850 |
+
pareto_simplificado_t_output,
|
| 851 |
equation_output,
|
| 852 |
optimization_table_output,
|
| 853 |
prediction_table_output,
|
|
|
|
| 854 |
anova_table_output,
|
| 855 |
download_all_plots_button, # Ruta del ZIP de gr谩ficos
|
| 856 |
download_excel_button # Ruta del Excel de tablas
|
|
|
|
| 931 |
interface.launch(share=True)
|
| 932 |
|
| 933 |
if __name__ == "__main__":
|
| 934 |
+
main()
|
| 935 |
+
|