【问题标题】:How to turn off k fold cross validation in rpart() in r如何在 r 中的 rpart() 中关闭 k 折交叉验证
【发布时间】:2019-01-05 11:48:57
【问题描述】:

我有比特币时间序列,我使用 11 个技术指标作为特征,我想将回归树拟合到数据中。据我所知,r 中有两个函数可以创建回归树,即 rpart() 和 tree(),但这两个函数似乎都不合适。 rpart() 使用 k 折交叉验证来验证最优成本复杂度参数 cp,而在 tree() 中,无法指定 cp 的值。

我知道 cv.tree() 通过交叉验证寻找 cp 的最佳值,但同样,cv.tee() 使用 k 折交叉验证。由于我有时间序列,因此有时间依赖性,我不想使用 k 折交叉验证,因为 k 折交叉验证会将数据随机分成 k 折,将模型拟合到 k-1 折并计算左边第k折的MSE,然后我的时间序列的序列显然被破坏了。

我找到了rpart()函数的一个参数,即xval,它应该让我指定交叉验证的次数,但是当我查看xval=0时rpart()函数调用的输出时,它似乎没有关闭交叉验证。下面你可以看到我的函数调用和输出:

tree.model= rpart(Close_5~ M+ DSMA+ DWMA+ DEMA+ CCI+ RSI+ DKD+ R+ FI+ DVI+ 
OBV, data= train.subset, method= "anova", control= 
rpart.control(cp=0.01,xval= 0, minbucket = 5))

> summary(tree.model)
Call:
rpart(formula = Close_5 ~ M + DSMA + DWMA + DEMA + CCI + RSI + 
DKD + R + FI + DVI + OBV, data = train.subset, method = "anova", 
control = rpart.control(cp = 0.01, xval = 0, minbucket = 5))
n= 590 

           CP nsplit rel error
1  0.35433076      0 1.0000000
2  0.10981049      1 0.6456692
3  0.06070669      2 0.5358587
4  0.04154720      3 0.4751521
5  0.02415633      5 0.3920576
6  0.02265346      6 0.3679013
7  0.02139752      8 0.3225944
8  0.02096500      9 0.3011969
9  0.02086543     10 0.2802319
10 0.01675277     11 0.2593665
11 0.01551861     13 0.2258609
12 0.01388126     14 0.2103423
13 0.01161287     15 0.1964610
14 0.01127722     16 0.1848482
15 0.01000000     18 0.1622937

rpart() 似乎交叉验证了 15 个不同的 cp 值。如果这些值是用 k 折交叉验证来测试的,那么我的时间序列的顺序又会被破坏,我基本上不能使用这些结果。有谁知道如何有效地关闭 rpart() 中的交叉验证,或者如何改变 tree() 中 cp 的值?

更新:我听从了一位同事的建议并设置了 xval=1,但这似乎并没有解决问题。当 xval=1 here 时,您可以看到完整的函数输出。顺便说一句,parameters[j] 是参数向量的第 j 个元素。当我调用这个函数时,parameters[j]= 0.0009765625

在此先感谢

【问题讨论】:

  • 您考虑过使用caret 包吗?它支持rolling forecasting origin techniques(以及许多其他有用的东西)。
  • 您是如何设置数据的?您是否正在创建滞后变量并将它们作为特征包含在模型中?您是否将日期属性作为特征包括在内?请提供minimal, complete, and verifiable examplerpart() 中的 cp 参数是复杂度参数,它限制了必须在每个步骤中改进的整体失配。它会影响交叉验证的行为,但无论xval 控制参数的值如何,它都会有所不同。
  • @LenGreski 感谢您的评论。我从比特币的开盘价、最高价、最低价和收盘价计算了 11 个技术指标,我将它们用作自变量。我没有将比特币价格本身的任何滞后值作为自变量。我至少花了 100 行代码来计算这些技术指标,那么您建议如何提供最小、完整和可验证的示例?如果有帮助,我绝对可以将数据框和我的整个代码上传到我的网站并将其链接到我的问题。然后,您可以重现该问题,但信息量很大。
  • @markus,感谢您的评论。我查看了 caret 包,它似乎可以做很多事情。我花了 15 分钟浏览它,但我没有找到任何关于回归树的信息。您能否提供一些伪代码,您将如何使用 caret 包来拟合回归树,同时关闭交叉验证并指定成本复杂性参数?
  • @KevinSüdmersen 也许library(caret); fit <- train(x = x, y = y, method = "rpart", trControl = trainControl(method = "none"), metric = "RMSE", tuneGrid = data.frame(cp=0.01), preProcess = c("center", "scale"), xval = 0, minbucket = 5)。对于method = rpart caret,让我们只在tuneGrid 参数中调整(或修复)cp,而不是xvalminbucket,这就是我们需要通过... 参数提供它们的原因。 x 是您的特征,y 结果变量向量。希望这会有所帮助。

标签: r tree cross-validation rpart


【解决方案1】:

为了证明rpart() 是通过迭代cp 的下降值而不是重新采样来创建树节点,我们将使用mlbench 包中的Ozone 数据来比较rpart() 和@ 的结果987654329@ 如 OP 的 cmets 中所述。我们将按照Support Vector Machines 的 CRAN 文档中的说明设置臭氧数据,它支持非线性回归并且与rpart() 相当。

library(rpart)
library(caret)
data(Ozone, package = "mlbench")
# split into test and training
index <- 1:nrow(Ozone)
set.seed(01381708)
testIndex <- sample(index, trunc(length(index) / 3))
testset <- na.omit(Ozone[testIndex,-3])
trainset <- na.omit(Ozone[-testIndex,-3])


# rpart version
set.seed(95014) #reset seed to ensure sample is same as caret version
rpart.model <- rpart(V4 ~ .,data = trainset,xval=0)
# summary(rpart.model)
# calculate RMSE
rpart.pred <- predict(rpart.model, testset[,-3])
crossprod(rpart.pred - testset[,3]) / length(testIndex)

...以及 RMSE 计算的输出:

> crossprod(rpart.pred - testset[,3]) / length(testIndex)
         [,1]
[1,] 18.25507

接下来,我们将使用caret::train() 运行与 OP 的 cmets 中建议的相同分析。

# caret version
set.seed(95014)
rpart.model <- caret::train(x = trainset[,-3],
                            y = trainset[,3],method = "rpart", trControl = trainControl(method = "none"), 
                            metric = "RMSE", tuneGrid = data.frame(cp=0.01), 
                            preProcess = c("center", "scale"), xval = 0, minbucket = 5)
# summary(rpart.model)
# demonstrate caret version did not do resampling
rpart.model
# calculate RMSE, which matches RMSE from rpart() 
rpart.pred <- predict(rpart.model, testset[,-3])
crossprod(rpart.pred - testset[,3]) / length(testIndex)

当我们从caret::train() 打印模型输出时,它清楚地指出没有重新采样。

> rpart.model
CART 

135 samples
 11 predictor

Pre-processing: centered (9), scaled (9), ignore (2) 
Resampling: None

caret::train() 版本的 RMSE 与 rpart() 中的 RMSE 匹配。

> # calculate RMSE, which matches RMSE from rpart() 
> rpart.pred <- predict(rpart.model, testset[,-3])
> crossprod(rpart.pred - testset[,3]) / length(testIndex)
         [,1]
[1,] 18.25507
> 

结论

首先,如上所述,caret::train()rpart() 都不会重新采样。但是,如果打印模型输出,则会看到cp 的多个值用于通过这两种技术生成最终的 47 个节点树。

插入符号summary(rpart.model) 的输出

          CP nsplit rel error
1 0.58951537      0 1.0000000
2 0.08544094      1 0.4104846
3 0.05237152      2 0.3250437
4 0.04686890      3 0.2726722
5 0.03603843      4 0.2258033
6 0.02651451      5 0.1897648
7 0.02194866      6 0.1632503
8 0.01000000      7 0.1413017

rpart summary(rpart.model) 的输出

          CP nsplit rel error
1 0.58951537      0 1.0000000
2 0.08544094      1 0.4104846
3 0.05237152      2 0.3250437
4 0.04686890      3 0.2726722
5 0.03603843      4 0.2258033
6 0.02651451      5 0.1897648
7 0.02194866      6 0.1632503
8 0.01000000      7 0.1413017

其次,两个模型都通过将 monthday 变量作为自变量包含在内来计算时间值。在Ozone 数据集中,V1 是月份变量,V2 是日期变量。所有数据都是在 1976 年收集的,因此数据集中没有包含年份变量,并且在 svm 小插图的原始分析中,在分析之前删除了星期几。

第三,当日期属性不用作模型中的特征时,为了使用 rpart()svm() 等算法考虑其他基于时间的影响,必须将滞后效应作为模型中的特征包括在内,因为这些算法不直接考虑时间分量。 Ensemble Regression Trees for Time Series Predictions 是一个使用一系列滞后值的回归树集合来执行此操作的示例。

【讨论】:

  • 看到人们为解决其他人的问题付出了多少努力真的很了不起,我非常感谢!这两种方法的输出既有趣又令人困惑。据我现在了解,这两个函数调用都不进行重新采样,但它们使用不同的 cp 值来生成一棵相同的树。所以我的第一个问题是:你怎么能告诉这两个函数只使用我指定的 cp 值?
  • @KevinSüdmersen - 我的回答确实只使用了一个 cp 值,即 0.01。这样想,在函数参数中设置 cp=.01 意味着“继续分裂树,直到解释的方差百分比小于 0.01。”
  • 我的第二个问题与您的第三点有关:据我了解,我必须先修改数据框,然后才能使用集成回归树进行 TS 预测。我试图了解您链接到并在 Google 中搜索的论文中概述的程序,但不幸的是,我还不清楚。您是否知道任何好的资源来解释如何“将滞后效应作为模型中的特征包含在内”,或者假设我有预测变量 X_1、X_2、X_3 和 Y,您是否可以向我展示如何设置我的数据框因变量?
  • 回复:“@KevinSüdmersen - 我的回答确实只使用了一个 cp 值,0.01。这样想,在函数参数中设置 cp=.01 意味着“继续拆分树,直到百分比解释的方差小于 0.01。”" --> 啊,所以我必须像这样解释 summary(rpart.model) 的输出:在第一次拆分时,解释的方差百分比 (POVE) 是 0.58951537,在第二次分裂,POVE 为0.08544094,rpart 不断分裂,直到 POVE 低于我们预先指定的值0.01
  • @KevinSüdmersen 您可能会发现Using regression trees for forecasting double-seasonal time series with trend in R 上的这篇博文很有用。问候
【解决方案2】:

在您的模型中,只需 xval=0 关闭交叉验证即可。

在您的输出中,您只有CP NSPLIT REL ERROR,通过交叉验证您应该有CP NSPLIT REL ERROR XERROR XSTD

cp 只是从 1 到 0.01 的“复杂性参数”(默认为 cp=0.01)。

rel error 是您对数据集训练的预测错误/根节点的预期损失。

nsplit 根据cp 在你的树的大小上的相对节点数。

看:https://cran.r-project.org/web/packages/rpart/vignettes/longintro.pdf

【讨论】:

    猜你喜欢
    • 2019-12-18
    • 2018-08-29
    • 2016-11-15
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 2016-01-15
    • 2017-06-09
    • 1970-01-01
    相关资源
    最近更新 更多