【问题标题】:How to use downsampling and configure class weight parameter when using XGboost for imbalanced classification?使用 XGboost 进行不平衡分类时如何使用下采样和配置类权重参数?
【发布时间】:2021-07-21 23:59:48
【问题描述】:

我正在研究具有极端类别不平衡的数据集的二元分类问题。为了帮助模型学习少数类的信号,我对多数类进行了下采样,使得训练集有 20% 的少数类和 80% 的多数类。

现在还有另一个参数 "scale_pos_weight" 。不知道下采样后如何设置这个参数。

我应该根据实际的类比来设置,还是应该在下采样后使用类比?

【问题讨论】:

    标签: python machine-learning xgboost


    【解决方案1】:

    由于您已经对数据进行了下采样,因此应根据您的下采样数据设置 scale_pos_weight 参数。使用以下方法计算值:

    scale_pos_weight = count(negative examples)/count(Positive examples)
    

    在你的情况下,

    scale_pos_weight = 80/20 = 4
    

    您还可以使用hyperparameter optimization 自动找到最佳参数集。

    【讨论】:

      【解决方案2】:

      在计算损失函数时使用类权重,以防止模型对主类赋予重要性。如果一个类在数据集上占主导地位,那么模型将倾向于更好地学习该类,因为损失主要取决于模型在该主导类上的表现。

      让我们考虑一个极端情况,即数据集包含 99% 的正样本。如果模型只为每个样本预测 1,那么它的准确率将达到 99%。 类权重背后的理念是您希望每个样本对损失的贡献均等。因此,您应该根据您的训练集计算此比率,因为损失是根据您的训练集计算的。您的模型不知道您丢弃的样本。

      如果你做出正确的预测,损失为0,否则不是。谈到你的情况,为了确保每个样本对损失的贡献相等,对少数类的错误预测应该比对多数类的错误预测多 4 倍的惩罚。这样,模型就不能忽略某个类或偏向多数类。

      通常最好将类权重设置为与该特定类的样本数量成反比。因此,在您的情况下,这将是 4。但是,在实践中,您可能应该尝试几个不同的值来找到最佳权重。

      另一个重要方面是这些样本在野外的比例。您说您进行了下采样,如果与您的训练数据集相比,野外的类比率不同,那么当您部署模型或在未见过的样本上测试它时,您可能会观察到更差的分数。这就是为什么理想情况下,您还应该使用您的领域知识以现实的比率分割您的验证集和测试集

      【讨论】:

        【解决方案3】:

        好问题。 XGBoostbeen known to do well for imbalanced datasets,并包含许多超参数来帮助我们实现目标。

        对于scale_pos_weight 功能,XGBoost documentation suggests

        sum(negative instances) / sum(positive instances)

        对于极度不平衡的数据集,有人建议使用上述公式的sqrt

        对于权重,通常通过 XGBoost 中的sample_weight 参数,您可以通过sklearn utility 学习class_weights,如here 所述。

        两者的区别是explored here,但总结起来:

        sample_weight 参数允许您指定不同的权重 对于每个训练示例。 scale_pos_weight 参数可让您 为整个示例类别(“正”类别)提供权重。

        在代码中,您可以在下面看到这些实现,包括平方根。请注意,我必须使用合成数据,因为问题中没有提供任何数据。

        # General imports
        import pandas as pd
        from sklearn import datasets
        from collections import Counter
        
        # Generate datasets
        from sklearn.datasets import make_classification
        from imblearn.datasets import make_imbalance
        
        # Train, test, splits and gridsearch optimization
        from sklearn.model_selection import train_test_split, GridSearchCV
        
        # Class weights
        from sklearn.utils import class_weight
        
        # Performance
        from sklearn.metrics import classification_report
        
        # Modeling
        import xgboost
        
        import warnings
        warnings.filterwarnings('ignore')
        
        # Generate synthetic data
        X, y = make_classification(n_samples=10000, n_features=20, n_informative=15, class_sep=2.0, n_classes=2, n_clusters_per_class=5, hypercube=True, random_state=30)
        scaled_X, scaled_y = make_imbalance(X, y, sampling_strategy={0:200}, random_state=8)
        data = pd.DataFrame(data=scaled_X, columns=['feature_{}'.format(i) for i in range(X.shape[1])])
        X_train, X_test, y_train, y_test = train_test_split(data, scaled_y, random_state=8, stratify=scaled_y)
        
        # Compare 3 XGBoost models: no changes to weights, using sample weights, and using weight_scale
        
        # Build a model without using the scale_pos_weight parameter, fit it, and get a set of its performance measures.
        model_no_scale = xgboost.XGBClassifier(random_state=30)
        model_no_scale.fit(X_train, y_train)
        # Print performance
        print("Off the Shelf XGBoost")
        print(classification_report(y_test, model_no_scale.predict(X_test)))
        
        # Get class_weights
        # https://datascience.stackexchange.com/questions/16342/unbalanced-multiclass-data-with-xgboost
        model_weights = xgboost.XGBClassifier(sample_weight=class_weight.compute_sample_weight(class_weight='balanced', y=scaled_y), random_state=30)
        model_weights.fit(X_train, y_train)
        # Print performance
        print("Weights XGBoost")
        print(classification_report(y_test, model_weights.predict(X_test)))
        
        # Get the counts of the training data per XGBoost documentation
        counts = Counter(y_train)
        model_scale = xgboost.XGBClassifier(scale_pos_weight=counts[0] / counts[1], random_state=30)
        model_scale.fit(X_train, y_train)
        # Print performance
        print("Scale XGBoost")
        print(classification_report(y_test, model_scale.predict(X_test)))
        
        # Get the counts of the training data per XGBoost documentation
        from math import sqrt
        model_sqrt = xgboost.XGBClassifier(scale_pos_weight=sqrt(counts[0] / counts[1]), random_state=30)
        model_sqrt.fit(X_train, y_train)
        # Print performance
        print("SQRT XGBoost")
        print(classification_report(y_test, model_sqrt.predict(X_test)))
        

        结果:

        Off the Shelf XGBoost
                      precision    recall  f1-score   support
        
                   0       0.95      0.38      0.54        50
                   1       0.98      1.00      0.99      1253
        
            accuracy                           0.98      1303
           macro avg       0.96      0.69      0.77      1303
        weighted avg       0.97      0.98      0.97      1303
        
        
        Weights XGBoost
                      precision    recall  f1-score   support
        
                   0       0.95      0.38      0.54        50
                   1       0.98      1.00      0.99      1253
        
            accuracy                           0.98      1303
           macro avg       0.96      0.69      0.77      1303
        weighted avg       0.97      0.98      0.97      1303
        
        Scale XGBoost
                      precision    recall  f1-score   support
        
                   0       0.73      0.64      0.68        50
                   1       0.99      0.99      0.99      1253
        
            accuracy                           0.98      1303
           macro avg       0.86      0.82      0.83      1303
        weighted avg       0.98      0.98      0.98      1303
        
        SQRT XGBoost
                      precision    recall  f1-score   support
        
                   0       0.96      0.46      0.62        50
                   1       0.98      1.00      0.99      1253
        
            accuracy                           0.98      1303
           macro avg       0.97      0.73      0.81      1303
        weighted avg       0.98      0.98      0.97      1303
        

        【讨论】:

          猜你喜欢
          • 2018-01-30
          • 1970-01-01
          • 2021-08-24
          • 1970-01-01
          • 2020-06-18
          • 2020-08-30
          • 1970-01-01
          • 1970-01-01
          • 2020-09-06
          相关资源
          最近更新 更多