Está en la página 1de 18

Árboles de decisión

Máster de Bioinformática y Bioestadística


Francesc Carmona
11 de junio de 2019

if(!(require(rpart))) install.packages("rpart")
if(!(require(rpart.plot))) install.packages("rpart.plot")
if(!(require(ipred))) install.packages("ipred")

Introducción

Los árboles de decisión (decision trees) son algoritmos versátiles de aprendizaje automático (Machine
Learning) que pueden realizar tareas de clasificación y de regresión. Se trata de algoritmos muy potentes,
capaces de ajustar conjuntos de datos complejos. Además, los árboles de decisión son componentes
fundamentales de los bosques aleatorios (random forest), que se encuentran entre los algoritmos de
aprendizaje automático más potentes disponibles en la actualidad.
Los árboles de decisión construidos automáticamente a partir de un conjunto de datos se han utilizado
con éxito en muchas situaciones del mundo real. Su efectividad ha sido ampliamente comparada con la de
otros métodos de exploración de datos y la de los expertos humanos.
Un árbol de decisión es una estructura en forma de árbol formada por nodos internos y externos conectados
por ramas. Un nodo interno contiene una pregunta, es una unidad que evalúa una función de decisión
para determinar cuál es el próximo hijo a visitar. En contraste, un nodo externo, también llamado nodo
hoja o nodo terminal, no tiene nodos hijos y se asocia con una etiqueta o valor que carateriza a los datos
que llegan al mismo.
En general, un árbol de decisión se emplea de la siguiente manera: en primer lugar, se presenta una
instancia, un vector compuesto por varios atributos, al nodo inicial (o nodo raíz) del árbol de decisión.
Dependiendo del resultado de la función de decisión usada por el nodo interno, el árbol nos conducirá
hacia uno de los nodos hijos. Esto se repite hasta que se alcanza un nodo terminal y se asigna una etiqueta
o valor a los datos de entrada.
Consideremos, por ejemplo, un hospital en el que se realizan operaciones de cirugía refractiva a personas
miopes (Hernández Orallo et al.,2004). Obviamente, tales operaciones no están indicadas en muchos
casos, y algunos podrían ser descartados en una primera fase para evitar riesgos potenciales o efectos
secundarios. Aunque la indicación de dicha operación requiere un examen minucioso por parte del servicio
de oftalmología del hospital, hay algunas condiciones que permiten determinar si, en principio, una persona
está indicada para el estudio detallado. La figura 1 muestra un ejemplo de árbol de decisión que se utiliza
para admitir las solicitudes.
Para saber si a un nuevo paciente se le ha de recomendar o no el estudio detallado, bastaría aplicar el
árbol de decisión de la figura, realizando las preguntas de los nodos internos y siguiendo las respuestas
hasta alguna de las hojas del árbol, catalogadas son un “sí” o un “no”.
Una de las grandes ventajas de los árboles de decisión es que las opciones posibles a partir de una
determinada condición son excluyentes, lo que permite analizar una situación y, siguiendo el árbol de
decisión apropiadamente, llegar a una sola acción o decisión a tomar.
Figura 1: Árbol de decisión para determinar la recomendación de cirugía ocular.

El árbol de decisión de la figura en concreto funciona como un clasificador, esto es, dado un nuevo individuo
lo clasificará en una de las dos clases: “sí” o “no”.
Los árboles de decisión que se usan para problemas de clasificación se denominan a menudo “árboles de
clasificación”, y cada nodo terminal contiene una etiqueta que indica la clase predicha de una observación o
vector de características dado. Los árboles de decisión utilizados para problemas de regresión se denominan
frecuentemente “árboles de regresión”, y las etiquetas de los nodos terminales deben ser constantes o
ecuaciones que especifican el valor de salida (output) predicho para una observación o vector de entrada
(input) dado. En este último caso, se suele distinguir entre “árboles de regresión” y “árboles de modelo”,
según que los nodos contengan, respectivamente, constantes o funciones lineales multivariantes.
Un árbol de decisión se denomina binario cuando cada nodo interno tiene exactamente dos hijos. Éstos
son los más usados, debido a su simplicidad, aunque tampoco son infrecuentes los árboles que exhiben
nodos con más de dos hijos. El árbol de la figura anterior se denomina univariante porque sólo un atributo
se ve involucrado en la decisión adoptada en cada nodo. En cambio, los nodos de los árboles de decisión
multivariantes contienen preguntas sobre relaciones que envuelven más de un atributo, por ejemplo,
combinaciones lineales de atributos. Esto les convierte en predictores potencialmente más poderosos, sin
embargo, también son más difíciles de interpretar y más costosos computacionalmente.
En general, el esquema básico de los principales algoritmos de aprendizaje de árboles de decisión consiste
en construir dichos árboles recursivamente siguiendo una estrategia descendente: el espacio de instancias
se va partiendo de arriba abajo, empleando en cada partición una sola variable o atributo (una partición
será entonces un conjunto de condiciones excluyentes y exhaustivas acerca de dicho atributo). Por ello se
emplea el acrónimo TDIDT (Top-Down Induction on Decision Trees) para hacer referencia a la familia de
algoritmos de construcción de árboles de decisión. La inducción top-down de árboles de decisión procede
de acuerdo con la estrategia denominada “divide y vencerás” (divide-and-conquer), donde el conjunto de
entrenamiento (el conjunto de datos usados para construir el árbol) se va partiendo en subconjuntos y el
algoritmo se aplica recursivamente a cada uno de ellos.
Esto supone un enfoque radicalmente diferente al que siguen las técnicas estadísticas tradicionales o las
redes neuronales al abordar el problema de la clasificación. Con éstas se trata de delimitar dos o más
regiones de decisión insertando hipersuperficies más o menos complejas en el espacio n-dimensional que
forman las n variables explicativas. En cambio, mediante la aplicación de algoritmos de inducción de
árboles las regiones de decisión vienen definidas a través de una serie de hiperrectángulos.
Veamos un ejemplo sencillo de cómo operan estas técnicas. Supongamos que tenemos 46 instancias, 26 de

Página 2 de 18
ellas de la clase A y 20 de la clase B, que están caracterizadas por sólo dos variables explicativas, X1 y X2 .
Supongamos que dividimos el conjunto inicial en dos subconjuntos por la condición X1 > 2.5. Todos los
puntos que verifican esa condición son de la clase B, y formarían por tanto un nodo hoja. En cambio,
la condición X1 ≤ 2.5 admite puntos de las dos clases A y B, y no podríamos alcanzar una decisión en
cuanto a la clasificación de los puntos que verifiquen esa condición. Tendríamos que considerar una nueva
partición del subconjunto, y supongamos ahora que la variable seleccionada es X2 y el punto de corte es 2,
con lo que añadiremos dos nuevos nodos al árbol.

Figura 2: Partición del conjunto de instancias.

Figura 3: Árbol de clasificación.

De esta forma recursiva, insertando rectángulos en nuestro espacio bidimensional, vamos construyendo
el árbol de decisión. Por contra, las técnicas tradicionales definirían una superficie de separación (en
nuestro ejemplo, por trabajar sólo en dos dimensiones, una línea). Así, por ejemplo, a través de un análisis
discriminante lineal las dos regiones de decisión vendrían delimitadas por la recta de la figura 4.
Existen muchas metodologías para construir árboles de decisión, pero una de las más antiguas es la
llamada CART (classification and regression tree) desarrollada por Breiman et al. (1984). Es la que utiliza
el paquete rpart de R y en este documento nos centraremos en ella.
Otro de los algoritmos muy utilizado recientemente es el C4.5 de Quinlan (1993), sucesor del id3 también
de Quinlan (1986). Por ejemplo, se puede utilizar con la función J48()del paquete RWeka.

Página 3 de 18
Figura 4: Discriminación clásica con una recta.

Lo que diferencia fundamentalmente entre sí a los distintos algoritmos de “partición” existentes hasta
la fecha es el criterio de selección de particiones. Como ya hemos mencionado, la estructura de árbol
se genera partiendo el conjunto de entrenamiento en subconjuntos más y más pequeños de una manera
recursiva top-down. Comenzando con el conjunto de entrenamiento completo en el nodo raíz, se escoge
una partición y se divide el conjunto en subconjuntos de acuerdo con ella. Recursivamente se va partiendo
cada uno de los subconjuntos obtenidos hasta que todos ellos son “puros” o hasta que su pureza ya no
pueda incrementarse. Un subconjunto es puro si las instancias que contiene son de una misma clase. El
objetivo es alcanzar el máximo grado de pureza usando el menor número de particiones posible de manera
que el árbol resultante sea pequeño y el número de instancias de cada subconjunto, grande.
La mayoría de métodos de construcción de árboles de decisión son algoritmos “voraces” (greedy), en el
sentido de que, en cada etapa, escogen la que consideran mejor opción en ese momento y no vuelven
atrás. Es decir, una vez elegida la partición continúan hacia abajo la construcción del árbol y no vuelven a
plantearse las particiones ya construidas. Por ello resulta esencial un criterio de selección de particiones que
permita realizar una buena elección de la partición más prometedora sin demasiado esfuerzo computacional,
ya que una mala elección de la partición, especialmente en las partes superiores del árbol, tendrá como
consecuencia una degradación muy acusada en la calidad del mismo.
Durante las dos últimas décadas se han presentado diversos criterios de partición, tales como el índice de
Gini empleado en CART (Breiman et al., 1984), la ganancia de información (Quinlan, 1986b) o la “razón
de ganancia” (Quinlan, 1993), entre otros. Todos ellos se basan en la idea de utilizar medidas de la pureza
de un nodo para buscar particiones de máxima discriminación, es decir, que den lugar a los nodos más
puros que sea posible, de manera que el algoritmo de aprendizaje vaya seleccionando las particiones que
correspondan al mejor valor del criterio de partición empleado. Como ya hemos señalado, un nodo puro
será aquel al que sólo correspondan casos pertenecientes a una de las clases del problema. La bondad de
una partición vendrá indicada por el decrecimiento de impureza que se consigue con ella. La maximización
de la bondad de una partición equivale, por tanto, a la minimización de la impureza del árbol generado
por dicha partición.

Página 4 de 18
Impureza de Gini

Por defecto, la función rpart() usa la medida de impureza de Gini como medida de la diversidad de
clases en un nodo. Cuanto más alto sea el índice de Gini, más instancias diferentes dentro del nodo. Este
índice no debe confundirse con el coeficiente de Gini.
En la página de Victor Zhou podemos hallar una sencilla explicación del índice de impureza de Gini.
Utilizado por el algoritmo de CART, la impureza de Gini es una medida de cuán a menudo un elemento
elegido aleatoriamente del conjunto sería etiquetado incorrectamente si fue etiquetado de manera aleatoria
de acuerdo a la distribución de las etiquetas en el subconjunto. La impureza de Gini se puede calcular
sumando la probabilidad de cada elemento siendo elegido multiplicado por la probabilidad de un error en
la categorización de ese elemento. Alcanza su mínimo (cero) cuando todos los casos del nodo corresponden
a una sola categoría de destino.
La entropía es también una medida de impureza muy utilizada y, en particular, es en la que se basan
los algoritmos de Quinlan. Según los experimentos realizados durante los últimos años, parece ser que el
criterio empleado por el algoritmo C4.5 manifiesta un comportamiento ligeramente superior al de Gini.

Los datos del Titanic

Si tiene curiosidad sobre el destino del Titanic, puede ver este video en Youtube. El propósito de este
ejemplo es predecir qué personas tienen más probabilidades de sobrevivir después de la colisión con el
iceberg. El conjunto de datos contiene 13 variables y 1309 observaciones y está ordenado por la variable X.
path <- 'https://raw.githubusercontent.com/thomaspernet/data_csv_r/master/data/titanic_csv.csv'
titanic <- read.csv(path)
str(titanic)

## 'data.frame': 1309 obs. of 13 variables:


## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ pclass : int 1 1 1 1 1 1 1 1 1 1 ...
## $ survived : int 1 1 0 0 0 1 1 0 1 0 ...
## $ name : Factor w/ 1307 levels "Abbing, Mr. Anthony",..: 22 24 25 26 27 31 46 47 51 55 ...
## $ sex : Factor w/ 2 levels "female","male": 1 2 1 2 1 2 1 2 1 2 ...
## $ age : num 29 0.917 2 30 25 ...
## $ sibsp : int 0 1 1 1 1 0 1 0 2 0 ...
## $ parch : int 0 2 2 2 2 0 0 0 0 0 ...
## $ ticket : Factor w/ 929 levels "110152","110413",..: 188 50 50 50 50 125 93 16 77 826 ...
## $ fare : num 211 152 152 152 152 ...
## $ cabin : Factor w/ 187 levels "","A10","A11",..: 45 81 81 81 81 151 147 17 63 1 ...
## $ embarked : Factor w/ 4 levels "","C","Q","S": 4 4 4 4 4 4 4 4 4 2 ...
## $ home.dest: Factor w/ 370 levels "","?Havana, Cuba",..: 310 232 232 232 232 238 163 25 23 230 ...
A continuación vamos a mejorar los datos con algunas medidas de limpieza:
# Drop variables
clean_titanic <- titanic[,-c(1,4,9,11,13)]
# Remove the NA observations
clean_titanic <- clean_titanic[complete.cases(clean_titanic),]
#Convert to factor level
clean_titanic$pclass <- factor(clean_titanic$pclass,

Página 5 de 18
levels = c(1, 2, 3),
labels = c('Upper', 'Middle', 'Lower'))
clean_titanic$survived <- factor(clean_titanic$survived,
levels = c(0, 1),
labels = c('Died', 'Survived'))
dim(clean_titanic)

## [1] 1045 8
El siguiente paso es crear los conjuntos de datos de entrenamiento y de prueba. Lo más habitual en la
práctica es dividir los datos en 80/20, es decir, el 80 % de los datos sirven para construir el modelo y el
20 % para hacer las predicciones y contrastar el resultado.
set.seed(678)
n <- dim(clean_titanic)[1]
idx <- sample(1:n, size = floor(0.8 * n)) # 80% of the data
data_train <- clean_titanic[idx, ]
data_test <- clean_titanic[-idx, ]
dim(data_train)

## [1] 836 8
dim(data_test)

## [1] 209 8
Veamos si la proporción de supervivientes es similar en los dos grupos:
prop.table(table(data_train$survived))

##
## Died Survived
## 0.5885167 0.4114833
prop.table(table(data_test$survived))

##
## Died Survived
## 0.6028708 0.3971292
En los dos grupos la proporción de supervivientes es parecida, sobre el 40 porciento.
library(rpart)
library(rpart.plot)
fit <- rpart(survived~., data = data_train, method = "class")
rpart.plot(fit, extra = 106)

Página 6 de 18
Died
0.41
100%
yes sex = male no

Died Survived
0.22 0.73
62% 38%
age >= 9.5 pclass = Lower

Survived Died
0.58 0.46
4% 15%
sibsp >= 3 fare >= 23

Survived
0.53
13%
age >= 17

Died
0.46
10%
embarked = Q

Survived
0.51
8%
fare >= 7.8

Died
0.46
7%
parch < 1

Died Died Survived Died Died Died Survived Survived Survived Survived
0.19 0.08 0.86 0.06 0.23 0.37 0.65 0.88 0.73 0.91
58% 1% 3% 2% 2% 5% 2% 1% 3% 22%

Empezando por el nodo raíz (la parte superior del gráfico):


1. En la parte superior tenemos la probabilidad general de supervivencia. Muestra la proporción de
pasajeros que sobrevivieron al accidente. El 41 por ciento de los pasajeros sobrevivió.
2. En ese mismo nodo se pregunta si el género del pasajero es masculino. En caso afirmativo, vamos
al nodo secundario izquierdo de la raíz. El 62 por ciento son hombres con una probabilidad de
supervivencia del 22 por ciento.
3. En el segundo nodo (el de la izquierda), se pregunta si el pasajero masculino tiene más de 9.5 años.
Si es así, entonces la probabilidad de supervivencia es del 19 por ciento.
4. Así se puede seguir para comprender qué características afectan la probabilidad de supervivencia.
Entre las muchas cualidades de los árboles de decisión, destaca que requieren muy poca preparación de
datos. En particular, no hace falta la función de escalado o centrado.
En cuanto a la tarea de clasificación, se han señalado varias ventajas de la clasificación basada en árboles
de decisión, entre ellas:
La adquisición de conocimiento a partir de ejemplos preclasificados salva el obstáculo que representa
el adquirir el conocimiento mediante la intervención de un experto humano en el dominio.
Los métodos basados en árboles son exploratorios en lugar de inferenciales. También son no
paramétricos. Al no realizarse hipótesis sobre el modelo y la distribución de los datos, los árboles
pueden modelizar un amplio rango de distribuciones de datos.
La descomposición jerárquica supone un mejor uso de las características disponibles y una mayor
eficiencia computacional en la clasificación.

Página 7 de 18
Al contrario que algunos métodos estadísticos, los árboles de clasificación pueden trabajar de la
misma manera con datos unimodales y multimodales.
Los árboles pueden usarse con la misma facilidad tanto en problemas deterministas como en
problemas incompletos. (En dominios deterministas, la variable dependiente puede ser determinada
perfectamente a partir de las variables independientes, mientras que en problemas incompletos, no.)
Los árboles llevan a cabo la clasificación a través de una secuencia de preguntas simples, fáciles de
entender, cuya semántica es intuitivamente clara para los expertos del dominio. El formalismo de los
árboles de decisión es en sí mismo muy intuitivo y atractivo para el entendimiento.
Por estas y otras razones, la metodología de árboles de decisión puede proporcionar una importante
herramienta en la investigación y práctica en minería de datos. De hecho, muchas herramientas existentes
en esta área se basan en la construcción de árboles de decisión a partir de conjuntos de datos.

Regresión

Los árboles de regresión básica dividen un conjunto de datos en subgrupos más pequeños y luego ajustan
una constante simple para cada observación en el subgrupo. La partición final se logra mediante particiones
binarias sucesivas (también conocidas como partición recursiva) basadas en los diferentes predictores. La
constante para predecir se basa en los valores de respuesta promedio para todas las observaciones que
caen en ese subgrupo.
Por ejemplo, queremos predecir el consumo de combustible (las millas por galón) que un automóvil
promediará en función de los cilindros cyl y los caballos de potencia hp. Todas las observaciones pasan
por este árbol, se evalúan en un nodo en particular y se dirigen a la izquierda si la respuesta es “sí” o
se avanza a la derecha si la respuesta es “no”. Entonces, primero, todas las observaciones que tienen 5
o más cilindros van a la rama izquierda, todas las demás observaciones continúan a la rama derecha. A
continuación, la rama izquierda se divide por los caballos de potencia. Esas observaciones de 5 o más
cilindros con caballos de potencia iguales o mayores a 193 proceden a la rama izquierda; Aquellos con
menos de 193 CV proceden a la derecha. Estas ramas conducen a nodos u hojas terminales que contienen
nuestro valor de respuesta previsto. Básicamente, todas las observaciones (automóviles en este ejemplo)
que no tienen 5 o más cilindros (rama derecha) promedian 27 mpg. Todas las observaciones que tienen 5 o
más cilindros y tienen más de 193 hp (rama izquierda) promedian 13 mpg.
data(mtcars)
fit.mpg <- rpart(mpg ~ cyl + hp, data = mtcars, method = "anova")
rpart.plot(fit.mpg, extra = 0)

Página 8 de 18
20
yes cyl >= 5 no

17
hp >= 193

13 18 27
Este ejemplo sencillo se puede generalizar al caso de una variable respuesta continua Y y dos variables
regresoras X1 y X2 . La partición recursiva nos llevará a tres posibles regiones R1 , R2 y R3 donde el
modelo predecirá Y con una constante ci para cada región Ri de forma que
3
X
Ŷ = ci IRi (x1 , x2 )
i=1

donde IRi es el índicador de pertenencia a la región Ri .


Para hallar la partición final, primero hay que señalar que la partición de las variables se realiza de arriba
hacia abajo y de forma voraz. Esto solo significa que una partición realizada anteriormente en el árbol no
cambiará según las particiones posteriores. Pero, ¿cómo se hacen estas partes? El modelo comienza con el
conjunto de datos completo, S, y busca cada valor distinto de cada variable de entrada para encontrar el
predictor y el valor de división que divide los datos en dos regiones (R1 y R2 ), de modo que la suma total
de los errores al cuadrado se minimizan:
X X
minimizar{SSE = (yi − c1 )2 + (yi − c2 )2 }
R1 R2

Una vez encontrada la mejor división, dividimos los datos en las dos regiones resultantes y repetimos el
proceso de división en cada una de las dos regiones. Este proceso continúa hasta que alcancemos algún
criterio de parada prefijado. El resultado es un árbol generalmente muy profundo y complejo que puede
producir buenas predicciones en el conjunto de entrenamiento, pero que es probable que se adapte muy
bien a esos datos y lleve a un rendimiento deficiente con nuevos datos.
Si utilizamos muestras ligeramente distintas se pueden obtener árboles de decisión donde las primeras
particiones son bastante similares en la parte superior de cada árbol. Sin embargo, tienden a diferir
sustancialmente más cerca de los nodos terminales. Estos nodos más profundos tienden a adaptarse a
atributos específicos de los datos de muestra. En consecuencia, muestras ligeramente diferentes darán
como resultado valores estimados/predichos altamente variables en los nodos terminales. Al eliminar estos
nodos de decisión de nivel inferior, podemos introducir un poco de sesgo en nuestro modelo que ayuda a
estabilizar las predicciones y tenderá a generalizar mejor el modelo para los datos nuevos.
Así pues hay que lograr un equilibrio entre la profundidad y la complejidad del árbol para optimizar el
rendimiento predictivo para datos nuevos. Para encontrar este equilibrio, normalmente se genera un árbol

Página 9 de 18
muy grande como se define en el párrafo anterior y luego lo podamos para encontrar un subárbol óptimo.
Encontramos el subárbol óptimo utilizando un parámetro de complejidad de coste α que penaliza nuestra
función objetivo anterior para el número de nodos terminales del árbol T como se indica en la siguiente
ecuación
minimizar{SSE + αT }

Para un valor dado de α encontraremos el árbol podado más pequeño que tiene el error penalizado más
bajo. Se trata de una forma de regresión regularizada, muy similar a la técnica LASSO. Al igual que con
ese método de regularización, las penalizaciones más pequeñas tienden a producir modelos más complejos,
lo que resulta en árboles más grandes. Mientras que las penalizaciones más grandes dan como resultado
árboles mucho más pequeños. En consecuencia, a medida que un árbol crece, la reducción en el SSE debe
ser mayor que la penalización de la complejidad. Por lo general, se evalúan varios modelos en un rango de
valores para α y se utiliza la validación cruzada para identificar el α óptimo y, por lo tanto, el subárbol
óptimo.

Fortalezas y debilidades

Los árboles de regresión tienen varias ventajas:


Se interpretan con facilidad.
Las predicciones son rápidas (no hay cálculos complicados, solo se buscan constantes en el árbol).
Es fácil entender qué variables son importantes para hacer la predicción. Los nodos internos
(divisiones) son las variables que más reducen en gran medida el SSE.
Si faltan algunos datos, es posible que no podamos bajar todo el camino del árbol a una hoja, pero
aún podemos hacer una predicción al promediar todas las hojas en el subárbol que alcanzamos.
El modelo proporciona una respuesta “irregular” no lineal, por lo que puede funcionar cuando la
verdadera superficie de regresión no es uniforme. Sin embargo, si es lisa, la superficie constante por
partes puede aproximarse de manera arbitraria (con hojas suficientes).
Hay algoritmos rápidos y confiables para aprender estos árboles.
Pero también hay algunas debilidades importantes:
Los árboles de regresión individuales tienen una varianza muy alta, lo que da como resultado
predicciones inestables (una submuestra alternativa de datos de entrenamiento puede cambiar
significativamente los nodos terminales).
Debido a la alta varianza, los árboles de regresión individuales tienen una pobre precisión predictiva.

Implementación básica

Entre bambalinas, la función rpart() aplica automáticamente por defecto un rango de valores α para
podar el árbol y reducir la complejidad. Para comparar el error para cada valor α, rpart() realiza una
validación cruzada de 10 grupos para que el error asociado a un valor α determinado se calcule con los
datos de validación.
En la página de UC Business Analytics R Programming Guide se puede ver un ejemplo de ajuste del
número de hojas terminales con la función rpart().
En ese mismo ejemplo se ajustan los valores del argumento control para los parámetros minsplit y
maxdepth.

Página 10 de 18
minsplit: el número mínimo de observaciones necesarias para intentar una división antes de que se
fuerce la creación de un nodo terminal. El valor predeterminado es 20. Si le damos un valor más
pequeño, los nodos terminales pueden contener solo algunas observaciones para crear el valor de
predicción.
maxdepth: el número máximo de nodos internos entre el nodo raíz y los nodos terminales. El valor
predeterminado es 30, que es bastante generoso y permite la construcción de árboles bastante
grandes.
Consideremos un ejemplo que nos servirá en el siguiente apartado. Se trata de predecir la cantidad de
ozono en el aire en función de la velocidad del viento. Aquí tenemos unos datos y su imagen:
data("airquality")
summary(airquality[,c("Ozone","Wind")])

## Ozone Wind
## Min. : 1.00 Min. : 1.700
## 1st Qu.: 18.00 1st Qu.: 7.400
## Median : 31.50 Median : 9.700
## Mean : 42.13 Mean : 9.958
## 3rd Qu.: 63.25 3rd Qu.:11.500
## Max. :168.00 Max. :20.700
## NA's :37
with(airquality,plot(Wind,Ozone))
150
100
Ozone

50
0

5 10 15 20

Wind
La relacién no es lineal, de manera que un árbol de regresión puede ser efectivo.
Si no lo hemos hecho ya, cargamos en memoria los paquetes rpart y rpart.plot:
library(rpart)
library(rpart.plot)

Página 11 de 18
En primer lugar debemos eliminar las observaciones con datos faltantes.
all.data <- na.omit(airquality[,c("Ozone","Wind")])

Con ellos calculamos un árbol de regresión:


model <- rpart(Ozone ~ Wind, data=all.data)
rpart.plot(model, extra = 0)

42
yes Wind >= 6.6 no

33
Wind >= 8.9

27 48 89
Todas las observaciones pasan por este árbol, se evalúan en un nodo en particular y se dirigen a la izquierda
si la respuesta es “sí” o se avanza a la derecha si la respuesta es “no”.
Dibujamos el modelo de regresión:
with(all.data, plot(Wind,Ozone))
oidx <- order(all.data$Wind)
lines(all.data$Wind[oidx], predict(model)[oidx])

Página 12 de 18
150
100
Ozone

50
0

5 10 15 20

Wind
También podemos ajustar la función rpart() con minsplit = 6:
model <- rpart(Ozone ~ Wind, data=all.data, control = list(minsplit = 6))
with(all.data,plot(Wind,Ozone))
lines(all.data$Wind[oidx], predict(model)[oidx])
150
100
Ozone

50
0

5 10 15 20

Wind

Página 13 de 18
Figura 5: El proceso de bagging.

Bagging

Como ya se ha dicho, uno de los inconvenientes de los árboles de decisión es que los modelos de árbol único
sufren una gran variabilidad. Si bien la poda del árbol ayuda a reducir esta variación, existen métodos
alternativos que realmente explotan la variabilidad de árboles individuales de una manera que puede
mejorar significativamente el rendimiento por encima de los árboles individuales. El bagging (Bootstrap
aggregating) es uno de estos enfoques (propuesto originalmente por Breiman, 1996).
El bagging combina y promedia múltiples modelos. El promedio entre varios árboles reduce la variabilidad
de cualquier árbol y reduce el sobreajuste, lo que mejora el rendimiento predictivo. El bagging sigue tres
simples pasos:
1. Crea M muestras de bootstrap a partir de los datos de entrenamiento. Las muestras bootstrap nos
permiten crear muchos conjuntos de datos ligeramente diferentes pero con la misma distribución
que el conjunto de entrenamiento general.
2. Para cada muestra de bootstrap, calcula un solo árbol de regresión sin afinar.
3. Promedia las predicciones individuales de cada árbol para crear un valor de predicción promedio
general.

Página 14 de 18
Este proceso puede aplicarse a cualquier regresión o modelo de clasificación. Sin embargo, proporciona la
mayor mejora para los modelos que tienen una gran variabilidad. Por ejemplo, los modelos paramétricos
más estables, como la regresión lineal y las splines de regresión multi-adaptativa, no experimentarán una
mejora substancial en el rendimiento predictivo.
Una de las ventajas del bagging es que, en promedio y para muestras grandes, en una muestra bootstrap
solo tenemos el 1 − 1/e = 63.21 % (aprox 2/3) de los datos de entrenamiento (los otros están repetidos).
Esto deja sobre 1/3 de los datos fuera de la muestra bootstrap. Este último conjunto de datos se llama
muestra fuera del saco (out-of-bag o OOB). Así esas observaciones OOB sirven para estimar la precisión
del modelo, creando un proceso natural de validación cruzada.
Ajustar un modelo de árbol con bagging en R es muy sencillo. En lugar de usar la función rpart()
debemos usar ipred::bagging. Utilizaremos coob = TRUE para usar las muestras OOB para estimar el
error.
library(ipred)
fit <- bagging(Ozone ~ Wind, data=all.data, coob=TRUE)
print(fit)

##
## Bagging regression trees with 25 bootstrap replications
##
## Call: bagging.data.frame(formula = Ozone ~ Wind, data = all.data, coob = TRUE)
##
## Out-of-bag estimate of root mean squared error: 25.1007
with(all.data,plot(Wind,Ozone))
lines(all.data$Wind[oidx], predict(fit)[oidx])
150
100
Ozone

50
0

5 10 15 20

Wind
Hacer bagging con ipred es muy simple, sin embargo, también se puede hacer con el paquete caret que

Página 15 de 18
tiene algunas mejoras.
En este documento procederemos ahora a mostrar un método de bagging de forma manual con intención
puramente didactica.

Árboles con bagging (sin llegar a bosque aleatorio o random forest)

Para construir árboles con bagging el procedimiento es muy sencillo. Supongamos que queremos 100
modelos para promediar. Para cada una de las cien iteraciones:
1. Tomaremos una muestra con reemplazamiento de los datos originales.
2. Calcularemos un árbol de regresión con esta muestra
3. Guardaremos el modelo junto con los otros
Una vez tenemos todos los modelos, para obtener una predicción de nuevos datos con el modelo bagging,
necesitamos:
1. Calcular el estimador para cada árbol individual de los guardados.
2. Promediar las estimaciones.

Un ejemplo

En primer lugar, procedemos a dividir los datos en una muestra de entreno (training sample) y una de
prueba (test sample). Ésta última solo es necesaria si queremos comparar los resultados con otros métodos.
Aquí no lo haremos.
set.seed(456)
bagging_data <- all.data
n <- nrow(bagging_data)
train_idx <- sample.int(n,size=round(n*0.8),replace = F)
data_train <- bagging_data[train_idx,]
data_test <- bagging_data[-train_idx,]

El modelo sin bagging:


no_bag_model <- rpart(Ozone~Wind,data_train,control=rpart.control(minsplit=6))

Calculamos y guardamos los 100 modelos:


n_model <- 100
bagged_models <- list()
for (i in 1:n_model)
{
new_sample <- sample(train_idx,size=length(train_idx),replace=T)
bagged_models <- c(bagged_models,list(rpart(Ozone~Wind,data_train[new_sample,],
control=rpart.control(minsplit=6))))
}

Obtenemos la estimación a partir del promedio de los resultados:


bagged_result <- NULL
i <- 0
for (from_bag_model in bagged_models)

Página 16 de 18
{
if (is.null(bagged_result))
bagged_result <- predict(from_bag_model,bagging_data)
else
bagged_result <- (i*bagged_result+predict(from_bag_model,bagging_data))/(i+1)
i <- i+1
}

El gráfico final:
with(data_train,plot(Wind,Ozone,pch=19,col="blue"))
with(data_test,points(Wind,Ozone,pch=19,col="red"))
legend("topright",legend = c("train","test"),col = c("blue","red"),pch = 19)
oidx <- order(bagging_data$Wind)
lines(bagging_data$Wind[oidx], predict(no_bag_model, bagging_data)[oidx],
col="blue", lwd=1.5)
lines(bagging_data$Wind[oidx], bagged_result[oidx],
col="green", lwd=2)

train
120

test
80
Ozone

60
40
20
0

5 10 15 20

Wind
La línea azul es la predicción del modelo sin bagging, mientras que la línea verde es la predicción con
bagging.

Para saber més

Los árboles de decisión proporcionan un tipo de modelo muy intuitivo que tiene varias ventajas. Desgra-
ciadamente, sufren un problema de alta variabilidad. Sin embargo, cuando se combinan con el bagging
podemos minimizar este inconveniente. Además, los árboles con bagging proporcionan la base fundamental
para algoritmos más complejos y potentes, tales como bosques aleatorios (random forest) y máquinas

Página 17 de 18
que aumentan el gradiente (gradient boosting). Para aprender más, se puede trabajar con los siguientes
recursos enumerados en orden de complejidad:
Regression Trees
Decision Tree in R with Example
Machine Learning Explained: Bagging
An Introduction to Statistical Learning
Applied Predictive Modeling
Classification and Regression Trees
The Elements of Statistical Learning
Bagging Predictors

Referencias

Zuleyka Díaz Martínez (2007), Predicción de crisis empresariales en seguros no vida, mediante árboles de
decisión y reglas de clasificación. Universidad Complutense de Madrid.
Regression trees. University of Cincinnati Business Analytics R Programming Guide

Página 18 de 18

También podría gustarte