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/15 17:23]
admin [Ejercicios]
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 y validación (para cada una de las épocas): Muestra las siguientes métricas durante el entrenamiento y validación (para cada una de las épocas):
Línea 634: Línea 683:
 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_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'' ya que son los mismos datos.+  * 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 684: Línea 733:
 {{:clase:iabd:pia:2eval:threshold-metricas.png?direct|}} {{:clase:iabd:pia:2eval:threshold-metricas.png?direct|}}
  
-¿Qué valor de umbral dejarías? Elige uno que no sea ''0.5'' 
  
 <note important> <note important>
Línea 692: Línea 740:
  
 ==== Ejercicio 5.B ==== ==== Ejercicio 5.B ====
-Vuelve a mostrar la matriz de confusión con todas las métricas pero usando el umbral que decidiste en el apartado anterior.+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|}} 
 + 
 + 
 +¿Que es mejor una alta precisión alta (VPP) o un alto VPN? Elije el umbral adecuado.
  
 <note important> <note important>
 Usa los datos de **test** para obtener las métricas.  Usa los datos de **test** para obtener las métricas. 
 </note> </note>
 +
 +==== Ejercicio 5.C ====
 +Ahora calcula una tabla similar a esta para ver resultado de 8 pacientes.
 +
 +<sxh python>
 +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>
 +
 +Responde ahora a estas preguntas:
 +  * ¿Que tiene de extraño el valor de algunos resultados? 
 +  * ¿Es útil el ''y-score''?
 +  * Porque $P(Enfermo|Positivo)=VPP=Precisión$ es siempre la misma?
 +  * 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)]
 +
 +    return sorted_indices[0]
 +
 +def get_pacientes_a_probar(model):
 +    breast_cancer=load_breast_cancer()
 +    tolerancia=0.07
 +    desc=-1
 +    asc=1
 +    numeros_pacientes=[]
 +
 +    y_pred=model.predict(breast_cancer.data,verbose=False).reshape(-1)
 +
 +    #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))
 +
 +    #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))
 +
 +    #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 ==== ==== Ejercicio 6 ====
-Indica en los siguientes problemas si subirías bajarías el umbral+Indica en los siguientes problemas si es mejor una precisión alta (VPP) un alto VPN
  
   * Una IA que detecta si hay petroleo en el subsuelo   * Una IA que detecta si hay petroleo en el subsuelo
Línea 705: Línea 821:
   * Una IA que decide si te concede un préstamo   * Una IA que decide si te concede un préstamo
   * Una IA que decide una persona en un juicio es inocente   * Una IA que decide una persona en un juicio es inocente
-  * Una IA que corrige automáticamente un examen y te dice si has aprobado+  * Una IA que corrige automáticamente un examen y  dice si se ha aprobado
  
- 
-==== Ejercicio 7 ==== 
-Haz ahora un pequeño programa en modo texto en python en el que: 
-  * Se pregunte al usuario los datos del "//bread cancer//". 
-    * Para facilitar la entrada que ponga valores por defecto para cada //x// y que indique el rango que tenemos en los posibles valores. 
-  * La prevalencia. Si la deja en blanco serán las de los datos 
-  * Que indique si tiene o no cáncer. 
-    * Si tiene cáncer que indique al usuario la probabilidad de que esta IA haya acertado (VPP) 
-    * Si no tiene cáncer que indique al usuario la probabilidad de que esta IA haya acertado (VPN) 
- 
-<note important> 
-Ahora hazte las siguientes preguntas 
-  * ¿Deberíamos haber preguntado al usuario el umbral? 
-  * ¿Deberíamos mostrar al usuario el ''y_score''? 
-</note> 
  
  
clase/iabd/pia/2eval/tema08.metricas_clasificacion.1739636607.txt.gz · Última modificación: 2025/02/15 17:23 por admin