【问题标题】:Imbalanced classes in multi-class classification problem多类分类问题中的不平衡类
【发布时间】:2018-09-18 10:00:09
【问题描述】:

我正在尝试使用 TensorFlow 的 DNNClassifier 来解决具有 4 个不同类的多类 (softmax) 分类问题。我有一个不平衡的数据集,分布如下:

  • 0 级:14.8%
  • 1 类:35.2%
  • 2 类:27.8%
  • 第 3 类:22.2%

如何为每个类分配 DNNClassifier 的 weight_column 的权重?我知道如何编写代码,但我想知道我应该为每个类赋予什么值。

【问题讨论】:

    标签: tensorflow machine-learning keras deep-learning neural-network


    【解决方案1】:

    有多种选项可以为不平衡分类问题建立权重。最常见的一种方法是直接使用训练中的类数来估计样本权重。这个选项很容易被sklearn 计算出来。 “平衡”模式使用 y 的值自动调整与类频率成反比的权重。

    我们在下面的示例中尝试做的是“合并”compute_sample_weight 方法来拟合我们的 DNNClassifier。作为标签分布,我使用了问题中表达的相同

    import numpy as np
    import pandas as pd
    import tensorflow as tf
    from sklearn.utils.class_weight import compute_sample_weight
    
    train_size = 1000
    test_size = 200
    columns = 30
    
    ## create train data
    y_train = np.random.choice([0,1,2,3], train_size, p=[0.15, 0.35, 0.28, 0.22])
    x_train = pd.DataFrame(np.random.uniform(0,1, (train_size,columns)).astype('float32'))
    x_train.columns = [str(i) for i in range(columns)]
    
    ## create train weights
    weight = compute_sample_weight(class_weight='balanced', y=y_train)
    x_train['weight'] = weight.astype('float32')
    
    ## create test data
    y_test = np.random.choice([0,1,2,3], test_size, p=[0.15, 0.35, 0.28, 0.22])
    x_test = pd.DataFrame(np.random.uniform(0,1, (test_size,columns)).astype('float32'))
    x_test.columns = [str(i) for i in range(columns)]
    
    ## create test weights
    x_test['weight'] = np.ones(len(y_test)).astype('float32') ## set them all to 1
    
    ## utility functions to pass data to DNNClassifier
    def train_input_fn():
        dataset = tf.data.Dataset.from_tensor_slices((dict(x_train), y_train))
        dataset = dataset.shuffle(1000).repeat().batch(10)
        return dataset
    
    def eval_input_fn():
        dataset = tf.data.Dataset.from_tensor_slices((dict(x_test), y_test))
        return dataset.shuffle(1000).repeat().batch(10)
    
    ## define DNNClassifier
    classifier = tf.estimator.DNNClassifier(
        feature_columns=[tf.feature_column.numeric_column(str(i), shape=[1]) for i in range(columns)],
        weight_column = tf.feature_column.numeric_column('weight'),
        hidden_units=[10],
        n_classes=4,
    )
    
    ## train DNNClassifier
    classifier.train(input_fn=lambda: train_input_fn(), steps=100)
    
    ## make evaluation
    eval_results = classifier.evaluate(input_fn=eval_input_fn, steps=1)
    

    考虑到我们的权重是作为目标函数构建的,我们必须在测试数据中将它们设置为 1,因为标签是未知的。

    【讨论】:

      【解决方案2】:

      我强烈建议您使用欠采样(如果您有足够的数据这样做)或使用 SMOTE 过采样,在 imblearn 库中,您可以找到它here

      作为一名经验丰富的 ML 工程师,我可以说任何“加权”方法都不适合您,XGBoost 有一个名为 scale_pos_weight 的参数,或者您可以使用带有 class_weight="balanced" 的逻辑回归,但它们相当无关紧要,因为问题不在于估算器,而在于您的数据。所以我强烈建议你使用你的数据而不是分配权重。

      【讨论】:

        【解决方案3】:

        您可以尝试以下公式来平衡所有类别:

        weight_for_class_X = total_samples_size / size_of_class_X / num_classes
        

        例如:

        num_CLASS_0: 10000   
        num_CLASS_1: 1000
        num_CLASS_2: 100
        
        wgt_for_0 = 11100 / 10000 / 3 = 0.37  
        wgt_for_1 = 11100 / 1000 / 3 = 3.7
        wgt_for_2 = 11100 / 100 / 3 = 37
        
        # so after one epoch training the total weights of each class will be:
        total_wgt_of_0 = 0.37 * 10000 = 3700
        total_wgt_of_1 = 3.7 * 1000 = 3700
        total_wgt_of_2 = 37 * 100 = 3700
        

        【讨论】:

          猜你喜欢
          • 2013-06-07
          • 1970-01-01
          • 2019-07-13
          • 2020-03-01
          • 2020-10-24
          • 2019-06-11
          • 2013-12-26
          • 2015-01-28
          • 2020-10-11
          相关资源
          最近更新 更多