我想修剪我的 rpart 分类树,为此我需要了解分配损失时如何计算交叉验证的分类误差(即 xerror)。 为了简单起见,让我们考虑两类分类问题(比如 A 和 B)。那么根据我的理解,错误是
A 类误分类数 x A 类误分类损失 + B 类错误分类数 x B 类错误分类损失
所以我预计 xerror 是交叉验证数据中的错误。 但是,我在 xerror 中看到非常奇怪的结果。这是一个简单的例子
N <- 1000
p <- 50
ilogit <- function(eta){
1/(1+exp(-eta))
}
dat <- matrix(rnorm(N*p,mean=-3),nrow=N)
coeff <- (1:ncol(dat))*0.001
(x <-rbinom(N,size=1,prob=ilogit(dat%*%coeff)))
mydat <- data.frame(dat,x=x)
>table(x)
0 1
978 22
请注意,第 1 类是罕见事件,因此第 1 类中只有 22 个观测值。 现在,我对 rpart 进行拟合,将 1 类错误分类到 0 类的损失比将 0 类错误分类到 1 类的损失大 10 倍。
library(rpart)
fit <- rpart(x~.,data=mydat,method="class",
parm=list(loss=matrix(c(0,1,
10,0),2,2,byrow=TRUE)))
printcp(fit)
输出为:
Classification tree:
rpart(formula = x ~ ., data = mydat, method = "class", parms = list(loss = matrix(c(0,
1, 10, 0), 2, 2, byrow = TRUE)))
Variables actually used in tree construction:
[1] X1 X10 X13 X14 X17 X19 X35 X37 X39 X8 X9
Root node error: 220/1000 = 0.22
n= 1000
CP nsplit rel error xerror xstd
1 0.061364 0 1.00000 0.1000 0.021084
2 0.050000 9 0.36364 2.4136 0.316196
3 0.018182 11 0.26364 2.7727 0.338565
4 0.010000 13 0.22727 3.4091 0.373655
奇怪的是,初始 xerror 非常小,为 0.1000(我看到这是 1/class 0 的损失),然后 xerror 增加到 2.41、2.77 等等。不知何故,初始节点处的 xerror 比 rel 错误好得多!如果我将 0 类的损失改得更大,则会发生更奇怪的事情:
library(rpart)
fit <- rpart(x~.,data=mydat,method="class",
parm=list(loss=matrix(c(0,1,
100000,0),2,2,byrow=TRUE)))
printcp(fit)
输出为:
Classification tree:
rpart(formula = x ~ ., data = mydat, method = "class", parms = list(loss = matrix(c(0,
1, 100000, 0), 2, 2, byrow = TRUE)))
Variables actually used in tree construction:
[1] X15 X17 X18 X2 X20 X27 X28 X30 X32 X35 X36 X38 X39 X41 X49 X50 X7 X8
Root node error: 978/1000 = 0.978
n= 1000
CP nsplit rel error xerror xstd
1 0.182004 0 1.00000 100000 474.29
2 0.116564 1 0.81800 76278 1407.50
3 0.100204 2 0.70143 65031 1555.75
4 0.067485 3 0.60123 58180 1601.24
5 0.057260 4 0.53374 47853 1613.39
6 0.049080 5 0.47648 42945 1595.88
7 0.040900 6 0.42740 37219 1555.75
8 0.033742 7 0.38650 32106 1500.68
9 0.028630 8 0.35276 30368 1477.46
10 0.025562 9 0.32413 27301 1430.44
11 0.021472 10 0.29857 24949 1388.73
12 0.019427 12 0.25562 21779 1323.85
13 0.017382 13 0.23620 20859 1302.96
14 0.014315 14 0.21881 19530 1271.02
15 0.013292 16 0.19018 18916 1255.53
16 0.011247 17 0.17689 16667 1194.31
17 0.010000 20 0.14315 12168 1046.94
所以这一次,xerror 比相对误差要糟糕得多。这次,初始 xerror 似乎是 0 类的丢失(与上次不同,它不是倒数)。而且,当树生长时,xerror 会不断变得更好。
你能告诉我为什么会发生这种情况吗?
最佳答案
我知道这需要很长时间,但在解决了类似的问题后,我得到了这个奇怪结果的(部分)解决方案。
如果我们仔细观察问题的第一个变体(损失为 10),我们会发现根节点误差的计算如下:
- [("类别 1 的丢失") * ("实际类别的数量")]/("数据集的大小)
从概念上讲,这意味着如果我们对大多数数据点进行分类 类我们将有一个加权错误率,如上所述。
虽然 1 类的损失不断增加,但最终会使分数大于 1!在这种情况下,树结构开始假设将所有内容分类为第一类(仅仅因为它在成本方面是最优的)!
重要:如果两个类别的损失值导致根节点误差大于 1,则选择成本较小的类别作为树的初始分类选择。
<小时/>在所有情况下,初始交叉验证平均误差 (xerror) 通过以下公式计算:
- (A类损失值)/(B类损失值),
其中A是每次在根节点中被确定为最佳通用分类器的类。 (例如,如果类别 0 的损失为 2,类别 1 的损失为 3,则根节点上的 xerror 值为 0.66667)
注意:在问题@ThePrincess 的示例中,假设是正确的,因为零类的损失是统一的
<小时/>- 就 xerror 值性能的原因而言,我倾向于认为,在第一个示例中,树遭受了严重的过度拟合,导致只有根节点的树是最优的,而在后一种情况下,我们显然当我们深入研究时,我们会得到更好的解决方案,因为我们将其与初始解决方案进行比较,在初始解决方案中,我们的所有数据基本上从一开始就被错误分类(我们只有 1000 个数据中的 22 个,但我们一开始就把所有数据都分类为一个)。
p.s这是我在平台上的第一个答案。我希望它有帮助! (欢迎提出改进我的答案结构的建议!)
关于r - 分配损失时如何解释 rpart(方法 ="class")的 xerror,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37736868/