# 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)