library(rpart)
d = read.csv('datos/kidiq.csv')
# method = "anova" para modelos de regresion
t1 = rpart(kid_score ~ mom_iq, data = d, method = "anova")
plot(t1, margin = 0.02)
text(t1, cex = 0.75)
print(t1)
## n= 434
##
## node), split, n, deviance, yval
## * denotes terminal node
##
## 1) root 434 180386.20 86.79724
## 2) mom_iq< 84.33641 69 29011.83 66.86957 *
## 3) mom_iq>=84.33641 365 118793.70 90.56438
## 6) mom_iq< 101.8061 191 58829.52 85.31937 *
## 7) mom_iq>=101.8061 174 48941.98 96.32184 *
Lo que devuelve la tabla es:
Por ejemplo, para el nodo raiz:
(yp_root = mean(d$kid_score))
## [1] 86.79724
( deviance_root = sum( (d$kid_score - yp_root)^2 ) )
## [1] 180386.2
Para el nodo 3:
d3 = d[d$mom_iq >= 84.33641,]
(yp_3 = mean(d3$kid_score))
## [1] 90.56438
( deviance_3 = sum( (d3$kid_score - yp_3)^2 ) )
## [1] 118793.7
t2 = rpart(kid_score ~ mom_iq, data = d, method = "anova",
control = rpart.control(minsplit = 10, minbucket = 5, cp = 0.05))
plot(t2, margin = 0.02)
text(t2, cex=.75)
control:
print(t2)
## n= 434
##
## node), split, n, deviance, yval
## * denotes terminal node
##
## 1) root 434 180386.20 86.79724
## 2) mom_iq< 84.33641 69 29011.83 66.86957 *
## 3) mom_iq>=84.33641 365 118793.70 90.56438
## 6) mom_iq< 101.8061 191 58829.52 85.31937 *
## 7) mom_iq>=101.8061 174 48941.98 96.32184 *
(118793.70 - 58829.52 - 48941.98)/180386.20
## [1] 0.06110334
que es mayor que el límite cp = 0.01.
Podemos construir un arbol más profundo:
t3 = rpart(kid_score ~ mom_iq, data = d, method = "anova",
control = rpart.control(minsplit = 10, minbucket = 5, cp = 0.0069))
plot(t3, margin = 0.02)
text(t3, cex=.75)
print(t3)
## n= 434
##
## node), split, n, deviance, yval
## * denotes terminal node
##
## 1) root 434 180386.200 86.79724
## 2) mom_iq< 84.33641 69 29011.830 66.86957
## 4) mom_iq< 83.57478 60 26044.850 65.45000
## 8) mom_iq>=82.1513 14 5136.357 57.78571 *
## 9) mom_iq< 82.1513 46 19835.830 67.78261
## 18) mom_iq< 81.13004 40 14465.600 65.40000 *
## 19) mom_iq>=81.13004 6 3629.333 83.66667 *
## 5) mom_iq>=83.57478 9 2040.000 76.33333 *
## 3) mom_iq>=84.33641 365 118793.700 90.56438
## 6) mom_iq< 101.8061 191 58829.520 85.31937 *
## 7) mom_iq>=101.8061 174 48941.980 96.32184
## 14) mom_iq< 122.2355 132 38970.810 94.53788 *
## 15) mom_iq>=122.2355 42 8230.786 101.92860 *
(48941.980 - 38970.810 - 8230.786)/180386.200
## [1] 0.009648099
plot(residuals(t3))
\[ R^2 = 1 - \frac{RSS}{TSS} \]
donde RSS = \(\sum e_i^2 = \sum deviance(hoja_i)\) y TSS = deviance(root)
Se denomina error relativo al cociente RSS/TSS. Y la X indica que se ha calculado mediante validación cruzada.
par(mfrow = c(1,2))
rsq.rpart(t3)
##
## Regression tree:
## rpart(formula = kid_score ~ mom_iq, data = d, method = "anova",
## control = rpart.control(minsplit = 10, minbucket = 5, cp = 0.0069))
##
## Variables actually used in tree construction:
## [1] mom_iq
##
## Root node error: 180386/434 = 415.64
##
## n= 434
##
## CP nsplit rel error xerror xstd
## 1 0.1806158 0 1.00000 1.00274 0.065024
## 2 0.0611036 1 0.81938 0.84728 0.058712
## 3 0.0096481 2 0.75828 0.79453 0.056327
## 4 0.0069121 3 0.74863 0.86242 0.059701
## 5 0.0069000 6 0.72790 0.89153 0.062770
Los árboles que hemos visto se construyen de arriba hacia abajo, desde el nodo raiz hasta las hojas. Otra estrategia es construir un arbol muy profundo y luego podarlo. Construiriamos el arbol, por tanto, de abajo hacia arriba.
Primero construimos un arbol profundo:
t4 = rpart(kid_score ~ mom_iq, data = d, method = "anova",
control = rpart.control(minsplit = 2, cp = 0.005))
plot(t4, margin = 0.02)
text(t4, cex=.75)
t4_printcp = printcp(t4) # lo guardamos en una variable para utilizarlo despues
##
## Regression tree:
## rpart(formula = kid_score ~ mom_iq, data = d, method = "anova",
## control = rpart.control(minsplit = 2, cp = 0.005))
##
## Variables actually used in tree construction:
## [1] mom_iq
##
## Root node error: 180386/434 = 415.64
##
## n= 434
##
## CP nsplit rel error xerror xstd
## 1 0.1806158 0 1.00000 1.00503 0.065431
## 2 0.0611036 1 0.81938 0.84436 0.058593
## 3 0.0106614 2 0.75828 0.78617 0.056071
## 4 0.0083922 6 0.71563 0.85314 0.061289
## 5 0.0074483 8 0.69885 0.92698 0.068632
## 6 0.0071830 10 0.68395 0.96620 0.073513
## 7 0.0062379 11 0.67677 0.99424 0.076778
## 8 0.0062370 16 0.64239 1.01822 0.077515
## 9 0.0057384 19 0.62368 1.02750 0.078904
## 10 0.0057042 20 0.61794 1.02597 0.079016
## 11 0.0056835 39 0.49145 1.01699 0.078452
## 12 0.0056244 40 0.48577 1.01665 0.078427
## 13 0.0055191 45 0.45765 1.03284 0.079389
## 14 0.0052498 46 0.45213 1.05642 0.080155
## 15 0.0050000 49 0.43638 1.08944 0.082479
plotcp(t4)
A veces este gráfico tiene un mínimo, por lo que deberíamos seleccionar ese arbol. En caso contrario, elegimos el tamaño donde el error se estabilice.
Según el gráfico y la tabla anterior, un arbol de 3 hojas (nsplit =2) parece razonable.
(t4_cp = t4_printcp[3,"CP"])
## [1] 0.01066143
t4_prune = prune(t4, cp = t4_cp)
plot(t4_prune, margin = 0.02)
text(t4_prune, cex=.75)
En este caso se ha obtenido la misma solución que construyendo el árbol con los parámetros por defecto.
xp = data.frame(mom_iq = 95)
predict(t4_prune, newdata = xp)
## 1
## 85.31937