Update app.py
Browse files
app.py
CHANGED
@@ -3,6 +3,10 @@ os.system('pip install gradio seaborn scipy scikit-learn openpyxl networkx pydan
|
|
3 |
|
4 |
from pydantic import BaseModel, ConfigDict
|
5 |
|
|
|
|
|
|
|
|
|
6 |
import numpy as np
|
7 |
import networkx as nx
|
8 |
import matplotlib.pyplot as plt
|
@@ -12,7 +16,6 @@ from sklearn.preprocessing import PolynomialFeatures
|
|
12 |
from sklearn.metrics import r2_score
|
13 |
from itertools import combinations
|
14 |
import tempfile
|
15 |
-
import pandas as pd
|
16 |
|
17 |
# Clase para el modelo de regresión
|
18 |
class RegressionModel:
|
@@ -29,7 +32,7 @@ class RegressionModel:
|
|
29 |
X_poly = self.poly.transform(X)
|
30 |
return self.model.predict(X_poly)
|
31 |
|
32 |
-
def
|
33 |
y_pred = self.predict(X)
|
34 |
return r2_score(y, y_pred)
|
35 |
|
@@ -68,8 +71,8 @@ class ExperimentalDesign:
|
|
68 |
self.model_variable1.fit(X, self.variable1_values)
|
69 |
self.model_variable2.fit(X, self.variable2_values)
|
70 |
|
71 |
-
self.r2_variable1 = self.model_variable1.
|
72 |
-
self.r2_variable2 = self.model_variable2.
|
73 |
|
74 |
# Clase para el análisis de teoría de grafos
|
75 |
class GraphTheoryAnalysis:
|
@@ -81,48 +84,16 @@ class GraphTheoryAnalysis:
|
|
81 |
def set_matrices_and_values(self):
|
82 |
self.all_factors = list(self.experiment.factor_values.keys())
|
83 |
|
84 |
-
def build_graph(self, level=
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
Args:
|
89 |
-
level (int): Nivel de combinación (2 o 3).
|
90 |
-
r2_threshold (float): Umbral de R² para incluir una interacción.
|
91 |
-
"""
|
92 |
-
if level not in [2, 3]:
|
93 |
-
raise ValueError("Nivel de combinación no soportado. Debe ser 2 o 3.")
|
94 |
-
|
95 |
-
self.graph.clear() # Limpiar grafo existente
|
96 |
-
|
97 |
-
if level >= 2:
|
98 |
-
# Construir interacciones de nivel 2
|
99 |
-
for pair in combinations(self.all_factors, 2):
|
100 |
-
self.experiment.set_active_factors(list(pair))
|
101 |
-
self.experiment.fit_models()
|
102 |
-
r2 = (self.experiment.r2_variable1 + self.experiment.r2_variable2) / 2
|
103 |
-
if r2 >= r2_threshold:
|
104 |
-
self.graph.add_edge(pair[0], pair[1], weight=r2)
|
105 |
-
|
106 |
-
if level == 3:
|
107 |
-
# Calcular R² acumulado por factor
|
108 |
-
factor_r2 = {}
|
109 |
-
for factor in self.all_factors:
|
110 |
-
edges = [data['weight'] for u, v, data in self.graph.edges(data=True) if u == factor or v == factor]
|
111 |
-
factor_r2[factor] = sum(edges) / len(edges) if edges else 0
|
112 |
-
|
113 |
-
# Seleccionar los 3 factores con mayor R²
|
114 |
-
top_factors = sorted(factor_r2, key=factor_r2.get, reverse=True)[:3]
|
115 |
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
# Añadir interacciones entre los 3 factores seleccionados
|
120 |
-
for pair in combinations(top_factors, 2):
|
121 |
self.experiment.set_active_factors(list(pair))
|
122 |
self.experiment.fit_models()
|
123 |
r2 = (self.experiment.r2_variable1 + self.experiment.r2_variable2) / 2
|
124 |
-
|
125 |
-
self.graph.add_edge(pair[0], pair[1], weight=r2)
|
126 |
|
127 |
def visualize_graph(self, style='Style 1'):
|
128 |
pos = nx.spring_layout(self.graph)
|
@@ -154,12 +125,9 @@ class GraphTheoryAnalysis:
|
|
154 |
nx.draw_networkx_labels(self.graph, pos, font_size=font_size)
|
155 |
|
156 |
edge_weights = [self.graph[u][v]['weight'] for u, v in self.graph.edges()]
|
157 |
-
|
158 |
-
max_weight = max(edge_weights) if edge_weights else 1
|
159 |
-
normalized_weights = [weight / max_weight * 5 for weight in edge_weights]
|
160 |
-
nx.draw_networkx_edges(self.graph, pos, width=normalized_weights, edge_color=edge_color)
|
161 |
|
162 |
-
edge_labels =
|
163 |
nx.draw_networkx_edge_labels(self.graph, pos, edge_labels=edge_labels, font_size=font_size)
|
164 |
|
165 |
plt.title(f"Grafo de relaciones entre factores basado en R² ({style})")
|
@@ -173,38 +141,8 @@ class GraphTheoryAnalysis:
|
|
173 |
|
174 |
return temp_file.name
|
175 |
|
176 |
-
# Función para generar el diseño Box-Behnken para 3 factores
|
177 |
-
def generate_box_behnken(factors):
|
178 |
-
# Box-Behnken design for 3 factors
|
179 |
-
bb_design_3f = [
|
180 |
-
[-1, -1, 0],
|
181 |
-
[ 1, -1, 0],
|
182 |
-
[-1, 1, 0],
|
183 |
-
[ 1, 1, 0],
|
184 |
-
[-1, 0, -1],
|
185 |
-
[ 1, 0, -1],
|
186 |
-
[-1, 0, 1],
|
187 |
-
[ 1, 0, 1],
|
188 |
-
[ 0, -1, -1],
|
189 |
-
[ 0, 1, -1],
|
190 |
-
[ 0, -1, 1],
|
191 |
-
[ 0, 1, 1]
|
192 |
-
]
|
193 |
-
design = []
|
194 |
-
for row in bb_design_3f:
|
195 |
-
design.append(dict(zip(factors, row)))
|
196 |
-
return design
|
197 |
-
|
198 |
# Definición de la interfaz de Gradio
|
199 |
def analyze_design(level, pb_design, bb_design, variable1_values, variable2_values, style):
|
200 |
-
# Validar y convertir matrices de diseño a numpy arrays
|
201 |
-
try:
|
202 |
-
pb_design_np = np.array(pb_design, dtype=float)
|
203 |
-
bb_design_np = np.array(bb_design, dtype=float)
|
204 |
-
except ValueError:
|
205 |
-
return "Error: Asegúrate de que las matrices de diseño contienen solo números.", None, None
|
206 |
-
|
207 |
-
# Inicializar diseño experimental
|
208 |
experiment = ExperimentalDesign(regression_degree=2)
|
209 |
optimizer = GraphTheoryAnalysis(experiment)
|
210 |
|
@@ -215,85 +153,14 @@ def analyze_design(level, pb_design, bb_design, variable1_values, variable2_valu
|
|
215 |
'X4': [0.05, 0.5]
|
216 |
}
|
217 |
|
218 |
-
experiment.set_design(
|
219 |
experiment.set_factors(factor_values)
|
220 |
-
experiment.set_dependent_variables(np.array(variable1_values
|
221 |
|
222 |
optimizer.set_matrices_and_values()
|
223 |
-
optimizer.build_graph(level=level
|
224 |
graph_image_path = optimizer.visualize_graph(style=style)
|
225 |
-
|
226 |
-
if level == 3:
|
227 |
-
# Identificar los 3 factores más activos basados en R²
|
228 |
-
factor_r2 = {}
|
229 |
-
for factor in experiment.factor_values.keys():
|
230 |
-
# Filtrar las aristas que contienen el factor
|
231 |
-
edges = [data['weight'] for u, v, data in optimizer.graph.edges(data=True) if u == factor or v == factor]
|
232 |
-
factor_r2[factor] = sum(edges) / len(edges) if edges else 0
|
233 |
-
|
234 |
-
# Seleccionar los 3 factores con mayor R²
|
235 |
-
top_factors = sorted(factor_r2, key=factor_r2.get, reverse=True)[:3]
|
236 |
-
|
237 |
-
# Generar diseño Box-Behnken para los 3 factores
|
238 |
-
bb_design_3f = generate_box_behnken(top_factors)
|
239 |
-
|
240 |
-
# Simular datos de respuesta (puedes ajustar esta parte según tus necesidades)
|
241 |
-
# Aquí, simplemente generamos valores aleatorios para las respuestas
|
242 |
-
np.random.seed(42) # Para reproducibilidad
|
243 |
-
simulated_response1 = np.random.uniform(0.1, 1.0, len(bb_design_3f))
|
244 |
-
simulated_response2 = np.random.uniform(0.1, 1.0, len(bb_design_3f))
|
245 |
-
|
246 |
-
# Crear dataframe de resultados
|
247 |
-
bb_results = []
|
248 |
-
for i, design in enumerate(bb_design_3f):
|
249 |
-
row = design.copy()
|
250 |
-
row['Response 1'] = round(simulated_response1[i], 3)
|
251 |
-
row['Response 2'] = round(simulated_response2[i], 3)
|
252 |
-
bb_results.append(row)
|
253 |
-
|
254 |
-
# Convertir bb_design_used a DataFrame para mostrar
|
255 |
-
bb_design_used = bb_design_3f
|
256 |
-
headers = top_factors + ['Response 1', 'Response 2']
|
257 |
-
|
258 |
-
# Crear DataFrame para la matriz Box-Behnken usada
|
259 |
-
df_bb_used = pd.DataFrame(bb_design_used)
|
260 |
-
# Agregar respuestas al DataFrame
|
261 |
-
df_bb_used[['Response 1', 'Response 2']] = pd.DataFrame(bb_results)[['Response 1', 'Response 2']]
|
262 |
-
|
263 |
-
elif level == 2:
|
264 |
-
# Usar el diseño Box-Behnken ingresado por el usuario para 4 factores
|
265 |
-
bb_design_used = []
|
266 |
-
for row in bb_design:
|
267 |
-
design_row = { 'X1': row[0], 'X2': row[1], 'X3': row[2], 'X4': row[3] }
|
268 |
-
bb_design_used.append(design_row)
|
269 |
-
|
270 |
-
# Simular datos de respuesta (puedes ajustar esta parte según tus necesidades)
|
271 |
-
# Aquí, simplemente generamos valores aleatorios para las respuestas
|
272 |
-
np.random.seed(42) # Para reproducibilidad
|
273 |
-
simulated_response1 = np.random.uniform(0.1, 1.0, len(bb_design_used))
|
274 |
-
simulated_response2 = np.random.uniform(0.1, 1.0, len(bb_design_used))
|
275 |
-
|
276 |
-
# Crear dataframe de resultados
|
277 |
-
bb_results = []
|
278 |
-
for i, design in enumerate(bb_design_used):
|
279 |
-
row = design.copy()
|
280 |
-
row['Response 1'] = round(simulated_response1[i], 3)
|
281 |
-
row['Response 2'] = round(simulated_response2[i], 3)
|
282 |
-
bb_results.append(row)
|
283 |
-
|
284 |
-
headers = ['X1', 'X2', 'X3', 'X4', 'Response 1', 'Response 2']
|
285 |
-
|
286 |
-
# Crear DataFrame para la matriz Box-Behnken usada
|
287 |
-
df_bb_used = pd.DataFrame(bb_design_used)
|
288 |
-
# Agregar respuestas al DataFrame
|
289 |
-
df_bb_used[['Response 1', 'Response 2']] = pd.DataFrame(bb_results)[['Response 1', 'Response 2']]
|
290 |
-
else:
|
291 |
-
return "Error: Nivel de combinación inválido. Debe ser 2 o 3.", None, None
|
292 |
-
|
293 |
-
# Crear DataFrame para los datos simulados
|
294 |
-
df_simulated = df_bb_used.copy()
|
295 |
-
|
296 |
-
return graph_image_path, df_bb_used, df_simulated
|
297 |
|
298 |
# Matriz Plackett-Burman (por defecto)
|
299 |
default_pb_design = [
|
@@ -307,7 +174,7 @@ default_pb_design = [
|
|
307 |
[-1, -1, -1, -1]
|
308 |
]
|
309 |
|
310 |
-
# Matriz Box-Behnken (por defecto)
|
311 |
default_bb_design = [
|
312 |
[-1, -1, 0, 0],
|
313 |
[1, -1, 0, 0],
|
@@ -344,52 +211,16 @@ default_variable2_values = [0.362, 0.856, 0.177, 0.261, 0.946, 0.695, 0.892, 0.0
|
|
344 |
interface = gr.Interface(
|
345 |
fn=analyze_design,
|
346 |
inputs=[
|
347 |
-
gr.Slider(
|
348 |
-
gr.Dataframe(
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
row_count=(8, "fixed"),
|
354 |
-
col_count=(4, "fixed")
|
355 |
-
),
|
356 |
-
gr.Dataframe(
|
357 |
-
headers=["X1", "X2", "X3", "X4"],
|
358 |
-
value=default_bb_design,
|
359 |
-
label="Matriz 2 (Box-Behnken)",
|
360 |
-
datatype=["number"]*4,
|
361 |
-
row_count=(25, "fixed"),
|
362 |
-
col_count=(4, "fixed")
|
363 |
-
),
|
364 |
-
gr.Dataframe(
|
365 |
-
headers=["Variable 1"],
|
366 |
-
value=[[val] for val in default_variable1_values],
|
367 |
-
label="Valores de Variable 1",
|
368 |
-
datatype=["number"],
|
369 |
-
row_count=(8, "fixed"),
|
370 |
-
col_count=(1, "fixed")
|
371 |
-
),
|
372 |
-
gr.Dataframe(
|
373 |
-
headers=["Variable 2"],
|
374 |
-
value=[[val] for val in default_variable2_values],
|
375 |
-
label="Valores de Variable 2",
|
376 |
-
datatype=["number"],
|
377 |
-
row_count=(8, "fixed"),
|
378 |
-
col_count=(1, "fixed")
|
379 |
-
),
|
380 |
-
gr.Dropdown(
|
381 |
-
["Style 1", "Style 2", "Style 3", "Style 4"],
|
382 |
-
label="Estilo del Grafo",
|
383 |
-
value="Style 1"
|
384 |
-
)
|
385 |
-
],
|
386 |
-
outputs=[
|
387 |
-
gr.Image(label="Grafo de Relaciones entre Factores"),
|
388 |
-
gr.Dataframe(label="Matriz Box-Behnken Usada"),
|
389 |
-
gr.Dataframe(label="Datos Simulados para Box-Behnken")
|
390 |
],
|
391 |
-
|
392 |
-
|
|
|
393 |
)
|
394 |
|
395 |
# Ejecutar la interfaz
|
|
|
3 |
|
4 |
from pydantic import BaseModel, ConfigDict
|
5 |
|
6 |
+
class YourModel(BaseModel):
|
7 |
+
class Config:
|
8 |
+
arbitrary_types_allowed = True
|
9 |
+
|
10 |
import numpy as np
|
11 |
import networkx as nx
|
12 |
import matplotlib.pyplot as plt
|
|
|
16 |
from sklearn.metrics import r2_score
|
17 |
from itertools import combinations
|
18 |
import tempfile
|
|
|
19 |
|
20 |
# Clase para el modelo de regresión
|
21 |
class RegressionModel:
|
|
|
32 |
X_poly = self.poly.transform(X)
|
33 |
return self.model.predict(X_poly)
|
34 |
|
35 |
+
def r2_score(self, X, y):
|
36 |
y_pred = self.predict(X)
|
37 |
return r2_score(y, y_pred)
|
38 |
|
|
|
71 |
self.model_variable1.fit(X, self.variable1_values)
|
72 |
self.model_variable2.fit(X, self.variable2_values)
|
73 |
|
74 |
+
self.r2_variable1 = self.model_variable1.r2_score(X, self.variable1_values)
|
75 |
+
self.r2_variable2 = self.model_variable2.r2_score(X, self.variable2_values)
|
76 |
|
77 |
# Clase para el análisis de teoría de grafos
|
78 |
class GraphTheoryAnalysis:
|
|
|
84 |
def set_matrices_and_values(self):
|
85 |
self.all_factors = list(self.experiment.factor_values.keys())
|
86 |
|
87 |
+
def build_graph(self, level=3):
|
88 |
+
if level > len(self.all_factors):
|
89 |
+
level = len(self.all_factors) # Ajustar el nivel al número de factores disponibles
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
+
for pair in combinations(self.all_factors, level):
|
92 |
+
if len(pair) >= 2: # Asegurarse de que hay suficientes elementos para formar un par
|
|
|
|
|
|
|
93 |
self.experiment.set_active_factors(list(pair))
|
94 |
self.experiment.fit_models()
|
95 |
r2 = (self.experiment.r2_variable1 + self.experiment.r2_variable2) / 2
|
96 |
+
self.graph.add_edge(pair[0], pair[1], weight=r2)
|
|
|
97 |
|
98 |
def visualize_graph(self, style='Style 1'):
|
99 |
pos = nx.spring_layout(self.graph)
|
|
|
125 |
nx.draw_networkx_labels(self.graph, pos, font_size=font_size)
|
126 |
|
127 |
edge_weights = [self.graph[u][v]['weight'] for u, v in self.graph.edges()]
|
128 |
+
nx.draw_networkx_edges(self.graph, pos, width=edge_weights, edge_color=edge_color)
|
|
|
|
|
|
|
129 |
|
130 |
+
edge_labels = nx.get_edge_attributes(self.graph, 'weight')
|
131 |
nx.draw_networkx_edge_labels(self.graph, pos, edge_labels=edge_labels, font_size=font_size)
|
132 |
|
133 |
plt.title(f"Grafo de relaciones entre factores basado en R² ({style})")
|
|
|
141 |
|
142 |
return temp_file.name
|
143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
# Definición de la interfaz de Gradio
|
145 |
def analyze_design(level, pb_design, bb_design, variable1_values, variable2_values, style):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
experiment = ExperimentalDesign(regression_degree=2)
|
147 |
optimizer = GraphTheoryAnalysis(experiment)
|
148 |
|
|
|
153 |
'X4': [0.05, 0.5]
|
154 |
}
|
155 |
|
156 |
+
experiment.set_design(np.array(pb_design), np.array(bb_design))
|
157 |
experiment.set_factors(factor_values)
|
158 |
+
experiment.set_dependent_variables(np.array(variable1_values), np.array(variable2_values))
|
159 |
|
160 |
optimizer.set_matrices_and_values()
|
161 |
+
optimizer.build_graph(level=level)
|
162 |
graph_image_path = optimizer.visualize_graph(style=style)
|
163 |
+
return graph_image_path, bb_design
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
|
165 |
# Matriz Plackett-Burman (por defecto)
|
166 |
default_pb_design = [
|
|
|
174 |
[-1, -1, -1, -1]
|
175 |
]
|
176 |
|
177 |
+
# Matriz Box-Behnken (por defecto)
|
178 |
default_bb_design = [
|
179 |
[-1, -1, 0, 0],
|
180 |
[1, -1, 0, 0],
|
|
|
211 |
interface = gr.Interface(
|
212 |
fn=analyze_design,
|
213 |
inputs=[
|
214 |
+
gr.Slider(1, 4, step=1, label="Level of Combination (1 to 4)"),
|
215 |
+
gr.Dataframe(headers=["X1", "X2", "X3", "X4"], value=default_pb_design, label="Matrix 1 (Plackett-Burman)"),
|
216 |
+
gr.Dataframe(headers=["X1", "X2", "X3", "X4"], value=default_bb_design, label="Matrix 2 (Box-Behnken)"),
|
217 |
+
gr.Dataframe(headers=["Variable 1"], value=[[val] for val in default_variable1_values], label="Variable 1 Values"),
|
218 |
+
gr.Dataframe(headers=["Variable 2"], value=[[val] for val in default_variable2_values], label="Variable 2 Values"),
|
219 |
+
gr.Dropdown(["Style 1", "Style 2", "Style 3", "Style 4"], label="Graph Style", value="Style 1")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
],
|
221 |
+
outputs=["image", "dataframe"],
|
222 |
+
title="Graph Theory Analysis for Experimental Design",
|
223 |
+
description="Analyze and visualize the relationships between factors in an experimental design using graph theory."
|
224 |
)
|
225 |
|
226 |
# Ejecutar la interfaz
|