Qual é a melhor métrica de desempenho usada no balanceamento de conjunto de dados usando a técnica SMOTE

8

Eu usei a técnica smote para exagerar o meu conjunto de dados e agora tenho um conjunto de dados equilibrado. O problema que enfrentei é que as métricas de desempenho; precisão, rechamada, medida f1, precisão no conjunto de dados desequilibrado são melhor executadas do que com o conjunto de dados balanceado.

Qual medida posso usar para mostrar que o balanceamento do conjunto de dados pode melhorar o desempenho do modelo?

NB: roc_auc_score é melhor no conjunto de dados balanceado que roc_auc_score com conjunto de dados desequilibrado. Pode ser considerado como uma boa medida de desempenho? após a explicação eu implementei o código e obtive esses 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 conjunto de dados balanceado

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

Não encontrei resultados eficientes. Devo implementar o modelo usando validação cruzada?

Rawia Sammout
fonte

Respostas:

8

Antes de tudo, para deixar claro, você não deve avaliar o desempenho de seus modelos no conjunto de dados balanceado. O que você deve fazer é dividir seu conjunto de dados em um trem e um conjunto de testes com idealmente o mesmo grau de desequilíbrio. A avaliação deve ser realizada exclusivamente no conjunto de testes, enquanto o equilíbrio no conjunto de treinamento.

Quanto à sua pergunta, qualquer métrica com média macro deve ser boa para provar que sua técnica de balanceamento é eficaz. Para calcular essa métrica (digamos precisão para simplificar), você só precisa calcular a precisão de cada classe individualmente e, em seguida, média -los.

Exemplo :
treinamos dois modelos m1e m2, o primeiro sem equilibrar o conjunto de dados e o segundo depois de usar o SMOTE para equilibrar o conjunto de dados.

Valores reais: 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
Predito m1: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 <- prediz apenas a classe majoritária
Predito m2:1, 0, 0, 1, 0, 1, 0, 0, 1, 1

Como normalmente calculamos a precisão?

umacc=correctpredEuctEuonstotumaeupredEuctEuons

Como nossos dois modelos se saem nessa métrica?

umacc1 1=810=80%
umacc2=710=70%

De acordo com essa métrica de desempenho, m2é melhor que m1. No entanto, este não é necessariamente o caso, pois m1apenas prevê a classe majoritária! Para mostrar como m2é melhor que m1, precisamos de uma métrica que trate as duas classes como iguais.

Agora, tentaremos calcular uma precisão macro-média. Como? Primeiro, calcularemos a precisão de cada classe separadamente e, depois, calcularemos a média delas:

  • m1
    umacc1 10 0=88=100%m10
    umacc1 11 1=0 02=0 0%m11
    mumacro_umacc1 1=umacc1 10 0+umacc1 11 12=100%+0 0%2=50.%

  • m2
    umacc20 0=58=62,5%m20
    umacc21 1=22=100%m21
    mumacro_umacc2=umacc20 0+umacc21 12=62,5%+100%2=81,25%

Notas :

  • A média macro pode ser aplicada a qualquer métrica que você desejar, no entanto, é mais comum em métricas de matriz de confusão (por exemplo, precisão, recall, f1).

  • Você não precisa implementar isso sozinho, muitas bibliotecas já o possuem (por exemplo, o f1_score do sklearn possui um parâmetro chamado average, que pode ser definido como "macro")

Djib2011
fonte
Muito obrigado pela sua ótima explicação. É claro e conciso. Você poderia propor alguns artigos científicos de verdade?
Rawia Sammout
4
Alguns artigos sobre o assunto: 1 , 2 , 3 . O que esses artigos geralmente apresentam são métodos para combater o desequilíbrio de classe (sobre / sub-amostragem, pesos de classe etc.) e métricas que podem ser usadas nessas situações (ROC, g-mean, kappa quadrático etc.)
Djib2011
você poderia dar uma olhada no código compartilhado eu encontrei uma resultados confusos em vez od melhorar o desempenho do modelo usando feriu eu tenho o contraste
Rawia Sammout
3
Pelo que posso dizer, a julgar pelas matrizes de confusão, seu primeiro modelo (sem balanceamento) prediz apenas a classe majoritária, enquanto o segundo (com smote) prediz a outra classe. Eu recomendaria talvez tentar outro classificador, pois os SVMs exigem uma grande quantidade de ajustes de hiperparâmetros (ou seja, executando seu modelo repetidamente para descobrir o melhor tipo de C, gama, kernel, etc.).
precisa saber é o seguinte
obrigado por você eu acho que mudando o classificador é melhor porque eu uso parâmetro de ajuste gridsearch e treinei tanto o modelo sobre os melhores hiperparâmetros encontrada pelo algoritmo gridsearch
Rawia Sammout