如何解释随机森林 ML 算法根本不学习,而逻辑回归学习得很好?

机器算法验证 机器学习 Python 随机森林 模型评估 助推
2022-04-04 06:07:05

我的预测任务如下:

使用名称来预测人们的种族(分为 4 类:“英语”、“法语”、“中国人”和“所有其他人”)作为一个多类分类问题。在特征工程期间,名称变量被进一步分解为 3 个字母和 4 个字母的子串。例如,名称“Robert”被分解为“rob”、“obe”、“ber”、“ert”、“robe”、“ober”和“bert”。

我有大约 500 万行,每行代表一个人。我将整个数据分成 80:20 的训练:测试集。在训练集中,我挖出 10% 用作开发集,我运行 5 倍交叉验证以获得每个 ML 算法的最佳(超)参数集。我使用的 ML 算法包括正则化逻辑回归 (LR)、线性 SVC、非线性 SVC、决策树 (DT) 和随机森林 (RF)。

我使用了最优参数集(来自超参数集,从 5 折交叉验证中给出了最佳 F 分数)并应用到使用整个训练集来训练模型,然后我使用训练后的模型来预测和评估它在测试集中的表现。

我看到的奇怪现象是 LR 和 linear-SVC 的准确率和 F1 分数高达 80%,而 DT 和 RF 极差,约为 50%,这与没有预测值的基准虚拟预测器大致相同.

我知道一些 ML 算法在不同的问题空间中应该比其他算法表现更好(没有免费午餐定理),并且 LR 和线性 SVC 优于非线性 SVC 的事实,而非线性 SVC 反过来又非常优于 DT 和 RF,这表明问题是线性可分,但边界不整齐地平行于特征轴。

然而,DT/RF 根本无法学习任何东西(与随机预测器的性能相似)这一事实让我感到震惊,尤其是在有这么多数据以及 LR/linear-SVC 做得很好的情况下。我在训练集上应用并评估了经过训练的模型,即使在我发现奇怪的训练集中进行评估时,DT/RF 要么学得非常少,要么根本学不到(因为我认为测试集的表现不佳是由于训练中的过度拟合放)。

既然 DT/RF 是灵活的模型,它们至少应该能够学习一些东西吗?这是否可能真的发生在现实生活中(也就是我看到的是真实的自然现象),还是我可能错误地使用了 DT/RF?我在下面包含了代码,这些代码指示了我允许在 5 折交叉验证期间随机搜索超参数空间的空间。

# Partial code to specify hyperparameter space to be searched
'LR_V1': {  'clf': LogisticRegression(),
            'param': {
                'logisticregression__solver': ['liblinear'],
                'logisticregression__penalty': ['l1', 'l2'],
                'logisticregression__C': np.logspace(-4, 4, 20),
                'logisticregression__tol': np.logspace(-5, 5, 20),
                'logisticregression__class_weight': [None, 'balanced'],
                'logisticregression__multi_class': ['ovr', 'auto'],
                'logisticregression__max_iter': [50, 1000, 4000, 20000],
            }},
'LR_V2': {  'clf': LogisticRegression(),
            'param': {
                'logisticregression__solver': ['newton-cg', 'lbfgs', 'sag', 'saga'],
                'logisticregression__penalty': ['none', 'l2'],
                'logisticregression__C': np.logspace(-4, 4, 20),
                'logisticregression__tol': np.logspace(-5, 5, 20),
                'logisticregression__class_weight': [None, 'balanced'],
                'logisticregression__multi_class': ['ovr', 'multinomial', 'auto'],
                'logisticregression__max_iter': [50, 1000, 4000, 20000],
            }},
'SVC_LINEAR': { 'clf': OneVsRestClassifier(LinearSVC()),
                'param': {
                    'onevsrestclassifier__estimator__penalty': ['l2'],
                    'onevsrestclassifier__estimator__loss': ['hinge', 'squared_hinge'],
                    'onevsrestclassifier__estimator__C': np.logspace(-4, 4, 20),
                    'onevsrestclassifier__estimator__tol': [0.00001, 0.0001, 0.001, 0.01, 0.1, 1],
                    'onevsrestclassifier__estimator__class_weight': [None, 'balanced'],
                    'onevsrestclassifier__estimator__multi_class': ['ovr', 'crammer_singer'],
                    'onevsrestclassifier__estimator__max_iter': [50, 1000, 4000, 20000],
                }},
'SVC_NONLINEAR': {  'clf': OneVsRestClassifier(SVC()),
                    'param': {
                        'onevsrestclassifier__estimator__kernel': ['poly', 'rbf', 'sigmoid'],
                        'onevsrestclassifier__estimator__C': np.logspace(-4, 4, 20),
                        'onevsrestclassifier__estimator__tol': [0.00001, 0.0001, 0.001, 0.01, 0.1, 1],
                        'onevsrestclassifier__estimator__class_weight': [None, 'balanced'],
                        'onevsrestclassifier__estimator__decision_function_shape': ['ovo', 'ovr'],
                        'onevsrestclassifier__estimator__max_iter': [50, 1000, 4000, 20000],
                    }},
'RF': { 'clf': RandomForestClassifier(),
        'param': {
            'randomforestclassifier__n_estimators': [1, 8, 16, 32, 64, 100, 200, 500, 1000],
            'randomforestclassifier__criterion': ['gini', 'entropy'],
            'randomforestclassifier__class_weight': [None, 'balanced', 'balanced_subsample'],
            'randomforestclassifier__max_depth': [None, 5, 10, 20, 40, 80],
            'randomforestclassifier__min_samples_split': np.linspace(0.01, 1.0, 100, endpoint=True),
            'randomforestclassifier__min_samples_leaf': np.linspace(0.01, 0.5, 100, endpoint=True),
            'randomforestclassifier__max_leaf_nodes': [None, 10, 50, 100, 200, 400],
            'randomforestclassifier__max_features': [None, 'auto', 'sqrt', 'log2'],
        }},
'DT': { 'clf': DecisionTreeClassifier(),
        'param': {
            'decisiontreeclassifier__splitter': ['random', 'best'],
            'decisiontreeclassifier__criterion': ['gini', 'entropy'],
            'decisiontreeclassifier__class_weight': [None, 'balanced'],
            'decisiontreeclassifier__max_depth': [None, 5, 10, 20, 40, 80],
            'decisiontreeclassifier__min_samples_split': np.linspace(0.01, 1.0, 100, endpoint=True),
            'decisiontreeclassifier__min_samples_leaf': np.linspace(0.01, 0.5, 100, endpoint=True),
            'decisiontreeclassifier__max_leaf_nodes': [None, 10, 50, 100, 150, 200],
            'decisiontreeclassifier__max_features': [None, 'auto', 'sqrt', 'log2'],
        }},

# Partial code to show the random search in 5-fold cross-validation
from sklearn.model_selection import RandomizedSearchCV
pipe = make_pipeline(preprocessor, control_panel['ml_algo_param_grid'][1]['clf'])
grid = RandomizedSearchCV(pipe, param_distributions=control_panel['ml_algo_param_grid'][1]['param'], 
    n_jobs=-1, cv=5, scoring=f1_score)
grid.fit(X_dev, y_dev)
2个回答
  • 当数据高度稀疏时,RF 的表现会很差,因为它选择的要分割的特征很可能全为 0。请参阅:何时避免使用随机森林?

  • 像这样简单的东西或者当它恢复稀疏数据的有用密集表示时,可以改进 RF。但这不能保证。

  • 太丰富的树(太高的最大深度和相关参数)可能是过度拟合的根源,但影响通常很小,所以大多数人只是构建最深的树并收工。设置要分割的特征数量是迄今为止最重要的超参数;不过,我找不到我现在想的那篇文章。

  • 此外,"auto"和 " "根据文档sqrt做同样的事情。https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.htmlRandomForestClassifier

  • 使用 F1 分数来选择模型可能不够灵敏,可能会选择虚假模型。最好使用考虑到完整概率信息的严格适当的评分规则。一些例子是 Brier 分数和交叉熵。

  • 半相关说明:您不必调整随机森林中的树木数量我们必须调整随机森林中的树木数量吗?只需选择一个足够大的数字,以使预测的方差很小。

您在n_iter搜索中保留了 10 的默认值。对于具有多个重要超参数的大多数用途来说,这太低了,尤其是当您的搜索空间包含大面积的性能不佳的超参数组合时。

特别是,我认为您的树复杂性控制通常过于严格:每个分裂或叶子的小深度大的最小样本小的最大叶子可能会导致拟合不足。您可以跳到n_iter60-100,将这些参数的范围缩小到不太严格的范围(或不统一选择),和/或只搜索更少的类似用途的超参数。树木很少的随机森林也可能具有不稳定的分数;最好不要搜索该超参数,而将其保留在较大的位置。