【问题标题】:Using decision tree regression and cross-validation in sklearn在 sklearn 中使用决策树回归和交叉验证
【发布时间】:2017-11-24 17:22:54
【问题描述】:

我是统计方法的新手,所以请原谅任何天真。在使用来自 sklearn 的决策树回归(例如 DecisionTreeRegressor 和 RandomForestRegressor)时,我无法理解交叉验证的执行。我的数据集从具有多个预测变量(y = 单个因变量;X = 多个自变量)到具有单个预测变量并且包含足够多的案例(> 10k)。以下解释适用于所有情况。

使用标准方法对回归变量进行拟合和评分时:

dt = DecisionTreeRegressor()
rf = RandomForestRegressor()

dt.fit(X,y)
rf.fit(X,y)

dt_score = dt.score(X,y)
rf_score = rf.score(X,y)

dt_score 和 rf_score 返回有希望的 R 平方值 (> 0.7),但是我知道 DT 的过拟合属性以及较小程度的 RF。因此,我尝试通过交叉验证(10 倍)对回归变量进行评分,以获得更真实的准确性表示:

dt = DecisionTreeRegressor()
rf = RandomForestRegressor()

dt.fit(X,y)
rf.fit(X,y)

dt_scores = cross_val_score(dt, X, y, cv = 10)
rf_scores = cross_val_score(rf, X, y, cv = 10) 

dt_score = round(sum(dt_scores )/len(dt_scores ), 3)
rf_score = round(sum(rf_scores )/len(rf_scores ), 3)

这种交叉验证的结果总是返回负值。我假设它们是根据 sklearn 指导原则的 R 平方值:默认情况下,每次 CV 迭代计算的分数是估计器的 score 方法(两者的 score 方法回归量是 R 的平方)。基本 KFold 交叉验证指南给出的解释是:每个折叠都被用作一次验证,而剩余的 k - 1 个折叠形成训练集。

当使用 10 个旧 cv 时,我对此的理解是:我的数据集被分成 10 个相等的部分,对于每个部分,其余 9 个部分用于训练(我不确定这是拟合操作还是得分操作),其余部分用于验证(不确定为验证做了什么)。这些回归器对我来说是一个完整的“黑匣子”,所以我不知道如何将树用于回归以及交叉验证从何处获取其 R 平方值。

总而言之,我很难理解交叉验证如何显着降低准确性(R 平方)?我是否对回归器使用交叉验证权?对决策树回归器使用交叉验证是否有意义?我应该使用其他交叉验证方法吗?

谢谢

【问题讨论】:

  • 交叉验证是一种计算通用度量的技术,在本例中为 R^2。当您在某些数据上训练(即拟合)您的模型,然后在相同的训练数据上计算您的指标(即验证)时,您收到的指标可能存在偏差,因为您的模型对训练过度拟合数据。换句话说,交叉验证旨在估计您的模型在可见数据上的表现。所以,这告诉你,如果你做得正确,你的模型在看不见的数据上表现不佳,可能是由于过度拟合。
  • 正如您所说,DT 是臭名昭著的过度拟合者。您可以尝试调整 sklearn 中决策树回归器可用的各种参数。一个好的起点通常是最大深度。
  • 总而言之,“交叉验证如何显着降低准确性(R 平方)”的答案?是“因为你的模型在看不见的数据上表现很差”。
  • 感谢您的意见@juanpa.arrivillaga。您的评论“如果您做得正确”,您是指我如何在 python 中调用 sklearn 方法吗?所以你同意完全可以想象决策树和随机森林回归器过度预测如此严重以至于在应用交叉验证时它会将 R 平方从 0.8 降至

标签: python scikit-learn regression


【解决方案1】:

整理了一个小代码-sn-p,阐明了如何使用 DecisionTreeRegressor 和交叉验证。

A.在第一个 code-sn-p 中使用了“cross_val_score”。但是,r2_score 可能有负分,从而可以深入了解模型的学习效果不佳。

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, 
test_size=0.20, random_state=0)

dt = DecisionTreeRegressor(random_state=0, criterion="mae")
dt_fit = dt.fit(X_train, y_train)

dt_scores = cross_val_score(dt_fit, X_train, y_train, cv = 5)
print("mean cross validation score: {}".format(np.mean(dt_scores)))
print("score without cv: {}".format(dt_fit.score(X_train, y_train)))

# on the test or hold-out set
from sklearn.metrics import r2_score
print(r2_score(y_test, dt_fit.predict(X_test)))
print(dt_fit.score(X_test, y_test))

B.在下一节中,使用交叉验证对参数“min_samples_split”执行 GridSerach,然后使用最佳估计器对 valiation/holdout 集进行评分。 # 使用网格搜索: 从 sklearn.model_selection 导入 GridSearchCV 从 sklearn.metrics 导入 make_scorer 从 sklearn.metrics 导入 mean_absolute_error 从 sklearn.metrics 导入 r2_score

scoring = make_scorer(r2_score)
g_cv = GridSearchCV(DecisionTreeRegressor(random_state=0),
              param_grid={'min_samples_split': range(2, 10)},
              scoring=scoring, cv=5, refit=True)

g_cv.fit(X_train, y_train)
g_cv.best_params_

result = g_cv.cv_results_
# print(result)
r2_score(y_test, g_cv.best_estimator_.predict(X_test))

希望,这很有用。

参考:

https://www.programcreek.com/python/example/75177/sklearn.cross_validation.cross_val_score

【讨论】:

    【解决方案2】:

    决策树会根据您的特征值进行拆分,从而生成纯度最高的组。当我说纯洁时,我的意思是该组中的所有成员共享所有或几乎所有相似的东西(例如,全是白人、35 岁、全是男性等)。它将一直这样做,直到您的所有叶节点都是完全纯的,或者满足某些停止机制(例如,分裂所需的节点中的最小样本数)。您将在sklearn documentation 中看到的参数基本上是那些停止参数。现在,就回归而言,树将做的是将每个叶子(不再分裂的节点)的所有真实y 的平均值作为该特定路径的估计y-hat,这样当您预测您的测试数据集,该测试数据集中的每条记录基本上将沿着树的某个路径向下移动,直到它到达叶节点,并且该记录的估计 y-hat 将是该叶中所有观察值的平均真实 y节点。

    随机森林基本上是决策树的集合,它们使用训练数据的子集进行训练。这些树通常不如单个决策树模型那么深,这有助于缓解单个决策树的过拟合症状。 RF 的想法是您正在使用许多可以很好地概括您的数据的弱学习器。因此,更少的过拟合。

    R 平方度量基本上是1 - (SS_res / SS_tot)。分解该公式,您基本上是在查看残差平方和和总平方和。因此,您只需要知道真实的y 值、估计的y-hat 值以及真实y 值的平均值y-bar

    【讨论】:

    • 感谢您的解释@Scratch'N'Purr。这增加了我对这些概念的理解。在您的意见/经验中,当对决策树回归器应用交叉验证时,R 平方可以从 0.8 下降到
    • 在我看来,考虑到 sklearn 的 API 有一些默认设置来创建非常深的树,这是可能的。如果您查看 min_samples_leafmin_samples_split 之类的默认设置,它们建议使用非常深的树。甚至 RandomForestRegressor 也有这些默认值。我建议增加这些值。
    • 您还应该查看GridSearchCV。这会对可能的值进行参数搜索,以从您在网格搜索中提供的值列表中获取最佳参数值。对于初学者,只需在 min_samples_split 上运行参数搜索并将 min_samples_leaf 设置为 50。然后使用随机森林。
    • 太好了,谢谢@Scratch'N'Purr,树的高深度很有意义
    猜你喜欢
    • 2016-05-07
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 2013-01-24
    • 2017-07-07
    • 2011-01-19
    • 2016-05-05
    • 2018-06-30
    相关资源
    最近更新 更多