¿Cuál es la mejor métrica de rendimiento utilizada para equilibrar el conjunto de datos utilizando la técnica SMOTE?

8

Utilicé la técnica smote para sobremuestrear mi conjunto de datos y ahora tengo un conjunto de datos equilibrado. El problema que enfrenté es que las métricas de rendimiento; precisión, recuperación, medida f1, precisión en el conjunto de datos desequilibrados se realizan mejor que con el conjunto de datos equilibrado.

¿Qué medida puedo usar para mostrar que el conjunto de datos de equilibrio puede mejorar el rendimiento del modelo?

NB: roc_auc_score es mejor en datset equilibrado que roc_auc_score con dataset desequilibrado ¿Se puede considerar como una buena medición del rendimiento? Después de la explicación, implementé el código y obtuve estos resultados

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')))

Resultados:

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

Para un conjunto de datos equilibrado

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')))

Resultados:

(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

No encontré resultados eficientes. ¿Debo implementar el modelo usando validación cruzada?

Rawia Sammout
fuente

Respuestas:

8

En primer lugar, para ser claros, no debe evaluar el rendimiento de sus modelos en el conjunto de datos equilibrado. Lo que debe hacer es dividir su conjunto de datos en un tren y un conjunto de prueba con idealmente el mismo grado de desequilibrio. La evaluación debe realizarse exclusivamente en el conjunto de prueba, mientras que el equilibrio en el conjunto de entrenamiento.

En cuanto a su pregunta, cualquier métrica promediada macro debería funcionar bien para demostrar que su técnica de equilibrio es efectiva. Para calcular dicha métrica (digamos precisión por simplicidad), solo necesita calcular las precisiones de cada clase individualmente y luego promediarlas .

Ejemplo :
Entrenamos dos modelos m1y m2, el primero sin equilibrar el conjunto de datos y el segundo después de usar SMOTE para equilibrar el conjunto de datos.

Valores reales: 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
Predicho m1: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 <- solo predice la clase mayoritaria
Predicho m2:1, 0, 0, 1, 0, 1, 0, 0, 1, 1

¿Cómo calcularíamos normalmente la precisión?

acc=correctpredictionstotalpredictions

¿Cómo funcionan nuestros dos modelos en esta métrica?

acc1=810=80%
acc2=710=70%

Según esta métrica de rendimiento, m2es mejor que m1. Sin embargo, este no es necesariamente el caso, ¡ya que m1solo predice la clase mayoritaria! Para mostrar cómo m2es mejor que m1, necesitamos una métrica que trate las dos clases como iguales.

Ahora intentaremos calcular una precisión macro-promedio. ¿Cómo? Primero calcularemos la precisión para cada clase por separado, y luego los promediaremos:

  • Para m1: <- precisión de la clase en <- precisión de la clase
    acc10=88=100%m10
    acc11=02=0%m11
    macro_acc1=acc10+acc112=100%+0%2=50%

  • Para m2: <- precisión de la clase en <- precisión de la clase
    acc20=58=62.5%m20
    macro_acc2=acc 0 2 +acc 1 2acc21=22=100%m21
    macro_acc2=acc20+acc212=62.5%+100%2=81.25%

Notas :

  • El promedio de macros se puede aplicar a cualquier métrica que desee, sin embargo, es más común en las métricas de matriz de confusión (por ejemplo, precisión, recuperación, f1).

  • No necesita implementar esto usted mismo, muchas bibliotecas ya lo tienen (por ejemplo, sklearn's f1_score tiene un parámetro llamado average, que se puede establecer en "macro")

Djib2011
fuente
Muchas gracias por su gran explicación. Es claro y conciso. ¿Podría proponer algunos artículos científicos de verdad?
Rawia Sammout
44
Algunos artículos al respecto: 1 , 2 , 3 . Lo que estos artículos esencialmente resumen son métodos para combatir el desequilibrio de clase (sobre / submuestreo, pesos de clase, etc.) y métricas que se pueden utilizar en estas situaciones (ROC, media g, kappa cuadrático, etc.)
Djib2011
¿podría echar un vistazo al código compartido? Encontré resultados confusos en lugar de mejorar el rendimiento del modelo usando
smote. Obtuve
3
Por lo que puedo decir a juzgar por las matrices de confusión, su primer modelo (sin equilibrio) predice solo la clase mayoritaria, mientras que el segundo (con golpe) predice la otra clase. Recomendaría probar otro clasificador, ya que los SVM requieren una gran cantidad de ajustes de hiperparámetros (es decir, ejecutar su modelo una y otra vez para descubrir el mejor C, gamma, tipo de núcleo, etc.).
Djib2011
gracias por usted. Creo que cambiar el clasificador es mejor porque uso el parámetro de ajuste gridsearch y entrené a ambos modelos en los mejores hiperparámetros encontrados por el algoritmo gridsearch
Rawia Sammout