web-dev-qa-db-fra.com

Comment calculer la précision, le rappel, l'exactitude et le score f1 pour le cas multiclass avec scikit learn?

Je travaille dans un problème d'analyse de sentiment les données ressemblent à ceci:

label instances
    5    1190
    4     838
    3     239
    1     204
    2     127

Donc, mes données sont déséquilibrées depuis 1190 instances sont étiquetés avec 5. Pour la classification, j'utilise scikit SVC . Le problème est que je ne sais pas comment équilibrer correctement mes données afin de calculer avec précision la précision, le rappel, l'exactitude et le score f1 pour le cas multiclass. J'ai donc essayé les approches suivantes:

Première:

    wclf = SVC(kernel='linear', C= 1, class_weight={1: 10})
    wclf.fit(X, y)
    weighted_prediction = wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, weighted_prediction)
print 'F1 score:', f1_score(y_test, weighted_prediction,average='weighted')
print 'Recall:', recall_score(y_test, weighted_prediction,
                              average='weighted')
print 'Precision:', precision_score(y_test, weighted_prediction,
                                    average='weighted')
print '\n clasification report:\n', classification_report(y_test, weighted_prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, weighted_prediction)

Seconde:

auto_wclf = SVC(kernel='linear', C= 1, class_weight='auto')
auto_wclf.fit(X, y)
auto_weighted_prediction = auto_wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, auto_weighted_prediction)

print 'F1 score:', f1_score(y_test, auto_weighted_prediction,
                            average='weighted')

print 'Recall:', recall_score(y_test, auto_weighted_prediction,
                              average='weighted')

print 'Precision:', precision_score(y_test, auto_weighted_prediction,
                                    average='weighted')

print '\n clasification report:\n', classification_report(y_test,auto_weighted_prediction)

print '\n confussion matrix:\n',confusion_matrix(y_test, auto_weighted_prediction)

Troisième:

clf = SVC(kernel='linear', C= 1)
clf.fit(X, y)
prediction = clf.predict(X_test)


from sklearn.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, \
    accuracy_score, f1_score

print 'Accuracy:', accuracy_score(y_test, prediction)
print 'F1 score:', f1_score(y_test, prediction)
print 'Recall:', recall_score(y_test, prediction)
print 'Precision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test,prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)


F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1082: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
 0.930416613529

Cependant, je reçois des avertissements comme celui-ci:

/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172:
DeprecationWarning: The default `weighted` averaging is deprecated,
and from version 0.18, use of precision, recall or F-score with 
multiclass or multilabel data or pos_label=None will result in an 
exception. Please set an explicit value for `average`, one of (None, 
'micro', 'macro', 'weighted', 'samples'). In cross validation use, for 
instance, scoring="f1_weighted" instead of scoring="f1"

Comment puis-je gérer correctement mes données non équilibrées afin de calculer correctement les métriques du classifieur?

97
new_with_python

Je pense qu'il y a beaucoup de confusion quant aux poids utilisés pour quoi. Je ne suis pas sûr de savoir exactement ce qui vous dérange, je vais donc aborder différents sujets avec moi;).

Poids de classe

Les poids du paramètre class_weight sont utilisés pour former le classifieur. Ils ne sont utilisés dans le calcul d'aucune des mesures que vous utilisez: avec des poids de classe différents, les nombres seront différents simplement parce que le classificateur est différent.

Fondamentalement, dans chaque classifieur scikit-learn, les poids de classe sont utilisés pour indiquer à votre modèle l’importance d’une classe. Cela signifie que pendant la formation, le classificateur fera des efforts supplémentaires pour classer correctement les classes avec des poids élevés.
La façon dont ils le font est spécifique à l’algorithme. Si vous souhaitez des détails sur son fonctionnement pour SVC et que la doc n'a aucun sens, n'hésitez pas à le mentionner.

Les métriques

Une fois que vous avez un classificateur, vous voulez savoir comment il fonctionne. Vous pouvez utiliser ici les mesures que vous avez mentionnées: accuracy, recall_score, f1_score...

Habituellement, lorsque la répartition des classes est déséquilibrée, la précision est considérée comme un mauvais choix car elle donne des scores élevés aux modèles prédisant simplement la classe la plus fréquente.

Je ne détaillerai pas toutes ces métriques, mais notons que, à l'exception de accuracy, elles s'appliquent naturellement au niveau de la classe: comme vous pouvez le voir dans cette print d'un rapport de classification, elles sont définies pour chaque classe. Ils s'appuient sur des concepts tels que true positives ou false negative qui nécessitent de définir quelle classe est la classe positive .

             precision    recall  f1-score   support

          0       0.65      1.00      0.79        17
          1       0.57      0.75      0.65        16
          2       0.33      0.06      0.10        17
avg / total       0.52      0.60      0.51        50

L'avertissement

F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The 
default `weighted` averaging is deprecated, and from version 0.18, 
use of precision, recall or F-score with multiclass or multilabel data  
or pos_label=None will result in an exception. Please set an explicit 
value for `average`, one of (None, 'micro', 'macro', 'weighted', 
'samples'). In cross validation use, for instance, 
scoring="f1_weighted" instead of scoring="f1".

Vous recevez cet avertissement parce que vous utilisez le score-f1, le rappel et la précision sans définir comment ils doivent être calculés! La question pourrait être reformulée: à partir du rapport de classification ci-dessus, comment affichez-vous le nombre global n pour le score f1? Vous pourriez:

  1. Prenez la moyenne du score f1 pour chaque classe: c'est le résultat avg / total ci-dessus. C'est aussi appelé macro moyennage.
  2. Calculez le score f1 en utilisant le nombre global de vrais/faux négatifs, etc. (vous additionnez le nombre de vrais/faux négatifs pour chaque classe). Aka micro moyennage.
  3. Calcule une moyenne pondérée du score f1. L'utilisation de 'weighted' dans scikit-learn permettra de pondérer le score f1 par le support de la classe: plus une classe a d'éléments, plus le score f1 de cette classe est important pour le calcul.

Ce sont 3 des options de scikit-learn, l'avertissement est là pour vous dire devez en choisir un. Vous devez donc spécifier un argument average pour la méthode score.

Le choix que vous choisissez dépend de la manière dont vous souhaitez mesurer les performances du classificateur: par exemple, la moyenne macro-économique ne prend pas en compte le déséquilibre de classe et le score f1 de la classe 1 sera tout aussi important que le score f1 de la classe 5. Si vous utilisez une moyenne pondérée, vous aurez plus d’importance pour la classe 5.

La spécification complète de l'argument dans ces métriques n'est pas très claire dans scikit-learn pour le moment, elle s'améliorera dans la version 0.18 selon la documentation. Ils suppriment un comportement standard non évident et émettent des avertissements afin que les développeurs le remarquent.

Partitions informatiques

La dernière chose que je veux mentionner (n'hésitez pas à l'ignorer si vous en êtes conscient), c'est que les scores ne sont significatifs que s'ils sont calculés sur des données que le classificateur n'a jamais vues. Ceci est extrêmement important, car tout résultat obtenu avec les données utilisées lors de l'ajustement du classifieur n'a aucune pertinence.

Voici un moyen de le faire en utilisant StratifiedShuffleSplit, qui vous donne une répartition aléatoire de vos données (après réarrangement) afin de préserver la distribution des étiquettes.

from sklearn.datasets import make_classification
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

# We use a utility to generate artificial classification data.
X, y = make_classification(n_samples=100, n_informative=10, n_classes=3)
sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
for train_idx, test_idx in sss:
    X_train, X_test, y_train, y_test = X[train_idx], X[test_idx], y[train_idx], y[test_idx]
    svc.fit(X_train, y_train)
    y_pred = svc.predict(X_test)
    print(f1_score(y_test, y_pred, average="macro"))
    print(precision_score(y_test, y_pred, average="macro"))
    print(recall_score(y_test, y_pred, average="macro"))    

J'espère que cela t'aides.

138
ldirer

Beaucoup de réponses très détaillées ici, mais je ne pense pas que vous répondiez aux bonnes questions. Si je comprends bien la question, il y a deux préoccupations:

  1. Comment marquer un problème multiclass?
  2. Comment gérer les données non équilibrées?

1.

Vous pouvez utiliser la plupart des fonctions d'évaluation dans scikit-learn avec le problème multiclass comme avec les problèmes de classe unique. Ex.:

from sklearn.metrics import precision_recall_fscore_support as score

predicted = [1,2,3,4,5,1,2,1,1,4,5] 
y_test = [1,2,3,4,5,1,2,1,1,4,1]

precision, recall, fscore, support = score(y_test, predicted)

print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(fscore))
print('support: {}'.format(support))

De cette façon, vous vous retrouvez avec des nombres tangibles et interprétables pour chacune des classes.

| Label | Precision | Recall | FScore | Support |
|-------|-----------|--------|--------|---------|
| 1     | 94%       | 83%    | 0.88   | 204     |
| 2     | 71%       | 50%    | 0.54   | 127     |
| ...   | ...       | ...    | ...    | ...     |
| 4     | 80%       | 98%    | 0.89   | 838     |
| 5     | 93%       | 81%    | 0.91   | 1190    |

Ensuite...

2.

... vous pouvez dire si le déséquilibre des données pose problème. Si les scores des classes moins représentées (classes 1 et 2) sont inférieurs à ceux des classes ayant plus d'échantillons d'apprentissage (classes 4 et 5), alors vous savez que les données non équilibrées constituent en fait un problème et vous pouvez agir en conséquence, décrit dans certaines des autres réponses de ce fil. Toutefois, si la même distribution de classes est présente dans les données que vous souhaitez prédire, vos données d’entraînement déséquilibrées sont un bon représentant des données et, par conséquent, le déséquilibre est une bonne chose.

63
wonderkid2

Question posée

Répondant à la question "quelle métrique devrait être utilisée pour la classification multi-classes avec des données déséquilibrées": mesure Macro-F1. Macro Precision et Macro Recall peuvent également être utilisés, mais ils ne sont pas aussi faciles à interpréter que pour la classification binaire, ils sont déjà intégrés à F-measure et les métriques en excès compliquent la comparaison des méthodes, le réglage des paramètres, etc.

Les micro-moyennes sont sensibles au déséquilibre des classes: si votre méthode, par exemple, fonctionne bien pour les étiquettes les plus courantes et dérange totalement les autres, les métriques micro-moyennées donnent de bons résultats.

La moyenne pondérée ne convient pas aux données déséquilibrées, car elle pondère en fonction du nombre d'étiquettes. En outre, il est trop difficilement interprétable et impopulaire: par exemple, il n’est pas fait mention d’une telle moyenne dans le texte très détaillé suivant enquête Je recommande vivement de regarder à travers:

Sokolova, Marina et Guy Lapalme. "Une analyse systématique des mesures de performance pour les tâches de classification." Traitement et gestion de l'information 45.4 (2009): 427-437.

Question spécifique à l'application

Cependant, pour revenir à votre tâche, je voudrais effectuer une recherche sur 2 sujets:

  1. mesures couramment utilisées pour votre tâche spécifique - cela permet (a) de comparer votre méthode avec d'autres et de comprendre si vous faites quelque chose de mal, et (b) de ne pas l'explorer vous-même et de réutiliser les résultats de quelqu'un d'autre;
  2. coût des différentes erreurs de vos méthodes - par exemple, le cas d'utilisation de votre application peut uniquement s'appuyer sur des réviseurs 4 et 5 étoiles - dans ce cas, une métrique correcte ne devrait compter que ces 2 étiquettes.

Mesures couramment utilisées. Comme je peux le déduire après avoir parcouru la littérature, il existe 2 mesures d'évaluation principales:

  1. précision, qui est utilisé, par ex. dans

Yu, April et Daryl Chang. "Prédiction du sentiment de multiclasse à l'aide d'entreprises Yelp."

( link ) - notez que les auteurs travaillent avec presque la même répartition des notations, voir la figure 5.

Pang, Bo et Lillian Lee. "Voir les étoiles: Exploiter les relations de classe pour classer les sentiments par rapport aux échelles de notation." Actes de la 43ème réunion annuelle de l’Association pour la linguistique computationnelle. Association pour la linguistique computationnelle, 2005.

( lien )

  1. MSE (ou, moins souvent, Erreur absolue moyenne - MAE) - voir, par exemple,

Lee, Moontae et R. Grafe. "Analyse de sentiment multiclasse avec des critiques de restaurants." Projets finaux de CS N 224 (2010).

( lien ) - ils explorent à la fois la précision et la MSE, considérant que cette dernière est meilleure

Pappas, Nikolaos, Rue Marconi et Andrei Popescu-Belis. "Explaining the Stars: Apprentissage pondéré à instances multiples pour l'analyse du sentiment par aspect." Actes de la conférence de 2014 sur les méthodes empiriques dans le traitement du langage naturel. N ° EPFL-CONF-200899. 2014.

( lien ) - ils utilisent scikit-learn pour les approches d'évaluation et de référence et indiquent que leur code est disponible; Cependant, je ne le trouve pas. Si vous en avez besoin, écrivez une lettre aux auteurs. Le travail est assez nouveau et semble être écrit en Python.

Coût de différentes erreurs . Si vous tenez à éviter les erreurs grossières, par exemple. En évaluant les commentaires 1 à 5 étoiles ou quelque chose comme ça, regardez MSE; Si la différence compte, mais pas autant, essayez MAE, car elle ne correspond pas à la différence; sinon restez avec précision.

À propos des approches, pas des métriques

Essayez les approches de régression, par exemple SVR , car ils surperforment généralement les classificateurs Multiclass tels que SVC ou OVA SVM.

15

Tout d’abord, il est un peu plus difficile d’utiliser une simple analyse en comptant pour déterminer si vos données sont déséquilibrées ou non. Par exemple: 1 observation positive sur 1 000 est simplement un bruit, une erreur ou une avancée scientifique? On ne sait jamais.
Il est donc toujours préférable d'utiliser toutes vos connaissances disponibles et de choisir son statut avec sagesse.

Bon, si c'est vraiment déséquilibré?
Encore une fois - regardez vos données. Parfois, vous pouvez trouver une ou deux observations multipliées par cent. Parfois, il est utile de créer ces fausses observations d'une classe.
Si toutes les données sont nettes, l'étape suivante consiste à utiliser les pondérations de classe dans le modèle de prédiction.

Qu'en est-il des métriques multiclasses?
Dans mon expérience, aucune de vos métriques n'est généralement utilisée. Il y a deux principales raisons.
Premièrement: il est toujours préférable de travailler avec des probabilités qu'avec une prédiction solide (sinon, comment séparer les modèles avec les prédictions 0.9 et 0.6 s'ils vous donnent tous les deux la même classe?)
Et deuxièmement: il est beaucoup plus facile de comparer vos modèles de prévision et d’en construire de nouveaux en fonction d’une seule mesure.
D'après mon expérience, je pourrais recommander logloss ou MSE (ou simplement une erreur quadratique moyenne).

Comment résoudre les avertissements personnels?
Tout simplement (comme yangjie l’a remarqué), écrasez le paramètre average avec l’une des valeurs suivantes: 'micro' (calculez les mesures globalement), 'macro' (calculez les mesures pour chaque étiquette) ou 'weighted' (identique à la macro mais avec des pondérations automatiques).

f1_score(y_test, prediction, average='weighted')

Tous vos avertissements sont arrivés après l’appel de fonctions de métriques avec la valeur par défaut average'binary', ce qui n’est pas approprié pour la prédiction multiclass.
Bonne chance et amusez-vous avec l'apprentissage automatique!

Modifier:
J'ai trouvé une autre recommandation du répondeur de passer aux approches de régression (par exemple, la RVS) avec laquelle je ne peux pas accepter. Autant que je me souvienne, la régression multiclass n'existe même pas. Oui, il existe une régression multilabel qui est très différente et oui, il est possible dans certains cas de basculer entre la régression et la classification (si les classes sont en quelque sorte triées), mais cela reste plutôt rare.

Ce que je recommanderais (dans le cadre de scikit-learn) est d’essayer un autre outil de classification très puissant: accélération du gradient , forêt aléatoire (mon préféré), KNeighins et beaucoup plus.

Après cela, vous pouvez calculer une moyenne arithmétique ou géométrique entre les prévisions et la plupart du temps, vous obtiendrez un résultat encore meilleur.

final_prediction = (KNNprediction * RFprediction) ** 0.5
12
Vlad Mironov