rpart 复杂度参数混淆

机器算法验证 r 大车 rpart
2022-03-19 12:53:38

rpart我对对象摘要中的 CP 计算有点困惑。

举这个例子

df <- data.frame(x=c(1, 2, 3, 3, 3), 
                 y=factor(c("a", "a", "b", "a", "b")),
                 method="class")
mytree<-rpart(y ~ x, data = df, minbucket = 1, minsplit=1)
summary(mytree)

Call:
rpart(formula = y ~ x, data = df, minbucket = 1, minsplit = 1)
  n= 5 

    CP nsplit rel error xerror      xstd
1 0.50      0       1.0      1 0.5477226
2 0.01      1       0.5      2 0.4472136

Variable importance
  x 
100 

Node number 1: 5 observations,    complexity param=0.5
  predicted class=a  expected loss=0.4  P(node) =1
    class counts:     3     2
   probabilities: 0.600 0.400 
  left son=2 (2 obs) right son=3 (3 obs)
  Primary splits:
      x < 2.5 to the left,  improve=1.066667, (0 missing)

对于根节点,我认为 CP 应该是 0.4,因为对根中的元素进行错误分类的概率是 0.4,而根处的树大小是 0。0.5 是正确的 CP 吗?

4个回答

复杂度参数α指定树的成本如何C(T)受到终端节点数的惩罚|T|, 导致正则化成本Cα(T)(参见http://cran.r-project.org/web/packages/rpart/vignettes/longintro.pdf,第 4 节)。

Cα(T)=C(T)+α|T|

小的α导致更大的树和潜在的过度拟合,大α在小树和潜在的欠拟合中。

据我所知,复杂性参数不是该特定节点中的错误。它是拆分该节点改进相对误差的量。因此,在您的示例中,拆分原始根节点会将相对误差从 1.0 降低到 0.5,因此根节点的 CP 为 0.5。下一个节点的 CP 仅为 0.01(这是决定何时考虑拆分的默认限制)。所以拆分那个节点只会导致 0.01 的改进,所以树的构建就停在那里了。

遵循 rpart 计算进行分类并不是特别容易。此外,尽管“Long Intro”建议使用 gini 进行分类,但似乎成本复杂性修剪(以及因此 cp 的值)是基于准确性而不是 gini 报告的。在这种情况下,我们可以完成计算并复制原始问题中查询的 0.4。首先,创建树

df <- data.frame(x=c(1,2,3,3,3), y=factor(c("a", "a", "b", "a", "b")))
mytree <- rpart(y ~ x, data = df, minbucket = 1, minsplit=1, method="class")

然后输入

print(mytree)

我们得到

node), split,  n, loss, yval, (yprob)
1)     root    5   2     a (0.6000000 0.4000000)  
2)     x< 2.5  2   0     a (1.0000000 0.0000000) *
3)     x>=2.5  3   1     b (0.3333333 0.6666667) *

“损失”列不是 gini(您可能已经预料到了)。它是所犯错误的数量。

这棵分裂树崩溃的点(基于准确性)是

2+α1=1+α2

(上面的第一个 2 是修剪树中的损失,第二个 2 是完整树中的终端节点数)。

求解 alpha,得到的 alpha 为 1。

如上面的答案所述,在 cptable 中,顶行中的误差被缩放为 1,然后 cp 被缩放相同的数量。第一行中的错误是没有分裂的树中的错误数,即 2。因此,1 的 alpha 通过除以 2 得到 0.50。

rpart中的C代码很难看懂,不过以上是我认为它在做的事情。

我写信是为了进一步验证@joran 和@fernando 的答案,并帮助像我这样的人进一步阐明如何解释rpart obejct 中的cp 矩阵。如果您观察以下代码,您会发现我已经为分类树拟合了两种可能的结果,并引入了我自己的损失矩阵(FN 是 FP 成本的两倍)。

Classification tree:
rpart(formula = Result ~ ., data = data, method = "class", parms = list(loss 
= PenaltyMatrix))                 

Root node error: 174/343 = 0.50729

n= 343 

    CP     nsplit  rel error xerror   xstd
1 0.066092      0   1.00000 0.50000 0.046311
2 0.040230      2   0.86782 0.73563 0.065081
3 0.034483      4   0.78736 0.91379 0.075656
4 0.022989      5   0.75287 1.01149 0.080396
5 0.019157      7   0.70690 1.17241 0.086526
6 0.011494     10   0.64943 1.21264 0.087764
7 0.010000     12   0.62644 1.31609 0.090890

现在,如果您在矩阵上观察例如步骤 6,您可以看到拆分次数增加了 3(从 7 到 10),导致相对误差为0.64943现在,如果您从上一步中的相应错误中减去此错误,您会发现0.05747的改进,如果除以步骤 5-6 之间的额外拆分数(即三个),则结果约为0.01957,即是步骤 5 的复杂度参数。这可以在所有步骤之间进行验证!

现在,如果可以,我有两个问题要向社区提出。

  • 它仍然让我感到困惑,随着树大小的增长,xerror 不断增加意味着什么?

  • 如果我遵循所谓的经验法则,我必须选择具有最小 xerror 的树,该树的 xerror 在树的一个标准偏差内,并且整个表的 xerror 最小。在我的情况下,这将是第 2 步中的树(因为这是具有最小 xerror 和 0.73563+0.065081=0.800711 的树,表中的任何其他树都不满足此要求)。它是否正确?