Herramientas de usuario

Herramientas del sitio


clase:iabd:pia:2eval:tema08.metricas_clasificacion

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
clase:iabd:pia:2eval:tema08.metricas_clasificacion [2025/02/13 21:43]
admin [Teorema de Bayes]
clase:iabd:pia:2eval:tema08.metricas_clasificacion [2025/02/26 20:11] (actual)
admin [Ejercicios]
Línea 359: Línea 359:
 <sxh python> <sxh python>
 metrics=[tf.keras.metrics.Recall()] metrics=[tf.keras.metrics.Recall()]
-metrics=["Recall"]+metrics=["recall"]
 </sxh> </sxh>
  
Línea 367: Línea 367:
 history.history['val_recall'] history.history['val_recall']
 </sxh> </sxh>
 +
 +<note important>
 +En versiones antiguas de Tensorflow, se llamaba ''Recall'' (Con la R en mayúscula)
 +</note>
  
 Ejemplo: Ejemplo:
Línea 387: Línea 391:
  
 <sxh python> <sxh python>
-def specificity(y_true, y_score): 
-    threshold=0.5 
-    y_pred = tf.cast(tf.greater(y_score, threshold), tf.float32) 
  
 +from tensorflow.keras import backend as K
  
-    true_negatives = tf.logical_and(tf.equal(y_true, 0), tf.equal(y_pred0)+def specificity(y_true, y_score,threshold = 0.5)
-    num_true_negatives=tf.reduce_sum(tf.cast(true_negativestf.float32))+     
 +    y_true = K.cast(y_truedtype='float32'
 +    y_pred K.cast(y_score > thresholddtype='float32')
  
  
-    negatives =tf.equal(y_true, 0) 
-    num_negatives= tf.reduce_sum(tf.cast(negatives, tf.float32)) 
  
 +    y_true = tf.reshape(y_true, (-1, 1))
 +    y_pred = tf.reshape(y_pred, (-1, 1))
 +
 +
 +    TN = K.sum((1 - y_true) * (1 - y_pred))  
 +    FP = K.sum((1 - y_true) * y_pred)        
 +
 +    specificity = TN / (TN + FP + K.epsilon())  
  
-    specificity = num_true_negatives / (num_negatives + tf.keras.backend.epsilon()) 
-     
     return specificity     return specificity
 </sxh> </sxh>
Línea 427: Línea 435:
 </sxh> </sxh>
  
 +El motivo de éstas 2 líneas de código 
  
 +<sxh python>
 +TN = K.sum((1 - y_true) * (1 - y_pred))  
 +FP = K.sum((1 - y_true) * y_pred)   
 +</sxh>
  
 +se puede ver en la siguiente tabla de verdad:
 +
 +^  Entradas  ^^  Salidas  ^^^^
 +^  ''y_true''  ^  ''y_pred''  ^  TP  ^  TN  ^  FP  ^  FN  ^
 +|  1    1  |  1  |  0  |  0  |  0  |
 +|  0    0  |  0  |  1  |  0  |  0  |
 +|  0    1  |  0  |  0  |  1  |  0  |
 +|  1    0  |  0  |  0  |  0  |  1  |
 +
 +
 +Y se puede calcular de 2 maneras distintas:
 +
 +  * Aritméticamente
 +
 +<sxh python>
 +TP = sum(y_true * y_pred) 
 +TN = sum((1 - y_true) * (1 - y_pred))  
 +FP = sum((1 - y_true) * y_pred) 
 +FN = sum(y_true * (1 - y_pred))  
 +</sxh>
 + 
 +
 +  * Lógicamente
 +<sxh python>
 +TP = sum((y_true==1) & (y_pred==1))
 +TN = sum((y_true==0) & (y_pred==0))
 +FN = sum((y_true==1) & (y_pred==0))
 +FP = sum((y_true==0) & (y_pred==1))
 +</sxh>
 +
 +
 + 
  
  
Línea 456: Línea 501:
 Para mostrar la matriz de confusión se usará la siguiente función que usa de ''matplotlib'' Para mostrar la matriz de confusión se usará la siguiente función que usa de ''matplotlib''
 <sxh python> <sxh python>
-def plot_matriz_confusion(axes,TP=0,TN=0,FP=0,FN=0,fontsize=15,vpp=None,vpn=None,sensibilidad=None,especificidad=None,f1_score=None,mcc=None,auc=None,prevalencia=None):+def plot_matriz_confusion(axes,TP=0,TN=0,FP=0,FN=0,fontsize=15,titulo=None,vpp=None,vpn=None,sensibilidad=None,especificidad=None,f1_score=None,mcc=None,auc=None,prevalencia=None):
     success_color=matplotlib.colors.to_rgb('#9EE548')     success_color=matplotlib.colors.to_rgb('#9EE548')
     failure_color=matplotlib.colors.to_rgb("#C32240")     failure_color=matplotlib.colors.to_rgb("#C32240")
Línea 462: Línea 507:
  
  
-    if ((vpp is not None) | +    if ((vpp is not None) |  
-        (vpn is not None) |+        (vpn is not None) | 
         (sensibilidad is not None) |         (sensibilidad is not None) |
-        (especificidad is not None) |+        (especificidad is not None) | 
         (prevalencia is not None) |         (prevalencia is not None) |
-        (f1_score is not None) |+        (f1_score is not None) | 
         (mcc is not None) |         (mcc is not None) |
         (auc is not None) ):         (auc is not None) ):
Línea 481: Línea 526:
  
  
 +    if titulo==None:
 +        titulo="Predicción"
 +    else:
 +        titulo=titulo+"\nPredicción"
  
     labels = ['Positivo','Negativo']     labels = ['Positivo','Negativo']
Línea 489: Línea 538:
     axes.set_yticklabels(labels, fontsize=13, color="#003B80")     axes.set_yticklabels(labels, fontsize=13, color="#003B80")
     axes.text(0, 0, str(TP)+" TP",ha="center", va="center", color="#0A2102",fontsize=fontsize)     axes.text(0, 0, str(TP)+" TP",ha="center", va="center", color="#0A2102",fontsize=fontsize)
-    axes.text(0, 1, str(FP)+" FP",ha="center", va="center", color="#FAEAEA",fontsize=fontsize)+    axes.text(0, 1, str(FP)+" FP",ha="center", va="center", color="#FAEAEA",fontsize=fontsize) 
     axes.text(1, 0, str(FN)+" FN",ha="center", va="center", color="#FAEAEA",fontsize=fontsize)     axes.text(1, 0, str(FN)+" FN",ha="center", va="center", color="#FAEAEA",fontsize=fontsize)
-    axes.text(1, 1, str(TN)+" TN",ha="center", va="center", color="#0A2102",fontsize=fontsize)        +    axes.text(1, 1, str(TN)+" TN",ha="center", va="center", color="#0A2102",fontsize=fontsize)         
     axes.xaxis.tick_top()     axes.xaxis.tick_top()
-    axes.set_xlabel('Predicción', fontsize=fontsize, color="#003B80"+    axes.set_xlabel(titulo, fontsize=fontsize, color="#003B80")  
-    axes.xaxis.set_label_position('top'+    axes.xaxis.set_label_position('top')  
-    axes.set_ylabel('Realidad', fontsize=fontsize, color="#003B80")+    axes.set_ylabel('Realidad', fontsize=fontsize, color="#003B80"
  
  
Línea 506: Línea 555:
             axes.text(1, 2, f"VPN\n{vpn:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4)             axes.text(1, 2, f"VPN\n{vpn:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4)
         if (sensibilidad is not None):         if (sensibilidad is not None):
-            axes.text(2, 0, f"Sensibilidad\n{sensibilidad:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4)+            axes.text(2, 0, f"Sensibilidad\n{sensibilidad:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4) 
         if (especificidad is not None):         if (especificidad is not None):
-            axes.text(2, 1, f"Especificidad\n{especificidad:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4)+            axes.text(2, 1, f"Especificidad\n{especificidad:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4) 
  
         metricas_generales=""         metricas_generales=""
Línea 514: Línea 563:
             metricas_generales=metricas_generales+f"Prevalencia\n{prevalencia:.2f}\n"                     metricas_generales=metricas_generales+f"Prevalencia\n{prevalencia:.2f}\n"        
         if (f1_score is not None):         if (f1_score is not None):
-            metricas_generales=metricas_generales+f"F1-score\n{f1_score:.2f}\n"  +            metricas_generales=metricas_generales+f"F1-score\n{f1_score:.2f}\n"   
         if (mcc is not None):         if (mcc is not None):
             metricas_generales=metricas_generales+f"MCC\n{mcc:.2f}\n"               metricas_generales=metricas_generales+f"MCC\n{mcc:.2f}\n"  
         if (auc is not None):         if (auc is not None):
-            metricas_generales=metricas_generales+f"AUC\n{auc:.2f}"            +            metricas_generales=metricas_generales+f"AUC\n{auc:.2f}"             
  
-        axes.text(2, 2, metricas_generales,ha="center", va="center", color="#0A2102",fontsize=fontsize-4)  +        axes.text(2, 2, metricas_generales,ha="center", va="center", color="#0A2102",fontsize=fontsize-4)    
 </sxh> </sxh>
  
Línea 611: Línea 660:
 Crea una red neuronal con los datos de //bread cancer// con las siguientes características: Crea una red neuronal con los datos de //bread cancer// con las siguientes características:
  
-  * neuronas por capa:''[30,64,32,16,8,1]'' +  * neuronas por capa:''[30,60,120,200,120,60,30,15,1]'' 
-  * Función de activation: ''ELU'' +  * Función de activation: ''swish'' 
-  * Nº de epocas: ''20'' +  * Nº de epocas: ''30'' 
-  * Optimizador: ''Adam'' con tasa de aprendizaje de ''0,0001''+  * Optimizador: ''Adam'' con tasa de aprendizaje de ''0.00001''
  
-Muestra las siguientes métricas durante el entrenamiento (para cada una de las épocas):+Muestra las siguientes métricas durante el entrenamiento y validación (para cada una de las épocas):
   * Loss   * Loss
   * Sensibilidad   * Sensibilidad
Línea 622: Línea 671:
  
 {{:clase:iabd:pia:2eval:metricas-epocas.png?direct|}} {{:clase:iabd:pia:2eval:metricas-epocas.png?direct|}}
 +
 +<note important>
 +Separa los datos en 3 conjuntos:
 +  * Entrenamiento (60%)
 +  * Validación (20%)
 +  * Test (20%)
 +</note>
 +
  
 ==== Ejercicio 3.B ==== ==== Ejercicio 3.B ====
 En este ejercicio vamos a mostrar la matriz de confusión de la red que acabamos de crear. En este ejercicio vamos a mostrar la matriz de confusión de la red que acabamos de crear.
  
-Para ello vamos a usar los valores de test que los tenemos en las siguientes variables del ejercicio anterior: +Para ello vamos a usar los valores de validación que los tenemos en las siguientes variables del ejercicio anterior: 
-  * ''x_test'' +  * ''x_validacion'' 
-  * ''y_test''+  * ''y_validacion''
  
-La variable ''y_test'' es lo que llamamos ''y_true'' mientras que con ''x_test'' obtendremos ''y_score''.+La variable ''y_validacion'' es lo que llamamos ''y_true'' mientras que con ''y_score'' obtendremos ''y_pred''.
  
 Para ello sigue los siguientes pasos: Para ello sigue los siguientes pasos:
 +  * Crea una función llamada ''get_y_pred(y_score,threshold)''
   * Crea una función llamada ''get_matriz_confusion(y_true,y_score,threshold)'' que retorne ''TP'' ,''TN'', ''FP'' y ''FN''   * Crea una función llamada ''get_matriz_confusion(y_true,y_score,threshold)'' que retorne ''TP'' ,''TN'', ''FP'' y ''FN''
-  * Calcula ''y_score'' usando el método ''predict'' del modelo y usando la variable ''x_test'' +  * Calcula ''y_score'' usando el método ''predict'' del modelo y usando la variable ''x_validacion'' 
-  * Haz que ''y_true'' sea igual a ''y_test''+  * Haz que ''y_true'' sea igual a ''y_validacion'' ya que son los mismos datos.
   * Llama a la función ''get_matriz_confusion''   * Llama a la función ''get_matriz_confusion''
   * Muestra la matriz de confusión    * Muestra la matriz de confusión 
Línea 659: Línea 717:
    
  
-==== Ejercicio 3.E ==== +==== Ejercicio 4:Validación ==== 
-En un nuevo jupyter notebookcarga el modelo y con los datos de test , vuelve mostrar la matriz de confusión con todas las métricas.+Ahora vamos calcular todas las métricas de nuevo pero de un modelo que no hemos entrenado sino que nos lo han "pasado". Es decir el equipo de desarrollo ha hecho el modelo y ahora lo vamos a //testear//..
  
 +Para ello en un nuevo jupyter notebook, carga el modelo que guardaste en el ejercicio anterior y vuelve a mostrar la matriz de confusión con todas las métricas.
  
 +<note important>
 +Usa los datos de **test** para obtener las métricas. 
 +</note>
  
-==== Ejercicio 3.==== +==== Ejercicio 5.A: Umbral ==== 
-Muestra ahora gráfica, en la que se mostrará:+Muestra ahora una gráfica, en la que se mostrará:
  
   * El valor de la sensibilidad y la especificidad según el valor del umbral   * El valor de la sensibilidad y la especificidad según el valor del umbral
Línea 671: Línea 733:
 {{:clase:iabd:pia:2eval:threshold-metricas.png?direct|}} {{:clase:iabd:pia:2eval:threshold-metricas.png?direct|}}
  
-¿Que valor de umbral dejarías? 
  
-==== Ejercicio 3.G ==== +<note important> 
-Muestra una gráfica similar a las anteriores pero ahora sea la suma los valores de sensibilidad y la especificidad menos 1+Usa los datos de **test** para obtener las métricas 
 +</note>
  
-A la suma de los 2 valores para obtener el máximo pero restando 1 se le llama $Informedness$ 
  
-$$ +==== Ejercicio 5.B ==== 
-Informedness=Sensibilidad+Especificidad-1 +Muestra varias matrices de confusión, una para cada uno de estos umbrales: ''[0.2,0.3,0.4,0.5,0.7,0.8]'' 
-$$+{{:clase:iabd:pia:2eval:matriz-confusion-varios-umbrales.png|}}
  
-Muestra un punto con el máximo de la gráfica y el threshold correspondiente al máximo.Además para ese nivel de threshold, **imprime la sensibilidad y la especificidad** 
  
-{{:clase:iabd:pia:2eval:threshold-markedness-informedness.png?direct|}}+¿Que es mejor una alta precisión alta (VPP) o un alto VPNElije el umbral adecuado.
  
 +<note important>
 +Usa los datos de **test** para obtener las métricas. 
 +</note>
  
 +==== Ejercicio 5.C ====
 +Ahora calcula una tabla similar a esta para ver resultado de 8 pacientes.
  
-==== Ejercicio 4 ==== +<sxh python> 
-Indica en los siguientes problemas si subirías o bajarías el umbral+Paciente      y_score    Umbral  Resultado    Prob.      Realidad 
 +                                 Test         Acierto 
 +----------  ---------  --------  -----------  ---------  ---------- 
 +Nº 347      0.32628         0.3  Positivo     88% VPP    Enfermo 
 +Nº 270      0.95804         0.3  Positivo     88% VPP    Enfermo 
 +Nº 213      0.958995        0.3  Positivo     88% VPP    Sano 
 +Nº 3        0.31489         0.3  Positivo     88% VPP    Sano 
 +Nº 214      0.286227        0.3  Negativo     96% VPN    Sano 
 +Nº 265      0               0.3  Negativo     96% VPN    Sano 
 +Nº 92       0.0623996       0.3  Negativo     96% VPN    Enfermo 
 +Nº 476      0.275804        0.3  Negativo     96% VPN    Enfermo 
 +</sxh>
  
-  * Una IA que detecta si hay petroleo en el subsuelo +Responde ahora a estas preguntas: 
-  * Una IA que predice si un usuario en Amazon está cometiendo fraude +  * ¿Que tiene de extraño el valor de algunos resultados?  
-  * Una IA que decide si te concede un préstamo +  * ¿Es útil el ''y-score''? 
-  * Una IA que decide una persona en un juicio es inocente +  * Porque $P(Enfermo|Positivo)=VPP=Precisión$ es siempre la misma? 
-  * Una IA que corrige automáticamente un examen y te dice si has aprobado+  * Porque $P(Sano|Negativo)=VPN$ es siempre la misma?
  
 +Para saber con que pacientes debe probar concretamente en tu modelo, usa la función ''get_pacientes_a_probar(model)'' que retornará un array con los pacientes a probar.
  
 +<sxh python>
 +def get_paciente_a_probar(indices,y_pred,order):
 +    y_pred_values = y_pred[indices]
 +    sorted_indices = indices[0][np.argsort(order*y_pred_values)]
  
-==== Ejercicio 5.A ==== +    return sorted_indices[0]
-Crea una nueva red neuronal para el problema del //bread cancer//+
  
-Ahora razona con cual de las 2 redes te quedarías y que threshold elegirías para cada uno de ellos.+def get_pacientes_a_probar(model): 
 +    breast_cancer=load_breast_cancer() 
 +    tolerancia=0.07 
 +    desc=-1 
 +    asc=1 
 +    numeros_pacientes=[]
  
-Para elegir debes mostrar gráficas una al lado de la otra para comparar lo siguiente: +    y_pred=model.predict(breast_cancer.data,verbose=False).reshape(-1)
-  * Gráficos de perdida, sensibilida y especificidad durante el entrenamiento +
-  * Matriz de confusión con las métricas: Sensibilidad, Especificidad, VPP, VPN, Prevalencia +
-  * Threshold vs (Sensibilidad y Especificidad) +
-  * Threshold vs Informedness (Muestra en el label el máximo)+
  
 +    #TP Malo:
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==1) & (y_pred>best_threshold) & (y_pred<best_threshold+tolerancia)),y_pred,asc))
 +    #TP Bueno
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==1) & (y_pred>1-tolerancia) & (y_pred<1)),y_pred,desc))
  
-¿Con que red te quedarías?+    #FP Malo 
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==0) & (y_pred>1-tolerancia) & (y_pred<1)),y_pred,desc)) 
 +    #FP Casi bueno 
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==0) & (y_pred>best_threshold) & (y_pred<best_threshold+tolerancia)),y_pred,asc))
  
-{{:clase:iabd:pia:2eval:comparar_redes.png?direct|}}+    #TN Malo 
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==0) & (y_pred>best_threshold-tolerancia) & (y_pred<best_threshold)),y_pred,desc)) 
 +    #TN Bueno 
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==0) & (y_pred>0.0) & (y_pred<tolerancia)),y_pred,asc)) 
 + 
 +    #FN Malo 
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==1) & (y_pred>0.0) & (y_pred<=tolerancia)),y_pred,desc)) 
 +    #FN Casi bueno 
 +    numeros_pacientes.append(get_paciente_a_probar(np.where((breast_cancer.target==1) & (y_pred>best_threshold-tolerancia) & (y_pred<best_threshold)),y_pred,asc)) 
 + 
 +    return numeros_pacientes 
 +</sxh> 
 + 
 +==== Ejercicio 6 ==== 
 +Indica en los siguientes problemas si es mejor una precisión alta (VPP) o un alto VPN 
 + 
 +  * Una IA que detecta si hay petroleo en el subsuelo 
 +  * Una IA que predice si un usuario en Amazon está cometiendo fraude 
 +  * Una IA que decide si te concede un préstamo 
 +  * Una IA que decide una persona en un juicio es inocente 
 +  * Una IA que corrige automáticamente un examen y  dice si se ha aprobado
  
-Además para el nivel de threshold de la red que ha "ganado", **imprime la sensibilidad y la especificidad** 
  
-==== Ejercicio 5.B ==== 
-Con el modelo elegido, guarda el modelo a disco 
  
  
-==== Ejercicio 5.C ==== 
-Con modelo que has elegido, cárgalo desde disco en otro Jupyter notebook y realiza inferencia de 10 pacientes.  
  
-Para cada paciente: 
-  * Indica su prevalencia (te la tienes que inventar de forma aleatoria) 
-  * Indica la probabilidad de que la red haya acertado. 
  
  
clase/iabd/pia/2eval/tema08.metricas_clasificacion.1739479393.txt.gz · Última modificación: 2025/02/13 21:43 por admin