python - recall - sklearn metrics
Scikit-learn: Cómo obtener True Positive, True Negative, False Positive y False Negative (10)
Soy nuevo en aprendizaje automático y en scikit-learn.
Mi problema:
(Por favor, corrija cualquier tipo de idea errónea)
Tengo un conjunto de datos que es un BIG JSON, lo recupero y lo trainList
en una variable trainList
.
Lo pre-proceso para poder trabajar con él.
Una vez hecho esto, empiezo la clasificación:
- Utilizo el método de validación cruzada kfold para obtener la precisión media y entreno a un clasificador.
- Realizo las predicciones y obtengo la matriz de precisión y confusión de ese pliegue.
- Después de esto, me gustaría obtener los valores de Verdadero Positivo (TP), Verdadero Negativo (TN), Falso Positivo (FP) y Falso Negativo (FN). Usaría estos parámetros para obtener la Sensibilidad y la especificidad, y los utilizaría con el total de los TP a un HTML para mostrar un gráfico con los TP de cada etiqueta.
Código:
Las variables que tengo por el momento:
trainList #It is a list with all the data of my dataset in JSON form
labelList #It is a list with all the labels of my data
La mayor parte del método:
#I transform the data from JSON form to a numerical one
X=vec.fit_transform(trainList)
#I scale the matrix (don''t know why but without it, it makes an error)
X=preprocessing.scale(X.toarray())
#I generate a KFold in order to make cross validation
kf = KFold(len(X), n_folds=10, indices=True, shuffle=True, random_state=1)
#I start the cross validation
for train_indices, test_indices in kf:
X_train=[X[ii] for ii in train_indices]
X_test=[X[ii] for ii in test_indices]
y_train=[listaLabels[ii] for ii in train_indices]
y_test=[listaLabels[ii] for ii in test_indices]
#I train the classifier
trained=qda.fit(X_train,y_train)
#I make the predictions
predicted=qda.predict(X_test)
#I obtain the accuracy of this fold
ac=accuracy_score(predicted,y_test)
#I obtain the confusion matrix
cm=confusion_matrix(y_test, predicted)
#I should calculate the TP,TN, FP and FN
#I don''t know how to continue
Aquí hay una solución para el código de buggy de invoketheshell (que actualmente aparece como la respuesta aceptada):
def performance_measure(y_actual, y_hat):
TP = 0
FP = 0
TN = 0
FN = 0
for i in range(len(y_hat)):
if y_actual[i] == y_hat[i]==1:
TP += 1
if y_hat[i] == 1 and y_actual[i] == 0:
FP += 1
if y_hat[i] == y_actual[i] == 0:
TN +=1
if y_hat[i] == 0 and y_actual[i] == 1:
FN +=1
return(TP, FP, TN, FN)
Creo que ambas respuestas no son del todo correctas. Por ejemplo, supongamos que tenemos las siguientes matrices;
y_actual = [1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0]
y_predic = [1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0]
Si calculamos los valores de FP, FN, TP y TN manualmente, deben ser los siguientes:
FP: 3 FN: 1 TP: 3 TN: 4
Sin embargo, si utilizamos la primera respuesta, los resultados se dan de la siguiente manera:
FP: 1 FN: 3 TP: 3 TN: 4
No son correctos, porque en la primera respuesta, Falso Positivo debe estar donde real es 0, pero el pronosticado es 1, no lo contrario. También es igual para Falso Negativo.
Y, si usamos la segunda respuesta, los resultados se computan de la siguiente manera:
FP: 3 FN: 1 TP: 4 TN: 3
Los números True Positive y True Negative no son correctos, deben ser opuestos.
¿Estoy correcto con mis cálculos? Por favor avíseme si me falta algo.
En la biblioteca de "métricas" de scikit-learn hay un método de confusión_matriz que le da el resultado deseado.
Puede utilizar cualquier clasificador que desee. Aquí utilicé a los vecinos como ejemplo.
from sklearn import metrics, neighbors
clf = neighbors.KNeighborsClassifier()
X_test = ...
y_test = ...
expected = y_test
predicted = clf.predict(X_test)
conf_matrix = metrics.confusion_matrix(expected, predicted)
>>> print conf_matrix
>>> [[1403 87]
[ 56 3159]]
Los documentos: http://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html#sklearn.metrics.confusion_matrix
Escribí una versión que funciona usando solo numpy. Espero que te ayude.
import numpy as np
def perf_metrics_2X2(yobs, yhat):
"""
Returns the specificity, sensitivity, positive predictive value, and
negative predictive value
of a 2X2 table.
where:
0 = negative case
1 = positive case
Parameters
----------
yobs : array of positive and negative ``observed`` cases
yhat : array of positive and negative ``predicted`` cases
Returns
-------
sensitivity = TP / (TP+FN)
specificity = TN / (TN+FP)
pos_pred_val = TP/ (TP+FP)
neg_pred_val = TN/ (TN+FN)
Author: Julio Cardenas-Rodriguez
"""
TP = np.sum( yobs[yobs==1] == yhat[yobs==1] )
TN = np.sum( yobs[yobs==0] == yhat[yobs==0] )
FP = np.sum( yobs[yobs==1] == yhat[yobs==0] )
FN = np.sum( yobs[yobs==0] == yhat[yobs==1] )
sensitivity = TP / (TP+FN)
specificity = TN / (TN+FP)
pos_pred_val = TP/ (TP+FP)
neg_pred_val = TN/ (TN+FN)
return sensitivity, specificity, pos_pred_val, neg_pred_val
Para el caso de clases múltiples, todo lo que necesita puede encontrarse en la matriz de confusión. Por ejemplo, si su matriz de confusión se ve así:
Entonces, lo que estás buscando, por clase, se puede encontrar así:
Usando pandas / numpy, puedes hacer esto para todas las clases a la vez así:
FP = confusion_matrix.sum(axis=0) - np.diag(confusion_matrix)
FN = confusion_matrix.sum(axis=1) - np.diag(confusion_matrix)
TP = np.diag(confusion_matrix)
TN = confusion_matrix.values.sum() - (FP + FN + TP)
# Sensitivity, hit rate, recall, or true positive rate
TPR = TP/(TP+FN)
# Specificity or true negative rate
TNR = TN/(TN+FP)
# Precision or positive predictive value
PPV = TP/(TP+FP)
# Negative predictive value
NPV = TN/(TN+FN)
# Fall out or false positive rate
FPR = FP/(FP+TN)
# False negative rate
FNR = FN/(TP+FN)
# False discovery rate
FDR = FP/(TP+FP)
# Overall accuracy
ACC = (TP+TN)/(TP+FP+FN+TN)
Puede obtener todos los parámetros de la matriz de confusión. La estructura de la matriz de confusión (que es la matriz 2X2) es la siguiente
TP|FP
FN|TN
Asi que
TP = cm[0][0]
FP = cm[0][1]
FN = cm[1][0]
TN = cm[1][1]
Más detalles en https://en.wikipedia.org/wiki/Confusion_matrix
Según la documentación de scikit-learn,
Por definición, una matriz de confusión C es tal que C [i, j] es igual al número de observaciones que se sabe que están en el grupo i pero que se predice que están en el grupo j.
Por lo tanto, en la clasificación binaria, el recuento de verdaderos negativos es C [0,0], los falsos negativos es C [1,0], los verdaderos positivos son C [1,1] y los falsos positivos son C [0,1].
CM = confusion_matrix(y_true, y_pred)
TN = CM[0][0]
FN = CM[1][0]
TP = CM[1][1]
FP = CM[0][1]
Si tiene dos listas que tienen los valores predichos y reales; Como parece que lo hace, puede pasarlos a una función que calculará TP, FP, TN, FN con algo como esto:
def perf_measure(y_actual, y_hat):
TP = 0
FP = 0
TN = 0
FN = 0
for i in range(len(y_hat)):
if y_actual[i]==y_hat[i]==1:
TP += 1
if y_hat[i]==1 and y_actual[i]!=y_hat[i]:
FP += 1
if y_actual[i]==y_hat[i]==0:
TN += 1
if y_hat[i]==0 and y_actual[i]!=y_hat[i]:
FN += 1
return(TP, FP, TN, FN)
Desde aquí, creo que podrá calcular las tasas de interés para usted y otras medidas de rendimiento, como la especificidad y la sensibilidad.
Si tiene más de una clase en su clasificador, puede usar pandas-ml en esa parte. La Matriz de Confusión de pandas-ml da información más detallada. Mira esto
puede probar sklearn.metrics.classification_report
como se muestra a continuación:
import sklearn
y_true = [1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0]
y_pred = [1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0]
print sklearn.metrics.classification_report(y_true, y_pred)
salida:
precision recall f1-score support
0 0.80 0.57 0.67 7
1 0.50 0.75 0.60 4
avg / total 0.69 0.64 0.64 11