C2MV commited on
Commit
7bcf996
·
verified ·
1 Parent(s): 3301441

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -35
app.py CHANGED
@@ -268,35 +268,37 @@ class RSM_BoxBehnken:
268
 
269
  def pareto_chart(self, model, title):
270
  """
271
- Genera un diagrama de Pareto para los efectos estandarizados de un modelo,
272
  incluyendo la línea de significancia.
273
  """
274
- # Calcular los efectos estandarizados
275
- tvalues = model.tvalues[1:] # Excluir la Intercept
276
- abs_tvalues = np.abs(tvalues)
277
- sorted_idx = np.argsort(abs_tvalues)[::-1]
278
- sorted_tvalues = abs_tvalues[sorted_idx]
279
- sorted_names = tvalues.index[sorted_idx]
 
280
 
281
- # Calcular el valor crítico de t para la línea de significancia
282
  alpha = 0.05 # Nivel de significancia
283
- dof = model.df_resid # Grados de libertad residuales
284
- t_critical = t.ppf(1 - alpha / 2, dof)
 
285
 
286
  # Crear el diagrama de Pareto
287
  fig = px.bar(
288
- x=sorted_tvalues.round(3),
289
  y=sorted_names,
290
  orientation='h',
291
- labels={'x': 'Efecto Estandarizado', 'y': 'Término'},
292
  title=title
293
  )
294
  fig.update_yaxes(autorange="reversed")
295
 
296
  # Agregar la línea de significancia
297
- fig.add_vline(x=t_critical, line_dash="dot",
298
- annotation_text=f"t crítico = {t_critical:.3f}",
299
- annotation_position="bottom right")
300
 
301
  return fig
302
 
@@ -327,7 +329,7 @@ class RSM_BoxBehnken:
327
  equation += f" + {coef:.3f}*{self.x3_name}^2"
328
 
329
  return equation
330
-
331
  def generate_prediction_table(self):
332
  """
333
  Genera una tabla con los valores actuales, predichos y residuales.
@@ -343,7 +345,7 @@ class RSM_BoxBehnken:
343
 
344
  def calculate_contribution_percentage(self):
345
  """
346
- Calcula el porcentaje de contribución de cada factor a la variabilidad de la respuesta (AIA).
347
  """
348
  if self.model_simplified is None:
349
  print("Error: Ajusta el modelo simplificado primero.")
@@ -351,18 +353,21 @@ class RSM_BoxBehnken:
351
 
352
  # ANOVA del modelo simplificado
353
  anova_table = sm.stats.anova_lm(self.model_simplified, typ=2)
354
-
355
- # Suma de cuadrados total
356
  ss_total = anova_table['sum_sq'].sum()
357
-
358
  # Crear tabla de contribución
359
  contribution_table = pd.DataFrame({
360
  'Factor': [],
361
  'Suma de Cuadrados': [],
 
362
  '% Contribución': []
363
  })
364
 
365
- # Calcular porcentaje de contribución para cada factor
 
 
366
  for index, row in anova_table.iterrows():
367
  if index != 'Residual':
368
  factor_name = index
@@ -374,11 +379,13 @@ class RSM_BoxBehnken:
374
  factor_name = f'{self.x3_name}^2'
375
 
376
  ss_factor = row['sum_sq']
 
377
  contribution_percentage = (ss_factor / ss_total) * 100
378
 
379
  contribution_table = pd.concat([contribution_table, pd.DataFrame({
380
  'Factor': [factor_name],
381
  'Suma de Cuadrados': [ss_factor],
 
382
  '% Contribución': [contribution_percentage]
383
  })], ignore_index=True)
384
 
@@ -395,10 +402,10 @@ class RSM_BoxBehnken:
395
  # --- ANOVA detallada ---
396
  # 1. Ajustar un modelo solo con los términos de primer orden y cuadráticos
397
  formula_reduced = f'{self.y_name} ~ {self.x1_name} + {self.x2_name} + {self.x3_name} + ' \
398
- f'I({self.x1_name}**2) + I({self.x2_name}**2) + I({self.x3_name}**2)'
399
  model_reduced = smf.ols(formula_reduced, data=self.data).fit()
400
 
401
- # 2. ANOVA del modelo reducido (para obtener la suma de cuadrados de la regresión)
402
  anova_reduced = sm.stats.anova_lm(model_reduced, typ=2)
403
 
404
  # 3. Suma de cuadrados total
@@ -436,7 +443,10 @@ class RSM_BoxBehnken:
436
  ms_lack_of_fit = ss_lack_of_fit / df_lack_of_fit if not np.isnan(ss_lack_of_fit) else np.nan
437
  ms_pure_error = ss_pure_error / df_pure_error if not np.isnan(ss_pure_error) else np.nan
438
 
439
- # 11. Estadístico F y valor p para la falta de ajuste
 
 
 
440
  f_lack_of_fit = ms_lack_of_fit / ms_pure_error if not np.isnan(ms_lack_of_fit) else np.nan
441
  p_lack_of_fit = 1 - f.cdf(f_lack_of_fit, df_lack_of_fit, df_pure_error) if not np.isnan(f_lack_of_fit) else np.nan
442
 
@@ -446,22 +456,31 @@ class RSM_BoxBehnken:
446
  'Suma de Cuadrados': [ss_regression, ss_residual, ss_lack_of_fit, ss_pure_error, ss_total],
447
  'Grados de Libertad': [df_regression, df_residual, df_lack_of_fit, df_pure_error, df_total],
448
  'Cuadrado Medio': [ms_regression, ms_residual, ms_lack_of_fit, ms_pure_error, np.nan],
449
- 'F': [np.nan, np.nan, f_lack_of_fit, np.nan, np.nan],
450
- 'Valor p': [np.nan, np.nan, p_lack_of_fit, np.nan, np.nan]
451
  })
452
 
453
- # Calcular la suma de cuadrados y grados de libertad para la curvatura
454
- ss_curvature = anova_reduced['sum_sq'][f'I({self.x1_name} ** 2)'] + anova_reduced['sum_sq'][f'I({self.x2_name} ** 2)'] + anova_reduced['sum_sq'][f'I({self.x3_name} ** 2)']
 
 
455
  df_curvature = 3
 
 
 
456
 
457
  # Añadir la fila de curvatura a la tabla ANOVA
458
- detailed_anova_table.loc[len(detailed_anova_table)] = ['Curvatura', ss_curvature, df_curvature, ss_curvature / df_curvature, np.nan, np.nan]
 
 
 
 
 
 
 
459
 
460
- # Reorganizar las filas para que la curvatura aparezca después de la regresión
461
- detailed_anova_table = detailed_anova_table.reindex([0, 5, 1, 2, 3, 4])
462
-
463
- # Resetear el índice para que sea consecutivo
464
- detailed_anova_table = detailed_anova_table.reset_index(drop=True)
465
 
466
  return detailed_anova_table.round(3)
467
 
@@ -918,4 +937,4 @@ def main():
918
  interface.launch(share=True)
919
 
920
  if __name__ == "__main__":
921
- main()
 
268
 
269
  def pareto_chart(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
+ # F = (coef/std_err)^2 = t^2
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
284
+ dof_num = 1 # Grados de libertad del numerador (cada término)
285
+ dof_den = model.df_resid # Grados de libertad residuales
286
+ f_critical = f.ppf(1 - alpha, dof_num, dof_den)
287
 
288
  # Crear el diagrama de Pareto
289
  fig = px.bar(
290
+ x=sorted_fvalues.round(3),
291
  y=sorted_names,
292
  orientation='h',
293
+ labels={'x': 'Estadístico F', 'y': 'Término'},
294
  title=title
295
  )
296
  fig.update_yaxes(autorange="reversed")
297
 
298
  # Agregar la línea de significancia
299
+ fig.add_vline(x=f_critical, line_dash="dot",
300
+ annotation_text=f"F crítico = {f_critical:.3f}",
301
+ annotation_position="bottom right")
302
 
303
  return fig
304
 
 
329
  equation += f" + {coef:.3f}*{self.x3_name}^2"
330
 
331
  return equation
332
+
333
  def generate_prediction_table(self):
334
  """
335
  Genera una tabla con los valores actuales, predichos y residuales.
 
345
 
346
  def calculate_contribution_percentage(self):
347
  """
348
+ Calcula el porcentaje de contribución de cada factor usando estadísticos F.
349
  """
350
  if self.model_simplified is None:
351
  print("Error: Ajusta el modelo simplificado primero.")
 
353
 
354
  # ANOVA del modelo simplificado
355
  anova_table = sm.stats.anova_lm(self.model_simplified, typ=2)
356
+
357
+ # Calcular las sumas de cuadrados ajustadas
358
  ss_total = anova_table['sum_sq'].sum()
359
+
360
  # Crear tabla de contribución
361
  contribution_table = pd.DataFrame({
362
  'Factor': [],
363
  'Suma de Cuadrados': [],
364
+ 'Estadístico F': [],
365
  '% Contribución': []
366
  })
367
 
368
+ # Calcular estadísticos F y porcentaje de contribución para cada factor
369
+ ms_error = anova_table.loc['Residual', 'sum_sq'] / anova_table.loc['Residual', 'df']
370
+
371
  for index, row in anova_table.iterrows():
372
  if index != 'Residual':
373
  factor_name = index
 
379
  factor_name = f'{self.x3_name}^2'
380
 
381
  ss_factor = row['sum_sq']
382
+ f_stat = (ss_factor / row['df']) / ms_error
383
  contribution_percentage = (ss_factor / ss_total) * 100
384
 
385
  contribution_table = pd.concat([contribution_table, pd.DataFrame({
386
  'Factor': [factor_name],
387
  'Suma de Cuadrados': [ss_factor],
388
+ 'Estadístico F': [f_stat],
389
  '% Contribución': [contribution_percentage]
390
  })], ignore_index=True)
391
 
 
402
  # --- ANOVA detallada ---
403
  # 1. Ajustar un modelo solo con los términos de primer orden y cuadráticos
404
  formula_reduced = f'{self.y_name} ~ {self.x1_name} + {self.x2_name} + {self.x3_name} + ' \
405
+ f'I({self.x1_name}**2) + I({self.x2_name}**2) + I({self.x3_name}**2)'
406
  model_reduced = smf.ols(formula_reduced, data=self.data).fit()
407
 
408
+ # 2. ANOVA del modelo reducido
409
  anova_reduced = sm.stats.anova_lm(model_reduced, typ=2)
410
 
411
  # 3. Suma de cuadrados total
 
443
  ms_lack_of_fit = ss_lack_of_fit / df_lack_of_fit if not np.isnan(ss_lack_of_fit) else np.nan
444
  ms_pure_error = ss_pure_error / df_pure_error if not np.isnan(ss_pure_error) else np.nan
445
 
446
+ # 11. Estadísticos F y valores p
447
+ f_regression = ms_regression / ms_residual
448
+ p_regression = 1 - f.cdf(f_regression, df_regression, df_residual)
449
+
450
  f_lack_of_fit = ms_lack_of_fit / ms_pure_error if not np.isnan(ms_lack_of_fit) else np.nan
451
  p_lack_of_fit = 1 - f.cdf(f_lack_of_fit, df_lack_of_fit, df_pure_error) if not np.isnan(f_lack_of_fit) else np.nan
452
 
 
456
  'Suma de Cuadrados': [ss_regression, ss_residual, ss_lack_of_fit, ss_pure_error, ss_total],
457
  'Grados de Libertad': [df_regression, df_residual, df_lack_of_fit, df_pure_error, df_total],
458
  'Cuadrado Medio': [ms_regression, ms_residual, ms_lack_of_fit, ms_pure_error, np.nan],
459
+ 'F': [f_regression, np.nan, f_lack_of_fit, np.nan, np.nan],
460
+ 'Valor p': [p_regression, np.nan, p_lack_of_fit, np.nan, np.nan]
461
  })
462
 
463
+ # Calcular la suma de cuadrados y estadísticos F para la curvatura
464
+ ss_curvature = anova_reduced['sum_sq'][f'I({self.x1_name} ** 2)'] + \
465
+ anova_reduced['sum_sq'][f'I({self.x2_name} ** 2)'] + \
466
+ anova_reduced['sum_sq'][f'I({self.x3_name} ** 2)']
467
  df_curvature = 3
468
+ ms_curvature = ss_curvature / df_curvature
469
+ f_curvature = ms_curvature / ms_residual
470
+ p_curvature = 1 - f.cdf(f_curvature, df_curvature, df_residual)
471
 
472
  # Añadir la fila de curvatura a la tabla ANOVA
473
+ detailed_anova_table.loc[len(detailed_anova_table)] = [
474
+ 'Curvatura',
475
+ ss_curvature,
476
+ df_curvature,
477
+ ms_curvature,
478
+ f_curvature,
479
+ p_curvature
480
+ ]
481
 
482
+ # Reorganizar las filas y resetear el índice
483
+ detailed_anova_table = detailed_anova_table.reindex([0, 5, 1, 2, 3, 4]).reset_index(drop=True)
 
 
 
484
 
485
  return detailed_anova_table.round(3)
486
 
 
937
  interface.launch(share=True)
938
 
939
  if __name__ == "__main__":
940
+ main()