Daskam's picture
Update app.py
479e12c
# CREACION DE MODELO
# Importacion de librerias
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import warnings
warnings.filterwarnings("ignore")
df = pd.read_csv("heart.csv")
# Escalamiento
from sklearn.preprocessing import RobustScaler
# Train Test Split
from sklearn.model_selection import train_test_split
# Modelos
import torch
import torch.nn as nn
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import GradientBoostingClassifier
# Metricas
from sklearn.metrics import accuracy_score, classification_report, roc_curve
# Cross Validation
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
print('Packages imported...')
# Creación de una copia del df
df1 = df
# Seleccion de las columnas a ser escaladas y codificadas
cat_cols = ['sex','exng','caa','cp','fbs','restecg','slp','thall']
con_cols = ["age","trtbps","chol","thalachh","oldpeak"]
# Codificando las columnas categoricas
df1 = pd.get_dummies(df1, columns = cat_cols, drop_first = True)
# Definiendo los atributos independientes y el atributo dependiente
X = df1.drop(['output'],axis=1)
y = df1[['output']]
# Instanciando el escalador
scaler = RobustScaler()
# Escalando los atributos continuos
X[con_cols] = scaler.fit_transform(X[con_cols])
print("Las primeras 5 filas de X")
X.head()
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size = 0.2, random_state = 42)
print("El tamaño de X_train es ", X_train.shape)
print("El tamaño de X_test es ",X_test.shape)
print("El tamaño de y_train es ",y_train.shape)
print("El tamaño de y_test es ",y_test.shape)
# Instanciamiento del objeto
logreg = LogisticRegression()
# Ajustando el objeto
logreg.fit(X_train, y_train)
# Calculo de probabilidades
y_pred_proba = logreg.predict_proba(X_test)
# Encontrando los valores predichos
y_pred = np.argmax(y_pred_proba,axis=1)
# Impresión de la prueba de precisión
print("El puntaje de precisión en la prueba de Regresión Logística es ", accuracy_score(y_test, y_pred))
## GRADIO DE AQUÍ PARA ABAJO
# Instalamos nuestra librería para la respectiva interfaz gráfica para el usuario
#!pip install -q gradio
# Instalamos la libreria de hugging face spaces para el hosting en la nube
#!pip install -q transformers
#Importamos gradio y el metodo necesario para el hosting
import gradio as gr
# Variables globales
# Creamos una lista donde se almacenarán los nombres de todos los campo de la UI
nombres_campos = ['Edad', 'Sexo', 'Tipo de dolor toracico',
'Presión arterial en reposo', 'Colesterol',
'Azúcar en sangre en ayunas',
'Resultados electrocardiográficos en reposo',
'Ritmo cardíaco máximo alcanzado',
'Angina inducida por ejercicio',
'Depresión ST(Old Peak)', 'Pendiente del segmento ST',
'Número de vasos principales',
'Resultado de la prueba de esfuerzo con talio']
texto_atributos = """-Diccionario de datos-\n
`Edad` - Edad del paciente en cuestión.\n
`Sexo` - Sexo del paciente.\n
`Tipo de dolor torácico` - Si se presenta alguno de los siguientes: angina típica, angina atípica, dolor no anginal, 3 = asintomático.\n
`Presión arterial en reposo` - Presión arterial en reposo (medido en mm Hg).\n
`Colesterol` - Es obtenido a través del sensor de IMC (Medido en mg/dl).\n
`Azúcar en sangre en ayunas` - Cuando este valor es mayor a 120 mg/dl.\n
`Resultados electrocardiográficos en reposo` - Normal, Normalidad de la onda ST-T, Hipertrofia ventricular izquierda.\n
`Angina inducida por ejercicio` - Si se padece este tipo de angina.\n
`Ritmo cardíaco máximo alcanzado` - Ritmo cardíaco máximo alcanzado en la prueba con talio.\n
`Depresión ST(Old Peak)` - Pico anterior: es inducida por el ejercicio en relación al reposo.\n
`Pendiente del segmento ST` - Inclinación del segmento ST (ascendente, descendente u horizontal ).\n
`Número de vasos principales` - Número de vasos principales obtenido en Fluoroscopia.\n
`Resultado de la prueba de esfuerzo con talio` - Resultado de la prueba de esfuerzo con talio.\n"""
# creación de tema personalizado
custom_theme = gr.themes.Soft(
primary_hue="teal",
secondary_hue="cyan",
neutral_hue="zinc"
).set(
body_background_fill='*stat_background_fill',
body_background_fill_dark='*neutral_800',
body_text_color_subdued='*primary_100',
body_text_weight='500',
background_fill_primary_dark='*neutral_700',
background_fill_secondary_dark='*background_fill_primary',
border_color_accent='*primary_600',
border_color_accent_dark='*neutral_950',
color_accent='*neutral_800',
color_accent_soft_dark='*body_text_color_subdued',
link_text_color='*neutral_800',
link_text_color_dark='*border_color_primary',
prose_text_weight='500',
prose_header_text_weight='400',
block_background_fill='*neutral_700',
block_border_color_dark='*neutral_950',
block_border_width_dark='1 px',
block_info_text_size='*text_md',
block_label_background_fill_dark='*primary_800',
checkbox_background_color='*neutral_200',
checkbox_background_color_dark='*neutral_950',
checkbox_background_color_focus_dark='*neutral_800',
checkbox_border_color='*neutral_300',
checkbox_border_color_dark='*neutral_800'
)
# Crear archivos temporales para guardar el grafico en una imagen
import tempfile
# cambiar la media de todo el dataset real por todos los registros reales donde el target fue 1
def crear_grafico(datos_paciente):
nombres_campos_formateados = ['Edad', 'Sexo', 'Tipo de dolor\ntoracico',
'Presión arterial\nen reposo', 'Colesterol',
'Azúcar en sangre\nen ayunas',
'Resultados\nelectrocardiográficos\nen reposo',
'Ritmo cardíaco\nmáximo alcanzado',
'Angina inducida\nor ejercicio',
'Depresión ST\n(Old Peak)', 'Pendiente del\nsegmento ST',
'Número de vasos\nprincipales',
'Resultado de la prueba\nde esfuerzo con talio']
#features_mean_df= pd.DataFrame([df.mean(axis = 0)])
features_mean_df = df.loc[df['output'] == 1, ['age', 'sex', 'cp', 'trtbps', 'chol', 'fbs', 'restecg', 'thalachh', 'exng', 'oldpeak', 'slp', 'caa', 'thall', 'output']]
features_mean_df = features_mean_df.drop(['output'], axis = 1)
# Valores para X y Y para la media
y_plot_means = features_mean_df.iloc[0].values # Medias
# Valores para X y Y para los datos ingresados del paciente
y_plot_paciente = pd.DataFrame(datos_paciente).iloc[0].values
# Crear el gráfico de barras para la media del dataset
fig, ax = plt.subplots(figsize=(16,9))
width = 0.35 # the width of the bars
ind = np.arange(len(y_plot_means)) # the x locations for the groups
# Gráfico de barras para la media
ax.barh(ind, y_plot_means, width, color="darkseagreen", label='Media')
# Gráfico de barras para los datos del paciente
ax.barh(ind + width, y_plot_paciente.astype(float), width, color="skyblue")
ax.set_yticks(ind+width/2)
ax.set_yticklabels(labels = nombres_campos_formateados, fontweight='bold')
max_paciente = y_plot_paciente.astype(np.float64)
x_labels = np.max(max_paciente)
ax.set_xticklabels(labels = np.arange(0, x_labels+51, 50), fontweight='bold')
plt.title('Comparación de los atributos del pacientes con la media de infartos reales.', fontweight='bold')
plt.xlabel('Valores')
plt.ylabel('Atributo')
plt.legend(labels=['Media de Infartos', 'Paciente'])
fig.set_facecolor("mediumaquamarine")
ax.set_facecolor("mintcream")
# Agregar etiquetas con los valores del paciente en el gráfico
for i, v in enumerate(y_plot_means):
ax.annotate("{:.2f}".format(v), xy=(v + 4, i + .25), va='center', color='forestgreen', fontweight='bold')
for i, v in enumerate(y_plot_paciente.astype(float)):
ax.annotate("{:.2f}".format(v), xy=(v + 4, i + width + .33), va='center', color='steelblue', fontweight='bold')
# Guardar la figura en un archivo temporal
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_file:
fig.savefig(temp_file, format='png')
temp_file.close()
temp_filename = temp_file.name
return temp_filename
# Creamos la función con la que generaremos predicciones mediante el llenado de los
# valores de las variables y validaremos los valores que contienen los campos
def diagnosticar(age,sex,cp,trtbps,chol,fbs,restecg,thalachh,exng,oldpeak,slp,caa,thall):
# ---código para validación de campos---
# creamos una lista donde se almacenan los valores de los campos
inputs = [age,sex,cp,trtbps,chol,fbs,restecg,thalachh,exng,oldpeak,slp,caa,thall]
if all(var is not None and (var!= "" )and (var!= '') for var in inputs):
# verdadero si todas las variables tienen valores distintos a nulo
not_nulls = True;
else:
# falso si alguna de las variables tiene un valor nulo
not_nulls = False
# creamos una lista la cual contendra una tupla, donde se tendrá el nombre del campo y su valor nulo
campos_con_nulos = [nombres_campos[i] for i in range(len(inputs)) if (inputs[i] == "") or (inputs[i] == '') or (inputs[i] is None)]
# Dependiendo de la cantidad de campos vacíos mostraremos su error correspondiente
if len(campos_con_nulos) == 1:
raise gr.Error(message = f"Falta el campo: {campos_con_nulos} por llenar!")
else:
# creamos una cadena a partir de la lista campos_con_nulos
# juntaremos todos los registros en una sola cadena y separaremos el nombre
# de cada campo con una coma, seguido de un espacio y antes de que se
# muestre el nombre del campo se escribe una viñeta, esto para facilitarle
# al usuario la identificación de los campos vacíos
campos_faltantes = ', •'.join([campo for campo in campos_con_nulos])
raise gr.Error(message = f"¡Faltan por llenar {len(campos_con_nulos)} campos!: •{campos_faltantes}")
#---código para generar las predicciones---
if(not_nulls):
paciente_info = {
'age' : [age],
'sex' : [sex],
'cp' : [cp],
'trtbps' : [trtbps],
'chol' : [chol],
'fbs' : [fbs],
'restecg' : [restecg],
'thalachh' : [thalachh],
'exng' : [exng],
'oldpeak' : [oldpeak],
'slp' : [slp],
'caa' : [caa],
'thall' : [thall]
}
# creacion de DF para almacenar la información del paciente o usuario que
# quiera generar una predicción
paciente = pd.DataFrame(paciente_info)
#crear graficas para comparar el paciente con la media o el resto del dataset
graph = crear_grafico(paciente)
# Codificando las columnas categoricas
paciente_dummy = pd.get_dummies(paciente, columns = cat_cols, drop_first = True)
# Definiendo los atributos independientes y el atributo dependiente
all_cols = set(X_train.columns)
missing_cols = all_cols - set(paciente_dummy.columns)
for col in missing_cols:
paciente_dummy[col] = 0
paciente_dummy = paciente_dummy[X_train.columns]
paciente[con_cols] = scaler.transform(paciente[con_cols])
# Haciendo predicciones en nuevos datos
prediccion = logreg.predict(paciente_dummy)
if prediccion == 0:
return ("No se presenta riesgo de un infarto", graph)
else:
return ("Existe riesgo de infarto\nPor favor visite a un medico", graph)
else:
raise gr.Error("¡ERROR CRÍTICO.- Consulte a los desarrolladores.")
# Creación de block
with gr.Blocks(title="Predicción de riesgo de un IAM", theme = custom_theme) as modelo:
gr.Markdown(
"""
# Predicción de riesgo de Infarto Agudo al Miocardio
Modelo de Regresión Lineal para identificar la existencia de riesgo de un IAM.
Al final se presentan ejemplos, para ejecutarlos seleccionar uno y dar click en el botón "Generar".
"""
)
with gr.Row():
with gr.Column():
age = gr.Textbox(label="Edad",placeholder="Ingrese su edad en años.")
with gr.Row():
sex = gr.Dropdown(label="Sexo",
choices=["0","1"],
info="Mujer (0)\nHombre (1)",
placeholder="Seleccione la opción correspondiente.")
with gr.Row():
cp = gr.Dropdown(label="Tipo de dolor toracico",
info="0 = Angina típica\n1 = Angina atípica\n2 = Dolor no anginal\n3 = Asintomático",
choices=["0","1","2","3"],
placeholder="Seleccione la opción correspondiente.")
with gr.Row():
trtbps = gr.Textbox(label="Presión arterial en reposo",
info="(en mm Hg)",
placeholder="Ingrese su presión arterial.")
with gr.Row():
chol = gr.Textbox(label="Colesterol",
info="(en mg/dl obtenido a través del sensor de IMC)",
placeholder="Ingrese su nivel de colesterol.")
with gr.Row():
fbs = gr.Dropdown(label="Azúcar en sangre en ayunas",
info = "¿Es mayor a 120 mg/dl?\nSi (1) No (0)",
choices =["0","1"],
placeholder="Seleccione la opción correspondiente.")
with gr.Row():
restecg = gr.Dropdown(label="Resultados electrocardiográficos en reposo",
choices=["0","1","2"],
info="0 = Normal\n1 = Normalidad de la onda ST-T\n2 = Hipertrofia ventricular izquierda",
placeholder="Seleccione la opción correspondiente.")
with gr.Row():
thalachh = gr.Textbox(label="Ritmo cardíaco máximo alcanzado",
placeholder="Ingrese su ritmo cardíaco.")
with gr.Row():
exng = gr.Dropdown(label="Angina inducida por ejercicio",
choices=["0","1"],
info= "Si (1)\nNo (0)",
placeholder="Seleccione la opción correspondiente.")
with gr.Row():
oldpeak = gr.Textbox(label ="Depresión ST(Old Peak)",
info="Inducida por el ejercicio en relación al reposo.",
placeholder="Ingrese el valor correspondiente.")
with gr.Row():
slp = gr.Textbox(label="Pendiente del segmento ST",
info="-- Valor 1: ascendente\n-- Valor 2: horizontal\n-- Valor 3: descendente",
placeholder="Ingrese el valor en el pico del ejercicio.")
with gr.Row():
caa = gr.Dropdown(label="Número de vasos principales",
info="Valor obtenido en Fluoroscopia ",
choices=["0","1","2","3"],
placeholder="Seleccione la opción correspondiente.")
with gr.Row():
thall = gr.Dropdown(label="Resultado de la prueba de esfuerzo con talio",
info="1 = normal.\n2 = defecto fijo.\n3 = defecto reversible.",
choices=["1","2","3"],
placeholder="Seleccione la opción correspondiente.")
with gr.Row():
prediction_btn = gr.Button(value = "Generar")
with gr.Row():
prediction = gr.Textbox(label=("Resultado"))
with gr.Row():
graphGR = gr.Image(label=("Gráfica"))
prediction_btn.click(diagnosticar,
inputs = [age,sex,cp,trtbps,chol,fbs,restecg,thalachh,exng,oldpeak,slp,caa,thall],
outputs = [prediction, graphGR],
api_name = "prediccion-riesgo-iam")
data_dict = gr.Textbox(label = "Diccionario de datos", value = texto_atributos, interactive = False)
examples = gr.Examples(label="Ejemplos", examples=[
[64, 1, 0, 120, 246, 0, 0, 96, 1, 2.2, 0, 1, 2], # riesgo inexistente
[43,0,0,132,341,1,0,136,1,3,1,0,3,0], # riesgo inexistente
[50,0,2,120,219,0,1,158,0,1.6,1,0,2,1], # hay riesgo
[37,1,2,130,250,0,1,187,0,3.5,0,0,2]# hay riesgo
], inputs=[age,sex,cp,trtbps,chol,fbs,restecg,thalachh,exng,oldpeak,slp,caa,thall])
modelo.close()
modelo.launch(inline=False)