等级不平衡(正等级为少数)的随机森林,精度低且分数分布怪异

时间:2019-02-06 22:08:54

标签: python scikit-learn random-forest

我有一个非常不平衡的数据集(5000正,300000负)。我正在使用sklearn RandomForestClassifier尝试预测正类的概率。我拥有多年的数据,而我设计的功能之一是上一年的课程,因此除了培训期间的测试集外,我还将保留数据集的最后一年以进行测试上。

这是我尝试过的结果(以及结果):

使用SMOTE和SMOTEENN进行上采样(怪异的分数分布,请参见第一张图片,阳性和阴性类别的预测概率都相同,即模型预测大多数阳性类别的概率非常低)

向下采样到平衡数据集(测试集的召回率为〜0.80,但从非平衡的一年期测试集中的总负数的绝对数量来看,年终测试集为0.07,请参见第二张图片)

保持不平衡(再次怪异的得分分布,对于测试和过期测试集,精度达到〜0.60,召回率分别降至0.05和0.10)

XGBoost(在年终测试集上,回忆起来要好一点,为0.11)

接下来我应该尝试什么?我想针对F1进行优化,因为在我的情况下,误报和误报都同样糟糕。我想合并k倍交叉验证,并已阅读在上采样之前应该这样做,a)我应该这样做/是否可能有帮助,b)如何将其合并到类似于以下内容的管道中:

from imblearn.pipeline import make_pipeline, Pipeline

clf_rf = RandomForestClassifier(n_estimators=25, random_state=1)
smote_enn = SMOTEENN(smote = sm)
kf = StratifiedKFold(n_splits=5)

pipeline = make_pipeline(??)

pipeline.fit(X_train, ytrain)
ypred = pipeline.predict(Xtest)
ypredooy = pipeline.predict(Xtestooy)

score_dist score_dist

1 个答案:

答案 0 :(得分:3)

  • 使用SMOTE和SMOTEENN进行上采样:我远不是那些专家,但是通过对您的数据集进行上采样,您可能会放大导致过拟合的现有噪声。这可以解释您的算法无法正确分类的事实,从而在第一张图中给出结果。

我在这里找到了更多信息,以及如何改善结果: https://sci2s.ugr.es/sites/default/files/ficherosPublicaciones/1773_ver14_ASOC_SMOTE_FRPS.pdf

  • 降低采样率时,您似乎会遇到与我所理解的相同的过拟合问题(至少对于上一年的目标结果而言)。但是,如果不查看数据,很难推断出其背后的原因。

  • 您的过拟合问题可能来自所使用的功能数量,这些功能可能会增加不必要的噪音。您可以尝试减少使用的功能数量,然后逐渐增加(使用RFE模型)。此处提供更多信息:

https://machinelearningmastery.com/feature-selection-in-python-with-scikit-learn/

对于您使用的模型,您提到了Random Forest和XGBoost,但是没有提到使用了更简单的模型。您可以尝试使用更简单的模型,并专注于数据工程。 如果您还没有尝试过,也许可以:

  • 对数据进行降采样
  • 使用StandardScaler标准化所有数据
  • 测试简单模型(如朴素贝叶斯和Logistic回归)的“蛮力”调整

    # Define steps of the pipeline
    steps = [('scaler', StandardScaler()),
             ('log_reg', LogisticRegression())]
    
    pipeline = Pipeline(steps)
    
    # Specify the hyperparameters
    parameters = {'C':[1, 10, 100],
                  'penalty':['l1', 'l2']}
    
    # Create train and test sets
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, 
    random_state=42)
    
    # Instantiate a GridSearchCV object: cv
    cv = GridSearchCV(pipeline, param_grid=parameters)
    
    # Fit to the training set
    cv.fit(X_train, y_train)
    

无论如何,对于您的示例而言,管道可以是(我使用Logistic回归进行了建模,但是您可以使用其他ML算法对其进行更改,并因此更改参数网格):

from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV, StratifiedKFold, cross_val_score

from imblearn.combine import SMOTEENN
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline

param_grid = {'C': [1, 10, 100]}

clf = LogisticRegression(solver='lbfgs', multi_class = 'auto')
sme = SMOTEENN(smote = SMOTE(k_neighbors = 2), random_state=42)
grid = GridSearchCV(estimator=clf, param_grid = param_grid, score = "f1")

pipeline = Pipeline([('scale', StandardScaler()),
                     ('SMOTEENN', sme),
                     ('grid', grid)])

cv = StratifiedKFold(n_splits = 4, random_state=42)
score = cross_val_score(pipeline, X, y, cv=cv)

希望对您有所帮助。

(编辑:我在GridSearchCV中添加了score =“ f1”)