Hola, y bienvenidos a los árboles de decisión en R. En este cuaderno, veremos qué son los árboles de decisión, para qué se usan y cómo utilizarlos en el entorno R.
Nos morimos de hambre, por lo que cualquier cosa nos parece genial, pero comer uno de esos de manera descuidada puede hacer que nos envenenemos. Para saber si podemos o no podemos comer un hongo, necesitamos ** clasificarlo en función de nuestro conocimiento de sus características **, es decir, tenemos un problema de clasificación en nuestras manos.
Este tipo de problema no es fácil de resolver de manera efectiva, hay muchas variables involucradas en la clasificación correcta de algo. Existen muchos tipos diferentes de modelos matemáticos que se crearon para ayudarnos en las tareas de clasificación. Uno de estos modelos es el ** Modelo de Árbol de Decisión **.
El Árbol de decisiones es un modelo predictivo basado en el análisis de un conjunto de puntos de datos que describen el tipo de objeto que queremos clasificar. En nuestro ejemplo, podría ser un conjunto de observaciones del tipo de tapa de un hongo, su color, olor, forma de su tallo, etc. Estas descripciones de nuestro objeto se denominan ** características ** y son muy importantes en muchos tipos diferentes de algoritmos de aprendizaje automático, incluidos los árboles de decisión. La clasificación que queremos de estas características se deja de lado como un “resultado” de clases.
A partir de este conjunto de observaciones, el algoritmo de creación del árbol de decisión deduce probabilidades: por ejemplo, si muchos hongos que tienen grandes capitalizaciones son venenosos, el algoritmo asumirá que la probabilidad de que los hongos de gran capitalización sean venenosos es alta. Cuando el modelo está completo, tenemos una estructura en forma de árbol compuesta por lo que se llama ** nodos de decisión , que hacen preguntas a nuestros puntos de datos sobre sus características, y nodos de hoja **, que nos dicen qué clasificación toma la decisión Árbol cree que nuestro punto de datos es.
Por lo tanto, si creamos un buen Árbol de decisiones, podemos seguir este tipo de “flujo de trabajo” para averiguar qué es más probable. Por supuesto, no hay forma de estar completamente seguros, pero los árboles de decisión, cuando se crean correctamente, son sorprendentemente efectivos en lo que hacen.
Ahora, la pregunta es: ¿cómo se calculan estas probabilidades?
Revisemos rápidamente algunos términos que pueden aplicarse a los árboles de decisión. Si algunas de estas definiciones no tienen sentido en este momento, no se preocupe, ya que veremos algunos ejemplos que lo aclararán.
Nodo:. En un nodo, tenemos un conjunto de datos que se prueba para un determinado atributo. El objetivo del nodo es dividir el conjunto de datos en un atributo.
Nodo de la hoja: es el nodo terminal en el árbol que predice el resultado.
Root node: aparece en la parte superior del árbol y contiene el conjunto de datos completo de ese árbol.
__ Cómo encontrar la mejor característica en cada nodo para dividir
Entropy: La entropía se calcula para cada nodo. Es la cantidad de trastorno de la información, o la cantidad de aleatoriedad en los datos. La entropía en el nodo depende de la cantidad de datos aleatorios en ese nodo. En el árbol de decisión estamos buscando un árbol que tenga la entropía más pequeña en sus nodos. La entropía se utiliza para calcular la homogeneidad de las muestras en ese nodo. Si las muestras son completamente homogéneas, la entropía es cero y si la muestra está dividida en partes iguales, tiene una entropía de uno. Significa que, si todos los datos en un nodo son venenosos o comestibles, entonces la entropía es cero, pero si la mitad de los datos son venenosos y la otra mitad es comestible, entonces el entropuy es uno. Por ejemplo, para calcular la Entropía de nuestra clase objetivo:
Entropía = - p (comestible) * log (p (comestible)) - p (venenoso) * log (p (venenoso))
__ Ganancia de la información__: Esta es la información recopilada que puede aumentar el nivel de certeza en un predictor particular (atributos). Podemos pensar en la ganancia de información y la entropía como opuestos. A medida que disminuye la entropía, o la cantidad de aleatoriedad, aumenta la ganancia de información, o la cantidad de certeza, y viceversa. Por lo tanto, la construcción de un árbol de decisiones tiene que ver con la búsqueda de indicadores (atributos) que devuelven la mayor ganancia de información.
Algoritmo:
Tenemos nuestro conjunto de datos en el nodo raíz que consta de 4 colores: rojo, azul, verde y amarillo. Hay 4 puntos para cada color, totalizando 16 puntos. Usaremos histogramas para ver la posibilidad de que un punto de datos fuera de la muestra sea de un color determinado (** Clic **).
Ahora que sabemos qué son los árboles de decisión, podemos pasar a crearlos en R. Para empezar, vamos a cargar un conjunto de datos. Para este cuaderno, utilizaremos conjunto de datos `Mushroom`` de UCI para averiguar si hay un hongo Es venenoso o comestible. Como este conjunto de datos no está incorporado en R, debemos descargarlo y cargarlo en R. Para descargar el conjunto de datos, ejecute la celda de código a continuación.
download.file("https://ibm.box.com/shared/static/dpdh09s70abyiwxguehqvcq3dn0m7wve.data", "mushroom.data")
Una vez que haya terminado de descargar el archivo, debemos crear un marco de datos para alojar las observaciones en el conjunto de datos. Dado que el conjunto de datos está estructurado usando valores separados por comas, podemos usar la función read.csv.
mushrooms <- read.csv("mushroom.data", header = F)
head(mushrooms)
## V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20
## 1 p x s n t p f c n k e e s s w w p w o p
## 2 e x s y t a f c b k e c s s w w p w o p
## 3 e b s w t l f c b n e c s s w w p w o p
## 4 p x y w t p f c n n e e s s w w p w o p
## 5 e x s g f n f w b k t e s s w w p w o e
## 6 e x y y t a f c b n e c s s w w p w o p
## V21 V22 V23
## 1 k s u
## 2 n n g
## 3 n n m
## 4 k s u
## 5 n a g
## 6 k n g
Una vez hecho esto, tenemos los datos cargados. Sin embargo, la forma en que está estructurado no es la más intuitiva. En la celda de código a continuación, estamos agregando los nombres de columna al marco de datos con la función colnames
. Además, dado que nuestro marco de datos se compone de * factores *, podemos cambiar el nombre de algunos de estos factores a algo que sea más fácil de entender para nosotros mediante “niveles”.
# Define column names for the mushrooms data frame.
colnames(mushrooms) <- c("Class","cap.shape","cap.surface","cap.color","bruises","odor","gill.attachment","gill.spacing",
"gill.size","gill.color","stalk.shape","stalk.root","stalk.surface.above.ring",
"stalk.surface.below.ring","stalk.color.above.ring","stalk.color.below.ring","veil.type","veil.color",
"ring.number","ring.type","print","population","habitat")
head(mushrooms)
## Class cap.shape cap.surface cap.color bruises odor gill.attachment
## 1 p x s n t p f
## 2 e x s y t a f
## 3 e b s w t l f
## 4 p x y w t p f
## 5 e x s g f n f
## 6 e x y y t a f
## gill.spacing gill.size gill.color stalk.shape stalk.root
## 1 c n k e e
## 2 c b k e c
## 3 c b n e c
## 4 c n n e e
## 5 w b k t e
## 6 c b n e c
## stalk.surface.above.ring stalk.surface.below.ring stalk.color.above.ring
## 1 s s w
## 2 s s w
## 3 s s w
## 4 s s w
## 5 s s w
## 6 s s w
## stalk.color.below.ring veil.type veil.color ring.number ring.type print
## 1 w p w o p k
## 2 w p w o p n
## 3 w p w o p n
## 4 w p w o p k
## 5 w p w o e n
## 6 w p w o p k
## population habitat
## 1 s u
## 2 n g
## 3 n m
## 4 s u
## 5 a g
## 6 n g
# Define the factor names for "Class"
levels(mushrooms$Class) <- c("Edible","Poisonous")
# Define the factor names for "odor"
levels(mushrooms$odor) <- c("Almonds","Anise","Creosote","Fishy","Foul","Musty","None","Pungent","Spicy")
# Define the factor names for "print"
levels(mushrooms$print) <- c("Black","Brown","Buff","Chocolate","Green","Orange","Purple","White","Yellow")
head(mushrooms)
## Class cap.shape cap.surface cap.color bruises odor
## 1 Poisonous x s n t None
## 2 Edible x s y t Almonds
## 3 Edible b s w t Fishy
## 4 Poisonous x y w t None
## 5 Edible x s g f Musty
## 6 Edible x y y t Almonds
## gill.attachment gill.spacing gill.size gill.color stalk.shape stalk.root
## 1 f c n k e e
## 2 f c b k e c
## 3 f c b n e c
## 4 f c n n e e
## 5 f w b k t e
## 6 f c b n e c
## stalk.surface.above.ring stalk.surface.below.ring stalk.color.above.ring
## 1 s s w
## 2 s s w
## 3 s s w
## 4 s s w
## 5 s s w
## 6 s s w
## stalk.color.below.ring veil.type veil.color ring.number ring.type
## 1 w p w o p
## 2 w p w o p
## 3 w p w o p
## 4 w p w o p
## 5 w p w o e
## 6 w p w o p
## print population habitat
## 1 Buff s u
## 2 Chocolate n g
## 3 Chocolate n m
## 4 Buff s u
## 5 Chocolate a g
## 6 Buff n g
Ahora podemos llegar a construir nuestro modelo propiamente dicho. Para los árboles de decisión, vamos a utilizar dos bibliotecas diferentes pero relacionadas: rpart para crear el árbol de decisión y rpart.plot para visualizar nuestro árbol de decisión. Para importar bibliotecas, usamos la función de biblioteca, así:
library(rpart)
library(rpart.plot)
## Warning: package 'rpart.plot' was built under R version 3.5.3
Para crear nuestro modelo de árbol de decisión, podemos usar la función rpart. rpart es fácil de usar: le proporciona una fórmula, le muestra el conjunto de datos que se supone que debe usar y elige un método (ya sea “clase” para la clasificación o “anova” para la regresión). Un gran truco para saber cuando se manejan conjuntos de datos estructurados muy grandes (¡nuestro conjunto de datos tiene más de 20 columnas que queremos usar!) Es que en las declaraciones de fórmulas, se puede usar el. operador como una forma rápida de designar “todas las demás columnas” a R. También puede imprimir el modelo del Árbol de decisiones para recuperar un resumen que lo describa.
# Create a classification decision tree using "Class" as the variable we want to predict and everything else as its predictors.
myDecisionTree <- rpart(Class ~ ., data = mushrooms, method = "class")
# Print out a summary of our created model.
print(myDecisionTree)
## n= 8124
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 8124 3916 Edible (0.51797144 0.48202856)
## 2) odor=Almonds,Fishy,Musty 4328 120 Edible (0.97227357 0.02772643)
## 4) print=Black,Brown,Buff,Chocolate,Green,Purple,White,Yellow 4256 48 Edible (0.98872180 0.01127820) *
## 5) print=Orange 72 0 Poisonous (0.00000000 1.00000000) *
## 3) odor=Anise,Creosote,Foul,None,Pungent,Spicy 3796 0 Poisonous (0.00000000 1.00000000) *
Ahora que tenemos nuestro modelo, podemos dibujarlo para comprender mejor cómo está clasificando los puntos de datos. Podemos usar la función rpart.plot, una función especializada para trazar árboles, para representar nuestro modelo. Esta función adopta algunos parámetros para visualizar el árbol de diferentes maneras: ¡intente cambiar el parámetro de tipo (de 1 a 4) para ver qué sucede!
rpart.plot(myDecisionTree, type = 3, extra = 2, under = TRUE, faclen=5, cex = .75)
Como podemos ver (bajo los resultados de la clasificación), nuestro árbol de decisiones tiene una precisión perfecta al clasificar hongos venenosos, y una precisión casi perfecta cuando se trata de comestibles.
newCase <- mushrooms[10,-1]
newCase
## cap.shape cap.surface cap.color bruises odor gill.attachment
## 10 b s y t Almonds f
## gill.spacing gill.size gill.color stalk.shape stalk.root
## 10 c b g e c
## stalk.surface.above.ring stalk.surface.below.ring
## 10 s s
## stalk.color.above.ring stalk.color.below.ring veil.type veil.color
## 10 w w p w
## ring.number ring.type print population habitat
## 10 o p Buff s m
predict(myDecisionTree, newCase, type = "class")
## 10
## Edible
## Levels: Edible Poisonous
## 75% of the sample size
n <- nrow(mushrooms)
smp_size <- floor(0.75 * n)
## set the seed to make your partition reproductible
set.seed(123)
train_ind <- base::sample(c(1:n), size = smp_size)
mushrooms_train <- mushrooms[train_ind, ]
mushrooms_test <- mushrooms[-train_ind, ]
newDT <- rpart(Class ~ ., data = mushrooms_train, method = "class")
result <- predict(newDT, mushrooms_test[,-1], type = "class")
head(result)
## 2 3 5 10 14 16
## Edible Edible Edible Edible Poisonous Edible
## Levels: Edible Poisonous
head(mushrooms_test$Class)
## [1] Edible Edible Edible Edible Poisonous Edible
## Levels: Edible Poisonous
base::table(mushrooms_test$Class, result)
## result
## Edible Poisonous
## Edible 1049 0
## Poisonous 11 971