Quelle est la meilleure mesure de performances utilisée pour équilibrer l'ensemble de données à l'aide de la technique SMOTE

8

J'ai utilisé la technique smote pour suréchantillonner mon jeu de données et maintenant j'ai un jeu de données équilibré. Le problème que j'ai rencontré est que les mesures de performance; la précision, le rappel, la mesure f1, la précision dans l'ensemble de données déséquilibré sont mieux effectués qu'avec un ensemble de données équilibré.

Quelle mesure puis-je utiliser pour montrer qu'un ensemble de données d'équilibrage peut améliorer les performances du modèle?

NB: roc_auc_score est meilleur dans un jeu de données équilibré que roc_auc_score avec un jeu de données déséquilibré. Peut-il être considéré comme une bonne mesure de performance? après l'explication, j'ai mis en œuvre du code et j'ai obtenu ces résultats

import pandas as pd
import numpy as np
from sklearn import preprocessing
import matplotlib.pyplot as plt 
plt.rc("font", size=14)
from sklearn.svm import LinearSVC
from sklearn.svm import SVC
from sklearn.cross_validation import train_test_split,StratifiedShuffleSplit,cross_val_score
import seaborn as sns
from scipy import interp
from time import *
from sklearn import metrics
X=dataCAD.iloc[:,0:71]
y= dataCAD['Cardio1']
# Split the dataset in two equal parts
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=0)
print(y_test.value_counts())
model=SVC(C=0.001, kernel="rbf",gamma=0.01, probability=True)
t0 = time()
clf = model.fit(X_train,y_train)
y_pred = clf.predict(X_test)
t = time() - t0
print("=" * 52)
print("time cost: {}".format(t))
print()
print("confusion matrix\n", metrics.confusion_matrix( y_test, y_pred))
cf=metrics.confusion_matrix(y_test, y_pred)
accuracy=(cf.item((0,0))/50)+(cf.item((1,1))/14)
print("model accuracy \n",accuracy/2)
print()
print("\t\tprecision_score: {}".format(metrics.precision_score( y_test, y_pred, average='macro')))
print()
print("\t\trecall_score: {}".format(metrics.recall_score(y_test, y_pred, average='macro')))
print()
print("\t\tf1_score: {}".format(metrics.f1_score(y_test, y_pred, average='macro')))
print()
print("\t\troc_auc_score: {}".format(metrics.roc_auc_score( y_test, y_pred, average='macro')))

Résultats:

Name: Cardio1, dtype: int64
====================================================
time cost: 0.012008905410766602

confusion matrix
 [[50  0]
 [14  0]]
model accuracy 
 0.5

        precision_score: 0.390625

        recall_score: 0.5

        f1_score: 0.43859649122807015

        roc_auc_score: 0.5

Pour un ensemble de données équilibré

X_train1,y_train1 = sm.fit_sample(X_train, y_train.ravel())
df= pd.DataFrame({'Cardio1': y_train1})
df.groupby('Cardio1').Cardio1.count().plot.bar(ylim=0)
plt.show()
print(X_train1.shape)
print(y_train1.shape)
#model=SVC(C=0.001, kernel="rbf",gamma=0.01, probability=True)
model=SVC(C=10, kernel="sigmoid",gamma=0.001, probability=True)
t0 = time()
clf = model.fit(X_train1,y_train1)
y_pred = clf.predict(X_test)
t = time() - t0
print("=" * 52)
print("time cost: {}".format(t))
print()
print("confusion matrix\n", metrics.confusion_matrix(y_test, y_pred))
cf=metrics.confusion_matrix(y_test, y_pred)
accuracy=(cf.item((0,0))/50)+(cf.item((1,1))/14)
print("model accuracy \n",accuracy/2)
print()
#print("\t\taccuracy: {}".format(metrics.accuracy_score( y_test, y_pred)))
print()
print("\t\tprecision_score: {}".format(metrics.precision_score( y_test, y_pred, average='macro')))
print()
print("\t\trecall_score: {}".format(metrics.recall_score(y_test, y_pred, average='macro')))
print()
print("\t\tf1_score: {}".format(metrics.f1_score(y_test, y_pred, average='macro')))
print()
print("\t\troc_auc_score: {}".format(metrics.roc_auc_score( y_test, y_pred, average='macro')))

Résultats:

(246, 71)
(246,)
====================================================
time cost: 0.05353999137878418

confusion matrix
 [[ 0 50]
 [ 0 14]]
model accuracy 
 0.5


        precision_score: 0.109375

        recall_score: 0.5

        f1_score: 0.1794871794871795

        roc_auc_score: 0.5

Je n'ai trouvé aucun résultat efficace. Dois-je implémenter le modèle en utilisant la validation croisée?

Rawia Sammout
la source

Réponses:

8

Tout d'abord, pour être clair, vous ne devez pas évaluer les performances de vos modèles sur l'ensemble de données équilibré. Ce que vous devez faire est de diviser votre ensemble de données en un train et un ensemble de tests avec idéalement le même degré de déséquilibre. L'évaluation doit être effectuée exclusivement sur l'ensemble de test, tandis que l'équilibrage sur l'ensemble de formation.

Quant à votre question, n'importe quelle métrique moyenne de macro devrait suffire pour prouver que votre technique d'équilibrage est efficace. Pour calculer une telle métrique (disons précision pour plus de simplicité), il vous suffit de calculer les précisions de chaque classe individuellement , puis de les faire la moyenne .

Exemple :
Nous avons formé deux modèles m1et m2le premier sans équilibrer l'ensemble de données et le second après avoir utilisé SMOTE pour équilibrer l'ensemble de données.

Valeurs réelles: 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
Prédit m1: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 <- ne prédit que la classe majoritaire
Prédit m2:1, 0, 0, 1, 0, 1, 0, 0, 1, 1

Comment calculer normalement la précision?

unecc=correctprejectjeonstotunelprejectjeons

Comment nos deux modèles fonctionnent-ils sur cette métrique?

unecc1=8dix=80%
unecc2=7dix=70%

Selon cette mesure de performance, m2c'est mieux que m1. Cependant, ce n'est pas nécessairement le cas, car cela m1prédit simplement la classe majoritaire! Afin de montrer comment m2est meilleur que m1, nous avons besoin d'une métrique qui traite les deux classes comme égales.

Nous allons maintenant essayer de calculer une précision macro-moyenne. Comment? Nous allons d'abord calculer la précision de chaque classe séparément, puis nous les calculerons en moyenne:

  • m1
    unecc10=88=100%m10
    unecc11=02=0%m11
    munecro_unecc1=unecc10+unecc112=100%+0%2=50%

  • m2
    unecc20=58=62,5%m20
    unecc21=22=100%m21
    munecro_unecc2=unecc20+unecc212=62,5%+100%2=81,25%

Remarques :

  • La moyenne des macros peut être appliquée à n'importe quelle métrique de votre choix, mais elle est plus courante dans les métriques de matrice de confusion (par exemple, précision, rappel, f1).

  • Vous n'avez pas besoin de l'implémenter par vous-même, de nombreuses bibliothèques l'ont déjà (par exemple, f1_score de sklearn a un paramètre appelé average, qui peut être défini sur "macro")

Djib2011
la source
Merci beaucoup pour votre grande explication, c'est clair et concis Pouvez-vous proposer des articles scientifiques réels ??
Rawia Sammout
4
Quelques articles sur le sujet: 1 , 2 , 3 . Ces articles présentent essentiellement des méthodes pour lutter contre le déséquilibre des classes (sur / sous-échantillonnage, poids des classes, etc.) et des mesures pouvant être utilisées dans ces situations (ROC, moyenne g, kappa quadratique, etc.)
Djib2011
pourriez-vous jeter un oeil sur le code partagé j'ai trouvé un résultat déroutant au lieu d'améliorer les performances du modèle en utilisant smote j'ai obtenu le contraste
Rawia Sammout
3
D'après ce que je peux dire à en juger par les matrices de confusion, votre premier modèle (sans équilibrage) ne prédit que la classe majoritaire, tandis que le second (avec smote) prédit l'autre classe. Je recommanderais peut-être d'essayer un autre classificateur, car les SVM nécessitent beaucoup de réglages hyperparamétriques (c'est-à-dire que vous exécutez votre modèle encore et encore afin de déterminer le meilleur C, gamma, type de noyau, etc.).
Djib2011
Merci pour toi. je pense que changer le classificateur est meilleur parce que j'utilise le paramètre de réglage gridsearch et j'ai formé les deux modèles sur les meilleurs hyperparamètres trouvés par l'algorithme
gridsearch