Scikit-learn: sklearn.metrics.classification_report est incorrect?

Créé le 1 avr. 2020  ·  3Commentaires  ·  Source: scikit-learn/scikit-learn

Décrivez le bogue

sklearn.metrics.classification peut signaler des valeurs inversées pour la précision et le rappel?

Étapes / code à reproduire

from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.neighbors import KNeighborsClassifier
from sklearn import datasets

def calc_precision_recall(conf_matrix, class_labels):

    # for each class
    for i in range(len(class_labels)):

        # calculate true positives
        true_positives =(conf_matrix[i, i])

        # false positives
        false_positives = (conf_matrix[i, :].sum() - true_positives)

        # false negatives
        false_negatives = 0
        for j in range(len(class_labels)):
            false_negatives += conf_matrix[j, i]
        false_negatives -= true_positives

        # and finally true negatives
        true_negatives= (conf_matrix.sum() - false_positives - false_negatives - true_positives)

        # print calculated values
        print(
            "Class label", class_labels[i],
            "T_positive", true_positives,
            "F_positive", false_positives,
            "T_negative", true_negatives,
            "F_negative", false_negatives,
            "\nSensitivity/recall", true_positives / (true_positives + false_negatives),
            "Specificity", true_negatives / (true_negatives + false_positives),
            "Precision", true_positives/(true_positives+false_positives), "\n"
        )

    return

# import some data to play with
iris = datasets.load_iris()
X = iris.data[:, 0:3]  # we only take the first two features.
y = iris.target

# Random_state parameter is just a random seed that can be used to reproduce these specific results.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=27)

# Instantiate a K-Nearest Neighbors Classifier:
KNN_model = KNeighborsClassifier(n_neighbors=2)

# Fit the classifiers:
KNN_model.fit(X_train, y_train)

# Predict and store the prediction:
KNN_prediction = KNN_model.predict(X_test)

# Generate the confusion matrix
conf_matrix = confusion_matrix(KNN_prediction, y_test)

# Print the classification report
print(classification_report(KNN_prediction, y_test))

# Dummy class labels for the three iris classes
class_labels = [0,1,2]

# Own function to calculate precision and recall from the confusion matrix
calc_precision_recall(conf_matrix, class_labels)

Résultats attendus

Ma fonction renvoie les éléments suivants pour chaque classe:

Libellé de classe 0 T_positive 7 F_positive 0 T_negative 23 F_negative 0
Sensibilité / rappel 1.0 Spécificité 1.0 Précision 1.0

Étiquette de classe 1 T_positive 11 F_positive 1 T_negative 18 F_negative 0
Sensibilité / rappel 1,0 Spécificité 0,9473684210526315 Précision 0,9166666666666666

Étiquette de classe 2 T_positive 11 F_positive 0 T_negative 18 F_negative 1
Sensibilité / rappel 0,9166666666666666 Spécificité 1,0 Précision 1,0

          precision    recall  

       0       1.00      1.00      
       1       0.92      1.00    
       2       1.00      0.92

Ma fonction suppose que la matrice de confusion est structurée avec des valeurs réelles sur l'axe x supérieur et des valeurs prédites sur l'axe y gauche. Il s'agit de la même structure que celle utilisée dans Wikipédia et celle référencée dans la documentation pour la fonction de matrice de confusion.

Résultats actuels

En revanche, ce sont les résultats rapportés par sklearn.metrics import classification_report

           precision    recall  f1-score   support

       0       1.00      1.00      1.00         7
       1       1.00      0.92      0.96        12
       2       0.92      1.00      0.96        11

Versions

Système:
python: 3.8.1 (par défaut, 8 janvier 2020, 22:29:32) [GCC 7.3.0]
exécutable: / home / will / anaconda3 / envs / ElStatLearn / bin / python
machine: Linux-4.15.0-91-generic-x86_64-avec-glibc2.10

Dépendances Python:
pip: 20.0.2
setuptools: 38.2.5
sklearn: 0.22.1
numpy: 1.18.1
scipy: 1.4.1
Cython: aucun
pandas: 1.0.1
matplotlib: 3.1.3
joblib: 0.14.1

Construit avec OpenMP: True

triage metrics

Commentaire le plus utile

Je pense que y_test devrait venir en premier dans print(classification_report(KNN_prediction, y_test)) .

Donc: print(classification_report(y_test, KNN_prediction)) .

La fonction sklearn.metrics.classification_report(y_true, y_pred, labels=None, target_names=None, sample_weight=None, digits=2, output_dict=False, zero_division='warn') a y_true comme premier argument. Cela inverserait la précision et le rappel.

Voir classification_report .

Edit: votre matrice de confusion est également à l'envers, mais cela fonctionne parce que la matrice de confusion de sklearn est à l'envers de wikipedia.

>>> from sklearn.metrics import confusion_matrix
>>> y_true = [2, 0, 2, 2, 0, 1]
>>> y_pred = [0, 0, 2, 2, 0, 2]
>>> confusion_matrix(y_true, y_pred)
array([[2, 0, 0],
       [0, 0, 1],
       [1, 0, 2]])

Vous pouvez voir qu'il y a 1 observation dans la ligne 1 et 0 dans la colonne 1, donc les lignes sont la vérité terrain et les colonnes sont des prédictions. Vous pouvez donc utiliser la notation C[i, j] affichée à confusion_matrix

Tous les 3 commentaires

Je pense que y_test devrait venir en premier dans print(classification_report(KNN_prediction, y_test)) .

Donc: print(classification_report(y_test, KNN_prediction)) .

La fonction sklearn.metrics.classification_report(y_true, y_pred, labels=None, target_names=None, sample_weight=None, digits=2, output_dict=False, zero_division='warn') a y_true comme premier argument. Cela inverserait la précision et le rappel.

Voir classification_report .

Edit: votre matrice de confusion est également à l'envers, mais cela fonctionne parce que la matrice de confusion de sklearn est à l'envers de wikipedia.

>>> from sklearn.metrics import confusion_matrix
>>> y_true = [2, 0, 2, 2, 0, 1]
>>> y_pred = [0, 0, 2, 2, 0, 2]
>>> confusion_matrix(y_true, y_pred)
array([[2, 0, 0],
       [0, 0, 1],
       [1, 0, 2]])

Vous pouvez voir qu'il y a 1 observation dans la ligne 1 et 0 dans la colonne 1, donc les lignes sont la vérité terrain et les colonnes sont des prédictions. Vous pouvez donc utiliser la notation C[i, j] affichée à confusion_matrix

Merci beaucoup d'avoir clarifié cela - la référence wikipedia m'a confus!

Pas de problème, cela devrait probablement amener Wikipédia à changer son exemple en orientation sklearn.

Cette page vous a été utile?
0 / 5 - 0 notes