Hasta ahora hemos visto como definir una red neuronal y como entrenarla. El último paso que nos queda es saber si la red ha funcionado correctamente. Pero ¿Eso no se hacía con la función de coste? Pues no exactamente. La función de coste se usa para ayudar a ajustar los parámetros durante el entrenamiento mediante los datos de entrada pero no para saber si el modelo es bueno. Para saber si el modelo es bueno , se usan las métricas.
Las métricas son muy parecidas a las funciones de coste pero hay métricas que no existen como función de coste. El muchos casos la métrica será la misma que la función de coste.
En el método fit
de Keras tenemos un nuevo parámetro para indicar la métrica llamado metrics
que contiene un array con todas las métricas que queremos tener en nuestra red mientras se va entrenando
model.compile(loss="binary_crossentropy",optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),metrics=["AUC"]) history=model.fit(x,y_true,epochs=20,verbose=False)
Para obtener los valores de la métrica en cada época se usa la siguiente línea
history.history['auc'] history.history['val_auc']
Acabamos de ver que entrenando la red neuronal , el error se consigue bajar a prácticamente cero. Es decir que los valores de los parámetros , pesos (weight) y sesgos bias, debe ser muy buenos. No exactamente. Resulta que los parámetros se han ajustado a los datos que le hemos pasado, pero ¿Como es de bueno el modelo para nuevos datos que no ha visto? Realmente ver como se comporta con datos nuevos y con los datos que ha ya visto es lo que nos va a decir como es de bueno nuestro modelo. Así que pasemos a ver como sacar las métricas también con datos nuevos.
Lo primero es averiguar de donde obtenemos nuevos datos. Normalmente no tenemos nuevos datos así que lo que hacemos es que solo vamos a entrenar nuestra red neuronal con el 80% de los datos y el 20% restante los guardaremos para validar la red neuronal. Eso lo vamos a hacer con la función train_test_split de scikit-learn
from sklearn.model_selection import train_test_split x_train, x_test, y_train, y_test = train_test_split(x, y_true, test_size=0.2, random_state=42)
La función train_test_split
tiene los siguientes argumentos:
test_size
: La fracción de datos que se va a usar para la validación.Es un valor de 0.0 a 1.0. Siendo 0.0 que no hay datos para validación y 1.0 que todos sería para validación.Un valor aceptable de test_size
es entre 0.2
a 0.3
. random_state
: Es para que sea reproducible el generador de los números aleatorios. x_train
: Array con la x
de los datos de entrenamientox_test
: Array con la x
de los datos de validación y_train
: Array con la y
de los datos de entrenamientoy_test
: Array con la y
de los datos de validaciónY ahora a Keras se los tenemos que pasar así:
history=model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=epochs,verbose=False)
Lo datos de entrenamiento se pasan igual que antes pero los de validación se pasan en en un tupla en un parámetro llamado validation_data
.
Por último tenemos que obtener la métrica para los datos de validación. Se obtiene igual que antes pero el nombre de la métrica empieza por val_
history.history['val_binary_accuracy']
Veamos un ejemplo completo:
import numpy as np import tensorflow as tf import numpy as np import pandas as pd import keras import random from keras.models import Sequential from keras.layers import Dense from sklearn.datasets import load_iris import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split iris=load_iris() x=iris.data[0:99,2] y_true=iris.target[0:99] np.random.seed(5) tf.random.set_seed(5) random.seed(5) x_train, x_test, y_train, y_test = train_test_split(x, y_true, test_size=0.2, random_state=42) model=Sequential() model.add(Dense(3, input_dim=1,activation="sigmoid",kernel_initializer="glorot_normal")) model.add(Dense(1,activation="sigmoid",kernel_initializer="glorot_normal")) model.compile(loss="binary_crossentropy",optimizer=tf.keras.optimizers.Adam(learning_rate=0.01),metrics=["binary_accuracy"]) history=model.fit(x_train,y_train,validation_data=(x_test,y_test),epochs=40,verbose=False) figure=plt.figure(figsize=(8,6)) axes = figure.add_subplot() axes.plot(history.history['binary_accuracy'],label="Entrenamiento "+str(history.history['binary_accuracy'][-1])) axes.plot(history.history['val_binary_accuracy'],label="Validación "+str(history.history['val_binary_accuracy'][-1])) axes.legend() axes.set_xlabel('Época', fontsize=15,labelpad=20,color="#003B80") axes.set_ylabel('Valor métrica', fontsize=15,labelpad=20,color="#003B80") axes.set_facecolor("#F0F7FF") axes.grid(b=True, which='major', axis='both',color="#FFFFFF",linewidth=1)
Podemos ver en el gráfico que la métrica es muy similar con los datos de validación que con los de entrenamiento. otro detalle importante es que las métricas suelen ser buenas si su valor es 1 (al contrario de las funciones de pérdida en la que lo bueno era un 0)
Para acabar el tema vamos a ver las distintas métricas que existen. Lo primero es indicar nombres tanto en inglés como en español ya que vamos a usar los nombres en inglés
Inglés | Español |
---|---|
Precision | Precisión |
Recall | Exhaustividad |
F1-score | Valor-F |
Accuracy | Exactitud |
Sensitivity | Sensibilidad |
Confusion Matrix | Matriz de Confusión |
True Positive | Positivos Verdaderos |
True Negative | Negativos Verdaderos |
False Positive | Positivos Falsos |
False Negative | Negativos Falsos |
Hay métricas que son exactamente iguales a las funciones de coste como MEA o MSE en los problemas de regresión MAE, MSE. Si ya las usamos como función de coste y queremos usarlas como métricas no es necesario indicarlas como métricas, se puede acceder a ellas de la siguiente forma:
Para mostrar la función de coste en el entrenamiento:
history.history['loss']
Para mostrar la función de coste en la validación:
history.history['val_loss']
Son las métricas que se usan en problemas de regresión. Son casi las mismas que usábamos como funciones de coste.
Es igual que la función de coste de Mean Absolute Error (MAE), así que no explicaremos nada mas sobre ella excepto como se usa en Keras como métrica
Se define como:
metrics=[tf.keras.metrics.MeanAbsoluteError()] metrics=["mean_absolute_error"] metrics=["mae"]
y usarla como
history.history['mean_absolute_error'] history.history['val_mean_absolute_error'] history.history["mae"] history.history["val_mae"]
Mas información:
Es igual que la función de coste de Mean Squared Error (MSE), así que no explicaremos nada mas sobre ella excepto como se usa en Keras como métrica
Se define como:
metrics=[tf.keras.metrics.MeanSquaredError()] metrics=["mean_squared_error"] metrics=["mse"]
y usarla como
history.history['mean_squared_error'] history.history['val_mean_squared_error'] history.history["mse"] history.history["val_mse"]
Mas información:
Es igual que la función de coste de Distancia del coseno, así que no explicaremos nada mas sobre ella excepto como se usa en Keras como métrica
Se define en Keras como:
metrics=[tf.keras.metrics.CosineSimilarity()] metrics=["cosine_similarity"]
y se usa como
history.history['cosine_similarity'] history.history['val_cosine_similarity']
Mas información:
La Root Mean Squared Error (RMSE) o Raiz cuadrada del error cuadrático medio se calcula igual que el MSE pero se le aplica la raíz cuadrada.
Por lo tanto su fórmula es
$$RMSE = \sqrt{MSE}= \sqrt{\frac{1}{N} \sum\limits_{i=1}^{N}(y_{i} - \hat{y_{i}})^2}$$
Ahora vamos a explicar algunas cosas de RMSE.
Se define en Keras como:
metrics=[tf.keras.metrics.RootMeanSquaredError()]
y se usa como
history.history['root_mean_squared_error'] history.history['val_root_mean_squared_error']
Mas información:
El coeficiente de determinación o R² se calcula de la siguiente forma:
$$R^{2} = 1- \frac {\sum\limits_{i=1}^{N} (y_{i} - \hat{y_{i}})^2} {\sum\limits_{i=1}^{N} (y_{i} - \bar{y})^2}$$ $$\bar{y}=\frac {1}{N} \sum\limits_{i=1}^{N} y_{i} - \hat{y_{i}}$$
Siendo:
Ahora vamos a explicar algunas cosas de R²
num_regressors
a la clase RSquare
Se define en Keras como:
metrics=[tfa.metrics.RSquare()]
y se usa como
history.history['r_square']
Mas información:
La elección de una métrica u otra se puede ver en MAE, MSE, RMSE, Coefficient of Determination, Adjusted R Squared — Which Metric is Better? y Know The Best Evaluation Metrics for Your Regression Model
Clasificación con 2 posibles valores es cuando la salida de nuestra red neuronal solo puede tener 2 posibles valores.
Antes de entrar a ver las métricas , es necesario entender lo que son:
Predicción | |||
---|---|---|---|
Positivo | Negativo | ||
Realidad | Enfermo | TP | FN |
Sano | FP | TN |
Para explicar todos estos conceptos véase los artículos:
Más información:
En la clasificación binaria los posibles valores son 1
y 0
o True
y False
. Sin embargo nuestra red neuronal suele sacar un valor entre 0
y 1
.
A ese valor se le llama y_score
y en función de un threshold
lo transformamos en el valor predicho o y_pred
.
Si el valor del score
es mayor que el threshold
el valor predicho será un True
mientras que si el valor del score
es menor que el threshold
el valor predicho será un False
Veamos un ejemplo de ello:
y_score=np.array([0.27, 0.45, 0.76, 0.55, 0.28, 0.04, 0.34,0.4, 0.66, 0.88, 0.94,0.47,0.2]) y_pred=y_score>0.5 print(y_pred)
Siendo el resultado
[False False True True False False False False True True True False False]
Por ello la mayoría de nuestras métricas son dependientes del valor que indiquemos de threshold
. Excepto la métrica de AUC
que es independiente del valor de threshold
.
Un ejemplo de lo que acabamos de ver está en las métricas de f1-score
y AUC
de sklearn.
En https://scikit-learn.org/stable/modules/generated/sklearn.metrics.f1_score.html los parámetros de entrada son y_true
e y_pred
mientras que en https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html los parámetros de entrada son y_true
e y_score
ya que no necesita el umbral
La probabilidad condicional se expresa de la siguiente forma P(A|B) que significa , la probabilidad de que ocurra A sabiendo que ya ocurrido B. ¿Y que tiene que ver ésto con las métricas? Realmente las métricas se pueden expresar como probabilidades condicionales. Lo bueno de usar probabilidades condicionales es que se entienden mejor.
Para explicar las métricas vamos a imaginar los test de COVID que comprobamos en las farmacias , que nos decían si teníamos o no COVID. El ejemplo es igual que si fuera una red neuronal que dado una radiografía nos dijera si teníamos o no COVID. Pero se usa el test de farmacia de COVID para hacer más comprensible la explicación.
Para poner la probabilidad condicional vamos a usar la siguiente nomenclatura:
Veamos ahora unas probabilidades condicionales.
Detengámonos un momento. ¿Cual de las 2 probabilidades nos interesa?. P(Positivo|Enferma) o P(Enferma|Positivo). Si lo pensamos , ¿para que queremos saber P(Positivo|Enferma)? Si ya sabemos que la persona está enferma, ¿para que querríamos usar el test? ¡¡Ya sabemos que está enferma!!!! Así que realmente nos interesa $P(Enferma|Positivo)$
Pongamos ahora todas las combinaciones de probabilidades posibles de las métricas que realmente nos interesan.
Mientras que las 4 siguientes aparentemente no nos interesan lo más mínimo:
Volvamos a la matriz de confusión:
Predicción | |||
---|---|---|---|
Positivo (PP) | Negativo (PN) | ||
Realidad | Enfermo (P) | TP | FN |
Sano (N) | FP | TN |
$$ \begin{array} \\ E&=&TP+FN&=&Nº \; de \; enfermos \\ S&=&FP+TN&=&Nº \; de \; sanos \\ PP&=&TP+FP&=&Nº \; predichos \; positivos \\ PN&=&FN+TN&=&Nº \; predichos \; negativos \\ \end{array} $$
Y siendo un poco perspicaces podremos ver como se calculan las 8 probabilidades y los nombres que tienen:
$$
\begin{array}
\\
P(Enfermo|Positivo)&=&\frac{TP}{PP}&=&\frac{TP}{TP+FP}&=&Positive \; Predictive \; Value \; (PPV)&=&Precisión&
\\
P(Sano|Positivo)&=&\frac{FP}{PP}&=&\frac{FP}{TP+FP}&=&False \; Discovery \; Rate \; (FDR)&=&1-Precisión
\\
\\
P(Sano|Negativo)&=&\frac{TN}{PN}&=&\frac{TN}{FN+TN}&=&Negative \; Predictive \; Value \; (NPV)&&
\\
P(Enfermo|Negativo)&=&\frac{FP}{PN}&=&\frac{FP}{FN+TN}&=&False \; Omission \; Rate \; (FOR)&=&1-NPV
\\
\end{array}
$$
$$
\begin{array}
\\
P(Positivo|Enfermo)&=&\frac{TP}{E}&=&\frac{TP}{TP+FN}&=&True \; Positive \; Rate (TPR) &=&Sensibilidad
\\
P(Negativo|Enfermo)&=&\frac{FN}{E}&=&\frac{FN}{TP+FN}&=&False \; Negative \; Rate \; (FNR)&=&1-Sensibilidad
\\
\\
P(Negativo|Sano)&=&\frac{TN}{S}&=&\frac{TN}{FP+TN}&=&True \; Negative \; Rate (TNR) &=&Especificidad
\\
P(Positivo|Sano)&=&\frac{FP}{S}&=&\frac{FP}{FP+TN}&=&False \; Positive \; Rate \; (FPR)&=&1-Especificidad
\\
\end{array}
$$
Predicción | |||||
---|---|---|---|---|---|
Positivo (PP) | Negativo (PN) | Métricas | |||
Realidad | Enfermo (E) | TP | FN | $P(Positivo|Enfermo)=\frac{TP}{E}$ | $P(Negativo|Enfermo)=\frac{FN}{E}$ |
Sano (S) | FP | TN | $P(Positivo|Sano)=\frac{FP}{S}$ | $P(Negativo|Sano)=\frac{TN}{S}$ | |
Métricas | $P(Enfermo|Positivo)=\frac{TP}{PP}$ | $P(Enfermo|Negativo)=\frac{FN}{PN}$ | |||
$P(Sano|Positivo)=\frac{FP}{PP}$ | $P(Sano|Negativo)=\frac{TN}{PN}$ |
Predicción | |||||
---|---|---|---|---|---|
Positivo (PP) | Negativo (PN) | Métricas | |||
Realidad | Enfermo (E) | TP | FN | $TPR=\frac{TP}{E}$ | $FNR=\frac{FN}{E}$ |
Sano (S) | FP | TN | $FPR=\frac{FP}{S}$ | $TNR=\frac{TN}{S}$ | |
Métricas | $PPV=\frac{TP}{PP}$ | $FOR=\frac{FN}{PN}$ | |||
$FDR=\frac{FP}{PP}$ | $NPV=\frac{TN}{PN}$ |
Predicción | |||||
---|---|---|---|---|---|
Positivo (PP) | Negativo (PN) | Métricas | |||
Realidad | Enfermo (E) | TP | FN | $Sensibilidad=\frac{TP}{E}$ | $FNR=\frac{FN}{E}$ |
Sano (S) | FP | TN | $FPR=\frac{FP}{S}$ | $Especificidad=\frac{TN}{S}$ | |
Métricas | $Precisión=\frac{TP}{PP}$ | $FOR=\frac{FN}{PN}$ | |||
$FDR=\frac{FP}{PP}$ | $NPV=\frac{TN}{PN}$ |
Volvamos ahora a recapacitar otra vez sobre el significado de las métricas. En un test perfecto realmente lo que nos interesa es:
A esas 2 métricas se les llama:
Se llaman así porque realmente son las 2 métricas que predicen si estás enfermo o sano cuando el test da positivo o negativo respectivamente. Y a la primera de ellas se le llama también precisión
El problema de calcular la precisión y el VPN es que sus valores dependen de la cantidad de enfermos y de sanos que tengamos al entrenar nuestra red. Por lo tanto del valor de E y S. Es decir que dependen de lo balanceados que tengamos nuestras clases.
Para calcular como de balanceadas están las clases se usa la $Prevalencia \; o \; P(Enfermo)$ , y es un dato muy importante que se calcula de la siguiente forma:
$$ Prevalencia=P(Enfermo)=\frac{TP+FN}{TP+FN+FP+TN}=\frac{E}{E+S} $$
Además están otras probabilidades que son:
$$ \begin{array} \\ P(Enfermo)&=&\frac{TP+FN}{TP+FN+FP+TN}&=&\frac{E}{E+S}&=&Prevalencia \\ P(Sano)&=&\frac{FP+TN}{TP+FN+FP+TN}&=&\frac{S}{E+S}&=&1-Prevalencia \\ P(Positivo)&=&\frac{TP+FP}{TP+FN+FP+TN}&=&\frac{PP}{PP+PN} \\ P(Negativo)&=&\frac{FN+TN}{TP+FN+FP+TN}&=&\frac{PN}{PP+PN}&=&1-P(Positivo) \end{array} $$
Recordar que: $$ E+S=PP+PN=Total $$
En la siguiente imagen vamos a obtener las métricas y vamos a ver como varían las métricas si aumenta o disminuye el número de positivos. Es decir vamos a ver como dependen la precisión y el VPN según la prevalencia.
Vemos que si aumentamos el número de positivos (por lo tanto aumentando la prevalencia), se modifican las métricas de Precisión (VPP) y VPN de la siguiente forma:
En la gráfica se puede ver como varían el VPP y el VPN según la prevalencia. Y la línea roja es con la prevalencia de los datos.
Por lo tanto se podría hacer trampa y sin modificar el modelo pero variando la prevalencia de los datos de validación, conseguir mejorar el VPP o el PPN.
¿Cual es entonces la solución? Pues usar métricas que no dependan de la prevalencia. Y esas métricas son la $sensibilidad$ y la $especificidad$ que habíamos descartado. ¿Y para que las queremos? Pues esas 2 métricas nos dicen lo bueno que es nuestro modelo cuando lo estamos desarrollando ya que nos decían cuanto acertaban o fallaban cuando sabíamos lo que debía dar y son métricas independientes de la prevalencia de nuestros datos. Podemos ver que esas métricas no han variado aunque se haya modificado la prevalencia.
Vale, pero nosotros lo que queremos es saber la precisión y la VPN. Pues resulta que el teorema de bayes es una fórmula matemática que nos calcula la precisión y la VPN en base a la sensibilidad y la especificidad y además según la prevalencia. 😍😍😍😍😍😍
$$ P(Enfermo|Positivo)=\frac{P(Positivo|Enfermo)*P(Enfermo)}{P(Positivo|Enfermo)*P(Enfermo)+P(Positivo|Sano)*P(Sano)} $$
$$ P(Sano|Negativo)=\frac{P(Negativo|Sano)*P(Sano)}{P(Negativo|Sano)*P(Sano)+P(Negativo|Enfermo)*P(Enfermo)} $$
y usando los nombres normales de las métricas las fórmulas quedarían así:
$$ Precisión=VPP=\frac{Sensibilidad*Prevalencia}{Sensibilidad*Prevalencia+(1-Especificidad)*(1-Prevalencia)} $$
$$ VPN=\frac{Especificidad*(1-Prevalencia)}{Especificidad*(1-Prevalencia)+(1-sensibilidad)*Prevalencia} $$
Todo ellos nos lleva a que al desarrollar nuestra red neuronal solo nos interesan que los valores de $Sensibilidad$ y de $Especificidad$ sean lo más altos posibles. Y cuando vayamos a predecir, nos tendrán que indicar el valor de la prevalencia y en ese caso podremos calcular si ha salid positivo el valor de $Precisión \; (VPP)$ y si ha salido negativo calcularemos el valor de $VPN$.
Por ello en los prospectos de los test de covid, los valores que siempre se calculaban son el de $Sensibilidad$ y de $Especificidad$: sars-cov-2_rapid_antigen_test_es.pdf
En los siguientes 2 artículos vemos investigaciones para calcular la prevalencia del COVID según distintas circunstancias:
Ahora ya sabemos que VPP y VPN son las métricas que nos interesan realmente y que sus valores deben ser lo más cercanas a 1. Pero también sabemos que esas métricas dependen de la Prevalencia (que no depende de lo bueno que sea nuestro modelo ) y de las métricas de Sensibilidad y Especificidad (Que si que dependen de lo bueno que sea nuestro modelo). Así que para obtener los mejores valores del VPP y VPN tenemos que conseguir en nuestro modelo consigamos los mejores valores de Sensibilidad y Especificidad.
Como ya hemos visto hay las siguientes relaciones entre métricas:
$$
FNR=1-Sensibilidad
$$
$$
FPR=1-Especificidad
$$
Además de
$$
FDR=1-VPP
$$
$$
FOR=1-VPN
$$
Como esas métricas no son independientes de las anteriores, volvamos ahora a poner la tabla de confusión únicamente con las métricas que nos interesan y además los valores ideales que nos interesarían.
Predicción | |||||
---|---|---|---|---|---|
Positivo (PP) | Negativo (PN) | Métricas | |||
Realidad | Enfermo (E) | TP | FN | $Sensibilidad=1$ | |
Sano (S) | FP | TN | $Especificidad=1$ | ||
Métricas | $VPP=1$ | ||||
$VPN=1$ |
Y por lo tanto el resto de las métricas nos interesarían que fueran 0 pero al depender de la que hemos mostrado , ni las mediremos.
Más información en:
Veamos como calcular en Keras las métricas que necesitamos
La sensibilidad en inglés es Sensibility pero también se llama Recall que es como se usa en Keras.
Su uso en Keras es
metrics=[tf.keras.metrics.Recall()] metrics=["Recall"]
y usarla como
history.history['recall'] history.history['val_recall']
Ejemplo:
y_true = np.array([1,1,1,1,1]) y_pred = np.array([0.9, 0.2, 0.3, 0.8,0.6]) metric = tf.keras.metrics.Recall() metric(y_true, y_pred).numpy()
0.6
Más información:
Inexplicablemente esta métrica no existe en keras. Pero la podemos definir con el siguiente código:
def specificity(y_true, y_score): threshold=0.5 y_pred = tf.cast(tf.greater(y_score, threshold), tf.float32) true_negatives = tf.logical_and(tf.equal(y_true, 0), tf.equal(y_pred, 0)) num_true_negatives=tf.reduce_sum(tf.cast(true_negatives, tf.float32)) negatives =tf.equal(y_true, 0) num_negatives= tf.reduce_sum(tf.cast(negatives, tf.float32)) specificity = num_true_negatives / (num_negatives + tf.keras.backend.epsilon()) return specificity
Su uso en Keras es
metrics=[specificity]
y usarla como
history.history['specificity'] history.history['val_specificity']
Ejemplo:
y_true = np.array([0,0,0,0,0]) y_pred = np.array([0.9, 0.7, 0.3, 0.3,0.6]) specificity(y_true, y_pred).numpy()
0.4
Accuracy nos indica la proporción de aciertos que ha tenido. Es decir el porcentaje (en tanto por uno) de verdaderos positivos y verdaderos negativos
Su uso en keras es:
metrics=[tf.keras.metrics.CategoricalAccuracy()] metrics=["categorical_accuracy"]
y usarla como
history.history['categorical_accuracy'] history.history['val_categorical_accuracy']
Mas información:
matplotlib
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): success_color=matplotlib.colors.to_rgb('#9EE548') failure_color=matplotlib.colors.to_rgb("#C32240") blanco_color=matplotlib.colors.to_rgb("#FFFFFF") if ((vpp is not None) | (vpn is not None) | (sensibilidad is not None) | (especificidad is not None) | (prevalencia is not None) | (f1_score is not None) | (mcc is not None) | (auc is not None) ): show_metrics=True else: show_metrics=False if show_metrics==False: axes.imshow([[success_color,failure_color],[failure_color,success_color]]) else: axes.imshow([[success_color,failure_color,blanco_color],[failure_color,success_color,blanco_color],[blanco_color,blanco_color,blanco_color]]) labels = ['Positivo','Negativo'] xaxis = np.arange(len(labels)) axes.set_xticks(xaxis) axes.set_yticks(xaxis) axes.set_xticklabels(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, 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, 1, str(TN)+" TN",ha="center", va="center", color="#0A2102",fontsize=fontsize) axes.xaxis.tick_top() axes.set_xlabel('Predicción', fontsize=fontsize, color="#003B80") axes.xaxis.set_label_position('top') axes.set_ylabel('Realidad', fontsize=fontsize, color="#003B80") if show_metrics==True: if (vpp is not None): axes.text(0, 2, f"Precision\n{vpp:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4) if (vpn is not None): axes.text(1, 2, f"VPN\n{vpn:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4) if (sensibilidad is not None): axes.text(2, 0, f"Sensibilidad\n{sensibilidad:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4) if (especificidad is not None): axes.text(2, 1, f"Especificidad\n{especificidad:.2f}",ha="center", va="center", color="#0A2102",fontsize=fontsize-4) metricas_generales="" if (prevalencia is not None): metricas_generales=metricas_generales+f"Prevalencia\n{prevalencia:.2f}\n" if (f1_score is not None): metricas_generales=metricas_generales+f"F1-score\n{f1_score:.2f}\n" if (mcc is not None): metricas_generales=metricas_generales+f"MCC\n{mcc:.2f}\n" if (auc is not None): metricas_generales=metricas_generales+f"AUC\n{auc:.2f}" axes.text(2, 2, metricas_generales,ha="center", va="center", color="#0A2102",fontsize=fontsize-4)
Si una red neuronal para detectar si una radiografía es de un tórax ha predicho lo siguiente:
Indica el nº de:
Dibuja la matriz de confusión
Seguimos con la red neuronal que predice si una radiografía es de tórax.
Si para 10 imágenes ha sacado los siguientes resultados:
y_score=np.array([0.27, 0.45, 0.76, 0.55, 0.28, 0.04, 0.34,0.4, 0.66, 0.88, 0.94,0.47,0.2])
Indica para cada valor predicho , si ha predicho que era una imagen de tórax o no.
Seguimos con la red neuronal que predice si una radiografía es de tórax.
Si para 10 imágenes ha sacado los siguientes resultados:
y_score=np.array([0.27, 0.45, 0.76, 0.55, 0.28, 0.04, 0.34,0.4, 0.66, 0.88, 0.94,0.47,0.2])
Pero los valores verdaderos son los siguientes:
y_true=np.array([1,0,1,0,0,0,1,0,1,1,1,1,0])
Indica el nº de:
Dibuja la matriz de confusión
Siguiendo con los datos anteriores y suponiendo que el umbral es 0.5:
y_true=np.array([1,0,1,0,0,0,1,0,1,1,1,1,0]) y_score=np.array([0.27, 0.45, 0.76, 0.55, 0.28, 0.04, 0.34,0.4, 0.66, 0.88, 0.94,0.47,0.2])
Calcula directamente las siguientes métricas:
Calcula ahora los valores de:
pero usando el teorema de bayes en base a los valores de:
Muestra ahora una gráfica con matplolib en la que se vea como evolucionan los valores de VPP y VPN según la prevalencia.
Esa misma gráfica se puede mostrar en Bayesian Clinical Diagnostic Model
Crea una red neuronal con los datos de bread cancer con las siguientes características:
[30,64,32,16,8,1]
ELU
20
Adam
con tasa de aprendizaje de 0,0001
Muestra las siguientes métricas durante el entrenamiento (para cada una de las épocas):
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:
x_test
y_test
La variable y_test
es lo que llamamos y_true
mientras que con x_test
obtendremos y_score
.
Para ello sigue los siguientes pasos:
get_matriz_confusion(y_true,y_score,threshold)
que retorne TP
,TN
, FP
y FN
y_score
usando el método predict
del modelo y usando la variable x_test
y_true
sea igual a y_test
get_matriz_confusion
Crea una función llamada get_metrics(TP,TN,FP,FN,Prevalencia=None)
que retorne las siguientes métricas:
Para calcular VPP y VPN se debe usar la prevalencia. Si no se pasa el valor de prevalencia ( Es decir 'prevalencia==None', se usará el de los datos y sino se usará la prevalencia que se pase como argumento.
Usando los valores de TP
,TN
, FP
y FN
del ejercicio anterior, muestra las métricas que retorna get_metrics
Muestra todo en la matriz de confusión.
Guarda el modelo a disco
En un nuevo jupyter notebook, carga el modelo y con los datos de test , vuelve a mostrar la matriz de confusión con todas las métricas.
Muestra ahora 1 gráfica, en la que se mostrará:
¿Que valor de umbral dejarías?
Muestra una gráfica similar a las anteriores pero ahora sea la suma los valores de sensibilidad y la especificidad menos 1.
A la suma de los 2 valores para obtener el máximo pero restando 1 se le llama $Informedness$
$$ Informedness=Sensibilidad+Especificidad-1 $$
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
Indica en los siguientes problemas si subirías o bajarías el umbral
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.
Para elegir debes mostrar gráficas , una al lado de la otra para comparar lo siguiente:
¿Con que red te quedarías?
Además para el nivel de threshold de la red que ha "ganado", imprime la sensibilidad y la especificidad
Con el modelo elegido, guarda el modelo a disco
Con modelo que has elegido, cárgalo desde disco en otro Jupyter notebook y realiza inferencia de 10 pacientes.
Para cada paciente: