# 1. CARGA DE LIBRERÍAS ------------------------------------ import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt import plotly.express as px import plotly.graph_objects as go import statsmodels.formula.api as smf import itertools import io import gradio as gr import warnings warnings.filterwarnings("ignore") # 2. CARGA Y PREPARACIÓN DE LOS DATOS --------------------- try: # Use the raw URL to the CSV file # Para Hugging Face Spaces, la ruta es local al repositorio seguros = pd.read_csv('Costo_Seguro.csv') # print("Dataset 'Costo_Seguro' cargado correctamente.") except Exception as e: print(f"Fallo al cargar el archivo: {e}.") modelo_RLM = None # Objeto para guardar el modelo de Regresión Lineal Múltiple modelo_RLM_log = None # Objeto para guardar el modelo de Regresión Lineal Múltiple Logarítmico # Modelo Regresión Lineal Múltiple formula = 'seguro ~ edad + imc + C(genero) + C(hijos) + C(fumador) + C(region)' modelo_RLM = smf.ols(formula, data = seguros).fit() # Modelo Regresión Lineal Múltiple logarítmico formula = 'np.log(seguro) ~ edad + imc + C(genero) + C(hijos) + C(fumador) + C(region)' modelo_RLM_log = smf.ols(formula, data = seguros).fit() # Mostrar la forma (filas, columnas) del dataset original # print(f"\nForma del dataset original: {seguros.shape}") # Mostrar las primeras filas deL dataset # print("\nPrimetras 20 filas del dataset:") # print(seguros.head(20)) ### FUNCIONES PARA PRESENTAR DATOS / GRÁFICOS EN LA INTERFAZ GRADIO def obtener_info_dataset(): # Convertimos la tupla shape a Markdown filas, columnas = seguros.shape info_shape = f"**{filas}** filas, **{columnas}** columnas" # Convertimos el DataFrame.head() a Markdown info_head = seguros.head(10).to_markdown(index=False) # Convertimos el DataFrame.describe() a Markdown info_describe = seguros.describe().to_markdown() return info_shape, info_head, info_describe def generar_graficos(): plt1 = px.histogram(seguros, x='seguro', nbins=50, title="Histograma del Costo del Seguro", labels={'seguro': 'Costo del Seguro'}) #plt1.show() plt2 = px.box(seguros, x='genero', y='seguro', title="Distribución del Costo del Seguro por Género", labels={'genero': 'Género del Asegurado', 'seguro': 'Costo del Seguro'}) # plt2.show() plt3 = px.box(seguros, x='fumador', y='seguro', title="Distribución del Costo del Seguro por Condición de Fumador", labels={'fumador': 'Condición de Fumador del Asegurado', 'seguro': 'Costo del Seguro'}) # plt3.show() plt4 = px.box(seguros, x='region', y='seguro', title="Distribución del Costo del Seguro por Regiones", labels={'region': 'Región de Origen del Asegurado', 'seguro': 'Costo del Seguro'}) # plt4.show() plt5 = px.scatter(seguros, x='edad', y='seguro', title="Edad vs. Costo del Seguro", labels={'edad': 'Edad del Asegurado', 'seguro': 'Costo del Seguro'}) # plt5.show() plt6 = px.scatter(seguros, x='imc', y='seguro', title="IMC vs. Costo del Seguro", labels={'imc': 'Índice de Masa Corporal del Asegurado', 'seguro': 'Costo del Seguro'}) # plt6.show() return plt1, plt2, plt3, plt4, plt5, plt6 def calcular_RLS(): # Costo del Seguro vs. Edad RLS_1 = smf.ols('seguro ~ edad', data=seguros).fit() summary_text_1 = RLS_1.summary().as_text() data1_1 = f"```\n{summary_text_1}\n```" # Envuelve el texto en un bloque de código Markdown # Métricas r2 = RLS_1.rsquared adj = RLS_1.rsquared_adj rmse = np.sqrt(np.mean(RLS_1.resid**2)) data1_2 = f"Métricas:
R² = {r2:.4f}
R² Ajustado = {adj:.4f}
RMSE = {rmse:.2f}" # Ecuación de la recta b0, b1 = RLS_1.params data1_3 = f"Ecuación de la Recta:
Costo del Seguro = {b0:.2f} + {b1:.2f} * Edad" # Gráfico de la recta de regresión grid1 = np.linspace(seguros['edad'].min(), seguros['edad'].max(), 100) preds1 = RLS_1.predict(pd.DataFrame({'edad': grid1})) fig1 = go.Figure([ go.Scatter(x=seguros['edad'], y=seguros['seguro'], mode='markers', name='Datos'), go.Scatter(x=grid1, y=preds1, mode='lines', name='Recta') ]) fig1.update_layout(# title="Regresión Lineal Simple: Costo del Seguro vs. Edad", xaxis_title='Edad', yaxis_title='Costo del Seguro') # fig1.show() # Costo del Sefuro vs. IMC RLS_2 = smf.ols('seguro ~ imc', data=seguros).fit() summary_text_2 = RLS_1.summary().as_text() data2_1 = f"```\n{summary_text_2}\n```" # Envuelve el texto en un bloque de código Markdown # Métricas r2 = RLS_2.rsquared adj = RLS_2.rsquared_adj rmse = np.sqrt(np.mean(RLS_2.resid**2)) data2_2 = f"Métricas:
R² = {r2:.4f}
R² Ajustado = {adj:.4f}
RMSE = {rmse:.2f}" # Ecuación de la recta b0, b1 = RLS_2.params data2_3 = f"Ecuación de la Recta:
Costo del Seguro = {b0:.2f} + {b1:.2f} * IMC" # Gráfico de la recta de regresión grid2 = np.linspace(seguros['imc'].min(), seguros['imc'].max(), 100) preds2 = RLS_2.predict(pd.DataFrame({'imc': grid2})) fig2 = go.Figure([ go.Scatter(x=seguros['imc'], y=seguros['seguro'], mode='markers', name='Datos'), go.Scatter(x=grid2, y=preds2, mode='lines', name='Recta') ]) fig2.update_layout(# title="Regresión Lineal Simple: Costo del Seguro vs. IMC", xaxis_title='IMC', yaxis_title='Costo del Seguro') # fig2.show() return data1_1, data1_2, data1_3, data2_1, data2_2, data2_3, fig1, fig2 def calcular_RLM(): summary_text = modelo_RLM.summary().as_text() data1 = f"```\n{summary_text}\n```" # Métricas r2 = modelo_RLM.rsquared adj = modelo_RLM.rsquared_adj rmse = np.sqrt(np.mean(modelo_RLM.resid**2)) data2 = f"Métricas:
R² = {r2:.4f}
R² Ajustado = {adj:.4f}
RMSE = {rmse:.2f}" # Coeficientes de la Regresión Lineal Múltiple coef_orig = modelo_RLM.params terms = [f"{coef_orig['Intercept']:.2f}"] for name, coef in coef_orig.items(): if name == 'Intercept': continue terms.append(f"{coef:+.2f}*{name}") data3 = "Costo del Seguro = " + " ".join(terms) data3 = f"{data3}" return data1, data2, data3 def graficar_residuos(): fig, axes = plt.subplots(1, 2, figsize=(12,5)) # Gráfico de Residuos vs Costo del Seguro Ajustado axes[0].scatter(modelo_RLM.fittedvalues, modelo_RLM.resid, alpha=0.5) axes[0].axhline(0, color='red') axes[0].set(title='Residuos vs Costo del Seguro Ajustado', xlabel = 'Costo Ajustado', ylabel = 'Residuos') # Gráfico de Residuos vs Log(Costo del Seguro Ajustado) axes[1].scatter(modelo_RLM_log.fittedvalues, modelo_RLM_log.resid, color='darkgreen', alpha=0.5) axes[1].axhline(0, color='red') axes[1].set(title='Residuos vs Logaritmo del Costo del Seguro Ajustado', xlabel = 'Logaritmo del Costo Ajustado', ylabel = 'Residuos') plt.tight_layout() # IMPORTANTE: Para Gradio en Hugging Face, se retorna el objeto `plt` # o se usa `gr.Plot(plt.gcf())`. Aquí devolveremos el objeto `plt`. # Alternativamente, podrías guardar la imagen y devolver la ruta, pero devolver `plt` es más directo con `gr.Plot`. return plt def predecir_costo(edad, genero, imc, hijos, fumador, region): global modelo_RLM if modelo_RLM is None: # Esto no debería ocurrir si el modelo se entrena al inicio, # pero es una buena práctica de manejo de errores. return 0, 0, "ERROR: El Modelo de RLM no está disponible." nuevo = pd.DataFrame({ 'edad': [edad], 'genero': [genero], 'imc': [imc], 'hijos': [hijos], 'fumador': [fumador], 'region': [region] }) # Predicción con el modelo RLM original (variable dependiente 'seguro') prediccion1 = modelo_RLM.predict(nuevo)[0] # Predicción con el modelo RLM logarítmico (variable dependiente 'np.log(seguro)') prediccion_log = modelo_RLM_log.predict(nuevo)[0] # Se revierte el logaritmo con np.exp() para obtener la predicción original prediccion2 = np.exp(prediccion_log) return prediccion1, prediccion2 ### INTERFAZ GRADIO CON ESTRUCTURA DE PESTAÑAS with gr.Blocks() as appweb: # Contenedor principal with gr.Row(): gr.Image('encabezado.png', container = False) # Título de la aplicación # gr.Markdown("# COSTO DE SEGUROS PERSONALES") # Contenedor de pestañas with gr.Tabs(): # Pestaña 1: Inicio with gr.TabItem("Inicio") as tab_inicio: gr.Markdown("## DATASET DE COSTOS DE SEGUROS PERSONALES") gr.Markdown("### Estructura:") data1_output = gr.Markdown() gr.Markdown("### Primeras 10 filas:") data2_output = gr.Markdown() gr.Markdown("### Estadísticas Generales:") data3_output = gr.Markdown() # Se cargan los datos al iniciar la aplicación appweb.load(fn = obtener_info_dataset, inputs = None, outputs=[data1_output, data2_output, data3_output]) # Se cargan los datos al seleccionar la pestaña "Inicio" # tab_inicio.select(fn = obtener_info_dataset, inputs = None, # outputs=[data1_output, data2_output, data3_output]) # Pestaña 2: Gráficos Exploratorios with gr.TabItem("Gráficos") as tab_graficos: gr.Markdown("## VISUALIZACIÓN EXPLORATORIA DE DATOS") with gr.Row(): plot1_output = gr.Plot(label=None, show_label=False) plot2_output = gr.Plot(label=None, show_label=False) with gr.Row(): plot3_output = gr.Plot(label=None, show_label=False) plot4_output = gr.Plot(label=None, show_label=False) with gr.Row(): plot5_output = gr.Plot(label=None, show_label=False) plot6_output = gr.Plot(label=None, show_label=False) # Alternativa 1: al presionar un botón se llama a la función generar_graficos() # btn_graficos = gr.Button("Gráficos") # btn_graficos.click(fn = generar_graficos, inputs = None, # outputs = [plot1_output, plot2_output, plot3_output, # plot4_output, plot5_output, plot6_output]) # Alternativa 2: al seleccionar la pestaña "Gráficos" se llama a la función generar_graficos() # tab_graficos.select(fn = generar_graficos, inputs = None, # outputs = [plot1_output, plot2_output, plot3_output, # plot4_output, plot5_output, plot6_output]) # Alternativa 3: al iniciar la aplicación se llama a la función generar_graficos() appweb.load(fn = generar_graficos, inputs = None, outputs = [plot1_output, plot2_output, plot3_output, plot4_output, plot5_output, plot6_output]) # Pestaña 3: Regresiones Lineales Simples with gr.TabItem("Regresión Simple") as tab_reg_simple: gr.Markdown("# REGRESIONES LINEALES SIMPLES") gr.Markdown("## Costo del Seguro vs. Edad") reg11_output = gr.Markdown() with gr.Row(): reg12_output = gr.Markdown() reg13_output = gr.Markdown() plotreg1_output = gr.Plot(label=None, show_label=False) gr.Markdown("## Costo del Seguro vs. IMC") reg21_output = gr.Markdown() with gr.Row(): reg22_output = gr.Markdown() reg23_output = gr.Markdown() plotreg2_output = gr.Plot(label=None, show_label=False) tab_reg_simple.select(fn = calcular_RLS, inputs = None, outputs = [reg11_output, reg12_output, reg13_output, reg21_output, reg22_output, reg23_output, plotreg1_output, plotreg2_output]) # Pestaña 4: Regresión Lineal Múltiple with gr.TabItem("Regresión Múltiple") as tab_reg_multiple: gr.Markdown("# REGRESIÓN LINEAL MÚLTIPLE") regm1_output = gr.Markdown() regm2_output = gr.Markdown() gr.Markdown("### Ecuación de la Regresión") regm3_output = gr.Markdown() tab_reg_multiple.select(fn = calcular_RLM, inputs = None, outputs = [regm1_output, regm2_output, regm3_output]) # Pestaña 5: Comparación de Residuos with gr.TabItem("Residuos") as tab_residuos: gr.Markdown("## COMPARACIÓN DE RESIDUOS ENTRE COSTO DEL SEGURO Y LOG(COSTO DEL SEGURO)") plotres_output = gr.Plot(label=None, show_label=False) tab_residuos.select(fn = graficar_residuos, inputs = None, outputs = plotres_output) # Pestaña 6: Predicción de Costos - Modelo RLM with gr.TabItem("Predicción de Costos"): gr.Markdown("## PREDICCIÓN DE COSTOS DE SEGURO PERSONAL") with gr.Row(): input_edad = gr.Slider(minimum=18, maximum=80, step=1, value=30, label="Edad") input_genero = gr.Radio(choices=["femenino", "masculino"], label="Género", value="femenino") with gr.Row(): input_imc = gr.Slider(minimum=15, maximum=60, step=0.5, value=30.0, label="Índice de Masa Corporal") input_fumador = gr.Radio(choices=["si", "no"], label="Fumador", value="no") with gr.Row(): input_hijos = gr.Slider(minimum=0, maximum=5, step=1, value=0, label="Cantidad de Hijos") input_region = gr.Radio(choices=["NO", "NE", "SO", "SE"], label="Región", value="NO") gr.Markdown("---") with gr.Row(): btn_predecir = gr.Button("Predecir Costo") output_costo = gr.Number(label="Costo del Seguro (Modelo Lineal)", precision=2, value=0.00) output_costo_log = gr.Number(label="Costo del Seguro (Modelo Logarítmico)", precision=2, value=0.00) btn_predecir.click(fn = predecir_costo, inputs = [input_edad, input_genero, input_imc, input_hijos, input_fumador, input_region], outputs = [output_costo, output_costo_log]) # Ejecución de la aplicación # **MODIFICACIÓN CRUCIAL PARA HUGGING FACE SPACES** # Usar server_name="0.0.0.0" y server_port=7860 appweb.launch(server_name="0.0.0.0", server_port=7860)