随机森林过拟合

Posted

技术标签:

【中文标题】随机森林过拟合【英文标题】:Random Forest is overfitting 【发布时间】:2016-03-01 03:47:12 【问题描述】:

我正在使用带有分层 CV 的 scikit-learn 来比较一些分类器。 我正在计算:准确度、召回率、auc。

我用 GridSearchCV 进行参数优化,CV 为 5。

RandomForestClassifier(warm_start= True, min_samples_leaf= 1, n_estimators= 800, min_samples_split= 5,max_features= 'log2', max_depth= 400, class_weight=None)

是来自 GridSearchCV 的 best_params。

我的问题,我觉得我真的过拟合了。例如:

具有标准偏差 (+/-) 的随机森林

精度:0.99 (+/- 0.06) 灵敏度:0.94 (+/- 0.06) 特异性:0.94 (+/- 0.06) B_accuracy:0.94 (+/- 0.06) AUC:0.94 (+/- 0.11)

带标准差 (+/-) 的逻辑回归

精度:0.88(+/- 0.06) 灵敏度:0.79 (+/- 0.06) 特异性:0.68 (+/- 0.06) B_accuracy:0.73 (+/- 0.06) AUC:0.73 (+/- 0.041)

其他看起来也像逻辑回归(所以它们看起来并没有过度拟合)。

我的简历代码是:

for i,j in enumerate(data):
    X.append(data[i][0])
    y.append(float(data[i][1]))
x=np.array(X)
y=np.array(y)

def SD(values):

    mean=sum(values)/len(values)
    a=[]
    for i in range(len(values)):
        a.append((values[i]-mean)**2)
    erg=sum(a)/len(values)
    SD=math.sqrt(erg)
    return SD,mean

    for name, clf in zip(titles,classifiers):
    # go through all classifiers, compute 10 folds 
    # the next for loop should be 1 tab indent more, coudlnt realy format it here, sorry
    pre,sen,spe,ba,area=[],[],[],[],[]
    for train_index, test_index in skf:
        #print train_index, test_index
        #get the index from all train_index and test_index
        #change them to list due to some errors
        train=train_index.tolist()
        test=test_index.tolist()
        X_train=[]
        X_test=[]
        y_train=[]
        y_test=[]
        for i in train:
            X_train.append(x[i])

        for i in test:
            X_test.append(x[i]) 

        for i in train:
            y_train.append(y[i])

        for i in test:
            y_test.append(y[i]) 


        #clf=clf.fit(X_train,y_train)
        #predicted=clf.predict_proba(X_test)
        #... other code, calculating metrics and so on...
    print name 
    print("precision: %0.2f \t(+/- %0.2f)" % (SD(pre)[1], SD(pre)[0]))
    print("sensitivity: %0.2f \t(+/- %0.2f)" % (SD(sen)[1], SD(pre)[0]))
    print("specificity: %0.2f \t(+/- %0.2f)" % (SD(spe)[1], SD(pre)[0]))
    print("B_accuracy: %0.2f \t(+/- %0.2f)" % (SD(ba)[1], SD(pre)[0]))
    print("AUC: %0.2f \t(+/- %0.2f)" % (SD(area)[1], SD(area)[0]))
    print "\n"

如果我使用scores = cross_validation.cross_val_score(clf, X, y, cv=10, scoring='accuracy') 方法,我不会得到这个“过度拟合”值。所以也许我正在使用的 CV 方法有问题?但它只适用于射频......

由于 cross_val_function 中特异性评分函数的滞后,我自己做了。

【问题讨论】:

问题是……? 交叉验证随机森林。相反,在构建森林时会对其进行交叉验证。 但是我应该如何比较模型呢?我知道这是经过交叉验证的,但不知何故我应该将它与其他方法(如 SVM、逻辑回归等)进行比较。我的问题也是:为什么我会过度拟合?带有“for train_index, test_index in skf:”的部分是否整个循环可能是错误的?因为正如我提到的, scorer_val 函数给出“正常”值 @TimBiegeleisen 您指的是 OoB 错误吗?因为“在构建过程中进行交叉验证”意味着与实际发生的情况不同,不应将其视为使用 RF 时无需单独训练/测试的声明。 为什么你认为?过度拟合是指您在训练数据上表现良好(随机森林几乎总是如此)但在测试数据上表现不佳。似乎随机森林的表现优于逻辑回归,如果您有高维度,这是可以预期的高度非线性解的问题。 en.wikipedia.org/wiki/Overfitting 【参考方案1】:

赫伯特,

如果您的目标是比较不同的学习算法,我建议您使用嵌套交叉验证。 (我将学习算法称为不同的算法,例如逻辑回归、决策树和其他从您的训练数据中学习假设或模型(最终分类器)的判别模型。

如果您想调整单个算法的超参数,“常规”交叉验证很好。但是,一旦您开始使用相同的交叉验证参数/折叠运行超参数优化,您的性能估计可能会过于乐观。如果您一遍又一遍地运行交叉验证,您的测试数据将在某种程度上成为“训练数据”。

实际上,人们经常问我这个问题,我将从我在此处发布的常见问题解答部分中摘录一些内容:http://sebastianraschka.com/faq/docs/evaluate-a-model.html

在嵌套交叉验证中,我们有一个外部 k-fold 交叉验证循环来将数据分成训练和测试折叠,而一个内部循环用于通过训练上的 k-fold 交叉验证来选择模型折叠。模型选择后,测试折用于评估模型性能。在我们确定了我们“最喜欢的”算法之后,我们可以跟进一个“常规的”k-fold 交叉验证方法(在完整的训练集上)来找到它的“最佳”超参数并在独立的测试集上对其进行评估。让我们考虑一个逻辑回归模型来更清楚地说明这一点:使用嵌套交叉验证,您将训练 m 个不同的逻辑回归模型,m 个外部折叠各 1 个,内部折叠用于优化每个模型的超参数(例如,结合使用gridsearch和k-fold交叉验证。如果你的模型是稳定的,这m个模型应该都有相同的超参数值,并且你根据外部测试折叠报告这个模型的平均性能。然后,你继续下一个算法,例如 SVM 等。

我只能强烈推荐这篇更详细地讨论这个问题的优秀论文:

S。 Varma 和 R. 西蒙。使用交叉验证进行模型选择时的误差估计偏差。 BMC 生物信息学,7(1):91,2006。(http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1397873/)

PS:通常,您不需要/不想调整随机森林的超参数(如此广泛)。随机森林(一种装袋形式)背后的想法实际上是不修剪决策树 - 实际上,Breiman 提出随机森林算法的一个原因是处理单个决策树的修剪问题/过度拟合。因此,您真正需要“担心”的唯一参数是树的数量(可能还有每棵树的随机特征数量)。但是,通常,您最好采用大小为 n 的训练引导样本(其中 n 是训练集中的原始特征数)和 squareroot(m) 特征(其中 m 是训练集的维度)。

希望这对您有所帮助!

编辑:

通过 scikit-learn 进行嵌套 CV 的一些示例代码:

pipe_svc = Pipeline([('scl', StandardScaler()),
                     ('clf', SVC(random_state=1))])

param_range = [0.0001, 0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0]

param_grid = ['clf__C': param_range, 
               'clf__kernel': ['linear'],
             'clf__C': param_range, 
               'clf__gamma': param_range, 
               'clf__kernel': ['rbf']]


# Nested Cross-validation (here: 5 x 2 cross validation)
# =====================================
gs = GridSearchCV(estimator=pipe_svc, 
                            param_grid=param_grid, 
                            scoring='accuracy', 
                            cv=5)
scores = cross_val_score(gs, X_train, y_train, scoring='accuracy', cv=2)
print('CV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))

【讨论】:

grid = GridSearchCV(algo, paramsE, cv=5, score='accuracy').fit(x_data,y_data) 然后:scores = cross_validation.cross_val_score(grid, x_data, y_data),会是否是嵌套的简历?从中我可以得到 grid.best_score_ 和最佳参数/估计器? @auronsen 不完全是。这不会是“嵌套 CV”,因为您将在训练集上拟合网格搜索估计器,而不是在外循环的训练子折叠上。我在上一个答案的底部添加了一个示例;希望有帮助!

以上是关于随机森林过拟合的主要内容,如果未能解决你的问题,请参考以下文章

随机森林过拟合

10、决策树集成--随机森林

Kaggle 快速模型之 Random Forrest 随机森林

随机森林

如何测试过度拟合的随机森林回归模型?

如何使用随机森林对不平衡类进行分类以避免过度拟合