如何处理神经网络训练中的不平衡数据集

时间:2021-04-17 23:04:43

标签: python tensorflow keras imbalanced-data

我什至都在努力以简短但清晰的方式解释我的问题,因此在直接进入问题之前,我会尽我最大的努力提供一些背景信息。

基地

我有一个非常不平衡的数据集,它有 3 个类别,其中 2 个是少数类别,我有兴趣对它们进行分类。

数据集由稀疏特征组成,如下所示:

RA0 RA1 RA2 RA3 RA4 RA5 RA6 RA7 RA8 RA9 ... RB1 RB2 RB3 RB4 RB5 RB6 RB7 RB8 RB9 label
-------------------------------------------------------------------------------------
0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  1
0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  1
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  1

这个数据集非常不平衡,因为标签的 value_counts 如下:

df.label.value_counts()/len(df)
>0    0.944352
>1    0.028622
>2    0.027025

RAX 特征对应标签 1,RBX 特征对应标签 2。为什么这两个标签与这两种不同类型的特征“混合”?原始数据是一个时间序列,标签代表时间序列的“状态”。

因此,我尝试了反复和欠采样方法来尝试“重新平衡”数据集,但在这种情况下似乎更好的方法是尝试使用 GridSearch 找出标签的 class_weights

我尝试使用 roc_auc 评分进行 GridSearch,然后训练神经网络进行分类,但我在指标部分遇到了困难。模型如下:

 import tensorflow as tf

 def seq_model(n_features=20,init_neurons=170,decay=0.25,layers=3,lr=0.0001,activation1 = 'relu',activation2='relu'):
    model = Sequential()
    model.add(Dense(n_features, input_dim=n_features, activation=activation1))
    actual_neurons = init_neurons
    for i in range(layers):
        actual_neurons = int(actual_neurons*(1-decay*i))
        if actual_neurons <=0:
            break
        model.add(Dense(actual_neurons,activation = activation2))
    model.add(Dense(3,activation = 'softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=[tf.keras.metrics.AUC()])
    return model

在运行 GridSearch 后,我发现该数据集的最佳 class_weights 是 {0: 1, 1: 95, 2: 95}。然后,在完成 GridSearch 后,我训练了模型,但我注意到 Keras 不再支持指标的 roc_auc 曲线(如 accuracy),因此阅读其他问题和SO中的答案,我最终得到了这个:

class RocCallBack(Callback):
    def __init__(self,training_data,validation_data):
        self.x = training_data[0]
        self.y = training_data[1]
        self.x_val = validation_data[0]
        self.y_val = validation_data[1]
        
    def on_train_begin(self,logs={}):
        return
    def on_train_end(self, logs={}):
        return
    
    def on_epoch_begin(self,epoch,logs={}):
        return
    
    def on_epoch_end(self,epoch,logs={}):
        y_pred_train = self.model.predict_proba(self.x)
        roc_train = roc_auc_score(self.y,y_pred_train)
        y_pred_val = self.model.predict_proba(self.x_val)
        roc_val = roc_auc_score(self.y_val,y_pred_val)
        print('\rroc-auc_train: %s - roc-auc_val: %s' % (str(round(roc_train,4)),str(round(roc_val,4))),end=100*' '+'\n')
        return
    
    def on_batch_begin(self, batch, logs={}):
        return

    def on_batch_end(self, batch, logs={}):
        return

roc = RocCallBack(training_data=(x_train.values,y_train2),
                 validation_data = (x_test.values,y_test2))

early_stopping = EarlyStopping(patience = 100,verbose = True,monitor='val_auc',restore_best_weights=True)
check_point = ModelCheckpoint('classifier.hdf5',verbose=1,save_best_only=True,monitor = 'val_auc')

y_train2 = to_categorical(y_train)
y_test2 = to_categorical(y_test)

history = model.fit(x_train.values,y_train2, 
                    epochs = 50000,
                    batch_size = 24,
                    validation_data=(x_test.values,y_test2),
                    shuffle = False,
                    class_weight={0: 1, 1: 95, 2: 95},
                   callbacks=[roc,early_stopping,check_point])

问题

a) 在训练时,我注意到模型试图最小化 val_auc 值,这是我没想到的,因为我认为这个想法是最大化它。这是正常的还是我在这个过程中犯了一些错误?

b) 为了优化 roc_auc(从而提高精度,对吗?)将 tf.keras.metrics.AUC() 作为指标放入模型中是否正确?如果不是,应该如何做才能达到良好的性能?

c) 在为类寻找最佳权重时,我不应该使用 accuracy 作为指标,对吗? roc_auc 是我可以用于这种情况的最佳指标吗?

如果这篇文章很长,我真的很抱歉,但我仍在学习如何处理此类数据集,感谢您的帮助。如果需要,我还可以提供任何其他信息。

0 个答案:

没有答案