File size: 15,719 Bytes
b193952
 
 
 
 
 
 
 
1e0afd4
 
 
b193952
 
 
 
 
29deb9d
 
ef72c8c
29deb9d
 
 
b193952
 
 
 
 
 
 
 
 
 
 
 
f363b9c
 
b193952
f363b9c
 
b193952
 
 
 
 
 
 
f363b9c
 
b193952
f363b9c
 
b193952
f363b9c
 
b193952
f363b9c
 
b193952
f363b9c
 
b193952
f363b9c
 
b193952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f281fea
 
 
 
 
 
 
 
b193952
f363b9c
 
b193952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9ec33c1
b193952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f363b9c
 
 
 
 
 
 
 
 
 
 
 
b193952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f363b9c
 
 
 
 
 
b193952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f363b9c
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
import gradio as gr
import numpy as np
import joblib
import sys
import os
import pandas as pd


from models.train_linear_model import MultipleLinearRegressionGradientDescent
from models.train_logistic_model import LogisticRegressionGradientDescent


country_cols = ['Country_Afghanistan','Country_Albania', 'Country_Algeria', 'Country_Angola', 'Country_Antigua and Barbuda', 'Country_Argentina', 'Country_Armenia', 'Country_Australia', 'Country_Austria', 'Country_Azerbaijan', 'Country_Bahamas', 'Country_Bahrain', 'Country_Bangladesh', 'Country_Barbados', 'Country_Belarus', 'Country_Belgium', 'Country_Belize', 'Country_Benin', 'Country_Bhutan', 'Country_Bolivia (Plurinational State of)', 'Country_Bosnia and Herzegovina', 'Country_Botswana', 'Country_Brazil', 'Country_Brunei Darussalam', 'Country_Bulgaria', 'Country_Burkina Faso', 'Country_Burundi', 'Country_Cabo Verde', 'Country_Cambodia', 'Country_Cameroon', 'Country_Canada', 'Country_Central African Republic', 'Country_Chad', 'Country_Chile', 'Country_China', 'Country_Colombia', 'Country_Comoros', 'Country_Congo', 'Country_Costa Rica', 'Country_Croatia', 'Country_Cuba', 'Country_Cyprus', 'Country_Czechia', "Country_Côte d'Ivoire", "Country_Democratic People's Republic of Korea", 'Country_Democratic Republic of the Congo', 'Country_Denmark', 'Country_Djibouti', 'Country_Dominican Republic', 'Country_Ecuador', 'Country_Egypt', 'Country_El Salvador', 'Country_Equatorial Guinea', 'Country_Eritrea', 'Country_Estonia', 'Country_Ethiopia', 'Country_Fiji', 'Country_Finland', 'Country_France', 'Country_Gabon', 'Country_Gambia', 'Country_Georgia', 'Country_Germany', 'Country_Ghana', 'Country_Greece', 'Country_Grenada', 'Country_Guatemala', 'Country_Guinea', 'Country_Guinea-Bissau', 'Country_Guyana', 'Country_Haiti', 'Country_Honduras', 'Country_Hungary', 'Country_Iceland', 'Country_India', 'Country_Indonesia', 'Country_Iran (Islamic Republic of)', 'Country_Iraq', 'Country_Ireland', 'Country_Israel', 'Country_Italy', 'Country_Jamaica', 'Country_Japan', 'Country_Jordan', 'Country_Kazakhstan', 'Country_Kenya', 'Country_Kiribati', 'Country_Kuwait', 'Country_Kyrgyzstan', "Country_Lao People's Democratic Republic", 'Country_Latvia', 'Country_Lebanon', 'Country_Lesotho', 'Country_Liberia', 'Country_Libya', 'Country_Lithuania', 'Country_Luxembourg', 'Country_Madagascar', 'Country_Malawi', 'Country_Malaysia', 'Country_Maldives', 'Country_Mali', 'Country_Malta', 'Country_Mauritania', 'Country_Mauritius', 'Country_Mexico', 'Country_Micronesia (Federated States of)', 'Country_Mongolia', 'Country_Montenegro', 'Country_Morocco', 'Country_Mozambique', 'Country_Myanmar', 'Country_Namibia', 'Country_Nepal', 'Country_Netherlands', 'Country_New Zealand', 'Country_Nicaragua', 'Country_Niger', 'Country_Nigeria', 'Country_Norway', 'Country_Oman', 'Country_Pakistan', 'Country_Panama', 'Country_Papua New Guinea', 'Country_Paraguay', 'Country_Peru', 'Country_Philippines', 'Country_Poland', 'Country_Portugal', 'Country_Qatar', 'Country_Republic of Korea', 'Country_Republic of Moldova', 'Country_Romania', 'Country_Russian Federation', 'Country_Rwanda', 'Country_Saint Lucia', 'Country_Saint Vincent and the Grenadines', 'Country_Samoa', 'Country_Sao Tome and Principe', 'Country_Saudi Arabia', 'Country_Senegal', 'Country_Serbia', 'Country_Seychelles', 'Country_Sierra Leone', 'Country_Singapore', 'Country_Slovakia', 'Country_Slovenia', 'Country_Solomon Islands', 'Country_Somalia', 'Country_South Africa', 'Country_South Sudan', 'Country_Spain', 'Country_Sri Lanka', 'Country_Sudan', 'Country_Suriname', 'Country_Swaziland', 'Country_Sweden', 'Country_Switzerland', 'Country_Syrian Arab Republic', 'Country_Tajikistan', 'Country_Thailand', 'Country_The former Yugoslav republic of Macedonia', 'Country_Timor-Leste', 'Country_Togo', 'Country_Tonga', 'Country_Trinidad and Tobago', 'Country_Tunisia', 'Country_Turkey', 'Country_Turkmenistan', 'Country_Uganda', 'Country_Ukraine', 'Country_United Arab Emirates', 'Country_United Kingdom of Great Britain and Northern Ireland', 'Country_United Republic of Tanzania', 'Country_United States of America', 'Country_Uruguay', 'Country_Uzbekistan', 'Country_Vanuatu', 'Country_Venezuela (Bolivarian Republic of)', 'Country_Viet Nam', 'Country_Yemen', 'Country_Zambia', 'Country_Zimbabwe']


# Cargar modelos y scalers
linear_model = joblib.load("notebook/linear_regression/linear_model.pkl")
logistic_model = joblib.load("notebook/logistic_regression/logistic_model.pkl")
scaler_lin = joblib.load("notebook/linear_regression/scaler_linear.pkl")
feature_order = joblib.load("notebook/linear_regression/feature_order.pkl")
scaler_log = joblib.load("notebook/logistic_regression/scaler_logistic.pkl")


def validate_lineal_inputs(country, year, adult_mortality, expenditure_perce, measles, 
                         five_deaths, polio, total_exp, hiv, thinness, 
                         income_composition, schooling, status_dev):
    errors = []
    
    if not country:
        errors.append("❌ Debe seleccionar un país")
    
    if year < 1900 or year > 2100:
        errors.append("❌ Año debe estar entre 1900 y 2100")
    
    if adult_mortality < 0 or adult_mortality > 450:
        errors.append("❌ Mortalidad adulta debe estar entre 0 y 450")
    
    if expenditure_perce < 0 or expenditure_perce > 7000:
        errors.append("❌ Gasto porcentual debe estar entre 0 y 7000")
    
    if measles < 0:
        errors.append("❌ Casos de sarampión no puede ser negativo")
    
    if five_deaths < 0:
        errors.append("❌ Muertes menores de 5 años no puede ser negativo")
    
    if polio < 0 or polio > 100:
        errors.append("❌ Tasa de polio debe estar entre 0 y 100")
    
    if total_exp < 0 or total_exp > 100:
        errors.append("❌ Gasto total debe estar entre 0 y 100")
    
    if hiv < 0 or hiv > 15:
        errors.append("❌ Tasa de HIV/SIDA debe estar entre 0 y 15")
    
    if thinness < 0 or thinness > 20:
        errors.append("❌ Delgadez 10-19 años debe estar entre 0 y 20")
    
    if income_composition < 0.2 or income_composition > 1:
        errors.append("❌ Composición de ingresos debe estar entre 0.2 y 1")
    
    if schooling < 0 or schooling > 20:
        errors.append("❌ Escolaridad debe estar entre 0 y 20")
    
    if status_dev not in [0, 1]:
        errors.append("❌ Estado de desarrollo debe ser 0 (NO) o 1 (SÍ)")
    
    return "\n".join(errors) if errors else None

def validate_logistic_inputs(age, bmi, former_smoke, never_smoke, smokes, glucose):
    errors = []
    
    if age < 0 or age > 120:
        errors.append("❌ Edad debe estar entre 0 y 120 años")
    
    if bmi < 10 or bmi > 100:
        errors.append("❌ BMI debe estar entre 10 y 100")
    
    if former_smoke not in [0, 1]:
        errors.append("❌ Ex-fumador debe ser 0 (NO) o 1 (SÍ)")
    
    if never_smoke not in [0, 1]:
        errors.append("❌ Nunca fumó debe ser 0 (NO) o 1 (SÍ)")
    
    if smokes not in [0, 1]:
        errors.append("❌ Fumador actual debe ser 0 (NO) o 1 (SÍ)")
    
    tobacco_combo = (former_smoke, never_smoke, smokes)
    valid_combinations = [
        (1, 0, 0),  # Exfumador
        (0, 1, 0),  # Nunca fumó
        (0, 0, 1)   # Fumador actual
    ]
    if tobacco_combo not in valid_combinations:
        errors.append("❌ Las opciones de tabaquismo no son coherentes. Solo una debe marcarse como 'Sí'.")
    
    if glucose < 55 or glucose > 270:
        errors.append("❌ Nivel de glucosa debe estar entre 55 y 270 mg/dL")
    
    return "\n".join(errors) if errors else None

def predecir_lineal(pais, *args):
    # Validar inputs primero
    validation_error = validate_lineal_inputs(pais, *args)
    if validation_error:
        return validation_error
    
    base_names = [
        "Year", "Adult Mortality", "percentage expenditure", "Measles", "under-five deaths",
        "Polio", "Total expenditure", "HIV/AIDS", "thinness 10-19 years",  
        "Income composition of resources", "Schooling", "Status_Developing"
    ]
    
    try:
        base_inputs = list(args)
        base_dict = dict(zip(base_names, base_inputs))

        # Codificar país 
        country_dict = {col: 0 for col in country_cols}
        if pais in country_dict:
            country_dict[pais] = 1

        # Combinar todo en un solo dict
        full_input_dict = {**base_dict, **country_dict}

        # Reordenar según feature_order
        x_ordered = np.array([[full_input_dict[col] for col in feature_order]])

        # Escalar y predecir
        x_scaled = scaler_lin.transform(x_ordered)
        pred = linear_model.predict(x_scaled)

        return f"📈 Esperanza de vida estimada: {pred[0]:.2f} años"
    except Exception as e:
        return f"⚠️ Error al procesar la solicitud: {str(e)}"

def predecir_logistica(*args):
    # Validar inputs primero
    validation_error = validate_logistic_inputs(*args)
    if validation_error:
        return validation_error
    
    input_names = ['age', 'bmi', 'smoke_formerly smoked', 'smoke_never smoked', 'smoke_smokes', 'avg_glucose_level']
    
    try:
        input_values = list(args)
        input_dict = dict(zip(input_names, input_values))

        # Reordenar y convertir a DataFrame
        X_df = pd.DataFrame([input_dict], columns=input_names)

        # Escalar
        X_scaled = scaler_log.transform(X_df)

        # Predecir
        pred = logistic_model.predict(X_scaled)
        return "🟥 Riesgo de accidente cerebrovascular: ALTO" if pred[0] == 1 else "🟩 Riesgo de accidente cerebrovascular: BAJO"
    except Exception as e:
        return f"⚠️ Error al procesar la solicitud: {str(e)}"

# --- Interfaz con pantallas independientes ---
with gr.Blocks(title="App de Regresión", theme=gr.themes.Soft(
    primary_hue="pink",
    secondary_hue="pink",
    neutral_hue="gray"
), css="""
.custom-header {
    color: #d14d8b !important;
    text-align: center;
    padding: 10px;
    border-radius: 8px;
}
.custom-button {
    background: #f8c8dc !important;
    color: #333 !important;
    border: 1px solid #f8c8dc !important;
}
.custom-button:hover {
    background: #f5b5d1 !important;
}
.gr-box {
    border: 1px solid #f8c8dc !important;
    border-radius: 8px !important;
}
.error-message {
    color: #ff0000 !important;
    font-weight: bold;
}
""") as demo:
    current_page = gr.State("home")

    # --- Pantalla de inicio ---
    with gr.Column(visible=True) as pantalla_inicio:
        gr.Markdown("# Bienvenido a la App del Proyecto #1 de Análisis Numérico", 
                   elem_classes=["custom-header"])
        gr.Markdown("En este proyecto tenemos dos modelos de machine learning entrenados por medio de gradiente descendiente, uno de regresión lineal y otro de regresión logistica")
        with gr.Row():
            btn_go_lineal = gr.Button("Regresión Lineal", 
                                    elem_classes=["custom-button"])
            btn_go_log = gr.Button("Regresión Logística", 
                                 elem_classes=["custom-button"])

    # --- Pantalla Lineal ---
    with gr.Column(visible=False) as pantalla_lineal:
        gr.Markdown("## Regresión Lineal", 
                   elem_classes=["custom-header"])

        with gr.Row():
            with gr.Column(scale=3):
                country_dropdown = gr.Dropdown(choices=country_cols, label="País")
                year_input = gr.Number(label="Año: [2000-2015]", minimum=1900, maximum=2100)
                adult_mortality = gr.Number(label="Mortalidad adulta [1-450]", minimum=0, maximum=450)
                expenditure_perce = gr.Number(label="Gasto porcentual [0.005-7000]", minimum=0, maximum=7000)
                measles = gr.Number(label="Sarampión [0–40000]", minimum=0,maximum=40000)
                five_deaths = gr.Number(label="Muertes de menores de cinco años [0-100]", minimum=0,maximum=100)
                polio_input = gr.Number(label="Polio (% inmunizados)  [0-100]", minimum=0, maximum=100)
                total_exp = gr.Number(label="Gasto total (% PIB) [0-17.9]", minimum=0, maximum=18)
                hiv_input = gr.Number(label="VIH/SIDA [0.1-15]", minimum=0, maximum=15)
                thiness_input = gr.Number(label="Delgadez 10-19 años [0-20]", minimum=0, maximum=20)
                compos_input = gr.Number(label="Composición de ingresos de los recursos [0.2-1]", minimum=0.2, maximum=1)
                schooling = gr.Number(label="Enseñanza [0-20] años", minimum=0, maximum=20)
                dev_input = gr.Dropdown(choices=[("No", 0),("Si", 1)], label="En desarrollo",value=0)

                base_inputs = [
                    year_input, adult_mortality, expenditure_perce, measles, five_deaths,
                    polio_input, total_exp, hiv_input, thiness_input,
                    compos_input, schooling, dev_input
                ]

            with gr.Column(scale=2):
                btn_lineal = gr.Button("Predecir", 
                                     elem_classes=["custom-button"])
                out_lineal = gr.Textbox(label="Resultado", lines=3)
                btn_back1 = gr.Button("Volver al inicio", 
                                    elem_classes=["custom-button"])

    # --- Pantalla Logística ---
    with gr.Column(visible=False) as pantalla_log:
        gr.Markdown("## Regresión Logística", 
                   elem_classes=["custom-header"])

        with gr.Row():
            with gr.Column(scale=3):
                age_input = gr.Number(label="Edad", minimum=0, maximum=120)
                bmi_input = gr.Number(label="IMC (Índice de masa corporal) [10-70]", minimum=10, maximum=70)
                former_smoke = gr.Dropdown(choices=[("No", 0),("Si", 1)], label="Ex-fumador",value=0)
                never_smoke = gr.Dropdown(choices=[("No", 0),("Si", 1)], label="Nunca ha fumado",value=0)
                smokes = gr.Dropdown(choices=[("No", 0),("Si", 1)], label="Fuma",value=0)
                glucose_input = gr.Number(label="Nivel promedio de glucosa [55-270]", minimum=54, maximum=270)

                inputs_log = [
                    age_input, bmi_input, former_smoke, never_smoke, smokes, glucose_input
                ]

            with gr.Column(scale=2):
                btn_log = gr.Button("Predecir", 
                                  elem_classes=["custom-button"])
                out_log = gr.Textbox(label="Resultado", lines=3)
                btn_back2 = gr.Button("Volver al inicio", 
                                    elem_classes=["custom-button"])

    # --- Lógica de navegación ---
    def show_page(page):
        return {
            pantalla_inicio: gr.update(visible=(page == "home")),
            pantalla_lineal: gr.update(visible=(page == "lineal")),
            pantalla_log: gr.update(visible=(page == "log")),
            current_page: page
        }

    btn_go_lineal.click(lambda: show_page("lineal"), outputs=[pantalla_inicio, pantalla_lineal, pantalla_log, current_page])
    btn_go_log.click(lambda: show_page("log"), outputs=[pantalla_inicio, pantalla_lineal, pantalla_log, current_page])
    btn_back1.click(lambda: show_page("home"), outputs=[pantalla_inicio, pantalla_lineal, pantalla_log, current_page])
    btn_back2.click(lambda: show_page("home"), outputs=[pantalla_inicio, pantalla_lineal, pantalla_log, current_page])

    # --- Eventos de predicción ---
    btn_lineal.click(
        predecir_lineal, 
        inputs=[country_dropdown] + base_inputs, 
        outputs=out_lineal
    )
    
    btn_log.click(
        predecir_logistica, 
        inputs=inputs_log, 
        outputs=out_log
    )

if __name__ == "__main__":
    demo.launch()