JAVIER RUIZ PÉREZ PEC2
Esta práctica se basa en una de las aplicaciones de algoritmos de clasificación, desarrolladas con K-NN y árboles de decisión.
K-NN (o k-vecinos) es un sistema de clasificación basado en la comparación de instancias nuevas con instancias presentes en el juego de datos de entrenamiento. La construcción de grupos se realiza a partir del propio juego de datos de entrenamiento, tomando como referencia el parámetro k indicado por el investigador. El algoritmo de los K vecinos más cercanos es uno de los algoritmos más simples que existen que muestran la esencia del aprendizaje basado en instancias. Este algoritmo asume que todas las instancias corresponden a puntos que se encuentran en un espacio de dimensión n. El vecino más cercano de una instancia es definido en términos de la distancia Euclidiana estándar.
Los árboles de decisión son algoritmos que construyen modelos de decisión que forman estructuras similares a los diagramas de flujo donde los nodos internos suelen ser puntos de decisión sobre un atributo del juego de datos. Son muy dependientes del concepto de ganancia de la información ya que es el criterio que utilizan para construir las ramificaciones del árbol. A grandes rasgos existen dos tipos de árboles de decisión: * Ãrboles de decisión simple: el resultado se construye mediante un proceso de clasificación * Ãrboles de decisión múltiples (random forest): el resultado se construye mediante el desarrollo iterativo de n procesos de clasificación.
Recursos en la web:
A Detailed Introduction to K-Nearest Neighbor (K-NN) Algorithm
Formamos parte de la Dirección Comercial de la Bodega de vinos Mureda y queremos analizar la actividad de nuestra red de ventas, formada por tres categor�??as de comerciales (A, B y C). Para ello, estamos interesados en conocer si existen diferencias en la actividad generada por cada uno de los comerciales y, en caso afirmativo, identificar cuáles son las variables que más contribuyen a dichas diferencias y si podemos predecir a qué categor�??a de comercial pertenece un nuevo empleado en función de su actividad.
Para ello, nuestro equipo de análisis dispone de un fichero con información de 150 clientes que recoge estad�??sticas de actividad de los tres grupos de Comerciales, a razón de 50 registros por grupo de comercial. El fichero contiene información de las siguientes variables:
Importe: Volumen de Facturación en el Cliente (vinculado a un tipo de Comercial)
Margen: Margen por Cliente (vinculado a un tipo de Comercial)
Km: Kilómetros recorridos para visitar al Cliente (por Comercial)
Visitas: Visitas realizadas al Cliente (por Comercial)
Comercial: Grupo de Comerciales (Toma valores A, B ó C)
Una vez definidos los objetivos de nuestra investigación, nuestro departamento de análisis nos propone desarrollar un proceso de clasificación que aplique tres tipos de algoritmos complementarios: K-NN, Ãrboles de decisión simples y Ãrboles de clasificación múltiples (random forest) sobre nuestro fichero de datos.
El código R que utilizaremos en la práctica se divide en apartados según las tareas que iremos realizando:
Apartados práctica:
Carga de paquetes necesarios y fichero
Análisis univariable y bivariable del fichero K-NN
Descriptivos de las variables del fichero
Estudio de la relación entre variables
Comparación de las variables por tipo de Comercial
Clasificación de los clientes con K-NN
Construcción del Modelo de clasificación con K-NN
Validación del Modelo de clasificación con K-NN
Clasificación de los clientes con árboles de decisión simples
Construcción del Modelo de clasificación con el paquete party
Validación del Modelo de clasificación con el paquete party
Construcción del Modelo de clasificación con el paquete rpart
Validación del Modelo de clasificación con el paquete rpart
Clasificación de los clientes con árboles de decisión múltiples (random forest)
Construcción del Modelo de clasificación con el paquete randomForest
Validación del Modelo de clasificación con el paquete randomForest
Empezaremos por cargar los packages R que necesitaremos tener en memoria.
Cargamos también los datos ubicados en el fichero PEC2.csv
#revisamos si es necesario instalar los paquetes necesarios para desarrollar la PEC 2
#install.packages("ggplot2")
#install.packages("party")
#install.packages("rpart.plot")
#install.packages("useful")
#install.packages("randomForest")
#cargamos los paquetes necesarios para desarrollar la PEC 2
# Para representar gráficamente la relación entre variables
library("ggplot2")
# Para clasificar con K-NN
library("class")
# Para clasificar con rpart
library("rpart")
library("rpart.plot")
# Para clasificar con party
library("party")
# Para clasificar con randomForest
library("useful")
library("randomForest")
#cargamos el fichero de datos que utilizamos para desarrollar la PEC 2
nombreruta_PEC2 <- paste(getwd(),"/PEC2.csv", sep = "")
Data_PEC2 <- read.csv(nombreruta_PEC2, encoding="UTF-8",
header=TRUE, sep=",", na.strings="NA", dec=".", strip.white=TRUE)
La primera fase del análisis consiste siempre en un análisis descriptivo de las variables incluidas en el fichero y de la relación existente entre ellas. Para ello, aplicamos la siguiente secuencia de cálculos y representaciones gráficas.
# 1.Calculamos los descriptivos univariables de las variables del fichero
summary(Data_PEC2) #Estad�??sticos descriptivos básicos de las variables
## Ingresos Margen Km Visitas Comercial
## Min. :4300 Min. :200.0 Min. :10.00 Min. : 1.00 A:50
## 1st Qu.:5100 1st Qu.:280.0 1st Qu.:16.00 1st Qu.: 3.00 B:50
## Median :5800 Median :300.0 Median :43.50 Median :13.00 C:50
## Mean :5843 Mean :305.4 Mean :37.59 Mean :11.99
## 3rd Qu.:6400 3rd Qu.:330.0 3rd Qu.:51.00 3rd Qu.:18.00
## Max. :7900 Max. :440.0 Max. :69.00 Max. :25.00
Las 5 variables presentan una distribución bastante homogénea:
Importe: Promedio de 5.843â¬, Máximo 7.900â¬, MÃ???nimo 4.300â¬
Margen: Promedio de 305,4â¬, Máximo 440â¬, MÃ???nimo 200â¬
Km: Promedio de 37,59â¬, Máximo 69â¬, MÃ???nimo 10â¬
Visitas: Promedio de 11,99â¬, Máximo 25â¬, MÃ???nimo 1â¬
Comercial: 50 observaciones por comercial
# 2.Representamos gráficamente las variables del fichero mediante histogramas
#Histograma Ingresos
f1 <- hist(Data_PEC2$Ingresos, main="Histograma Ingresos", col = "gray", labels = TRUE)
f1
## $breaks
## [1] 4000 4500 5000 5500 6000 6500 7000 7500 8000
##
## $counts
## [1] 5 27 27 30 31 18 6 6
##
## $density
## [1] 6.666667e-05 3.600000e-04 3.600000e-04 4.000000e-04 4.133333e-04
## [6] 2.400000e-04 8.000000e-05 8.000000e-05
##
## $mids
## [1] 4250 4750 5250 5750 6250 6750 7250 7750
##
## $xname
## [1] "Data_PEC2$Ingresos"
##
## $equidist
## [1] TRUE
##
## attr(,"class")
## [1] "histogram"
#Histograma Margen
f2 <- hist(Data_PEC2$Margen, main="Histograma Margen", col = "gray", labels = TRUE)
f2
## $breaks
## [1] 200 220 240 260 280 300 320 340 360 380 400 420 440
##
## $counts
## [1] 4 7 13 23 36 25 18 9 9 3 2 1
##
## $density
## [1] 0.0013333333 0.0023333333 0.0043333333 0.0076666667 0.0120000000
## [6] 0.0083333333 0.0060000000 0.0030000000 0.0030000000 0.0010000000
## [11] 0.0006666667 0.0003333333
##
## $mids
## [1] 210 230 250 270 290 310 330 350 370 390 410 430
##
## $xname
## [1] "Data_PEC2$Margen"
##
## $equidist
## [1] TRUE
##
## attr(,"class")
## [1] "histogram"
#Histograma Km
f3 <- hist(Data_PEC2$Km, main="Histograma Km", col = "gray", labels = TRUE)
f3
## $breaks
## [1] 10 15 20 25 30 35 40 45 50 55 60 65 70
##
## $counts
## [1] 37 13 0 1 4 11 21 21 17 16 5 4
##
## $density
## [1] 0.049333333 0.017333333 0.000000000 0.001333333 0.005333333
## [6] 0.014666667 0.028000000 0.028000000 0.022666667 0.021333333
## [11] 0.006666667 0.005333333
##
## $mids
## [1] 12.5 17.5 22.5 27.5 32.5 37.5 42.5 47.5 52.5 57.5 62.5 67.5
##
## $xname
## [1] "Data_PEC2$Km"
##
## $equidist
## [1] TRUE
##
## attr(,"class")
## [1] "histogram"
#Histograma Visitas
f4 <- hist(Data_PEC2$Visitas, main="Histograma Visitas", col = "gray", labels = TRUE)
f4
## $breaks
## [1] 0 2 4 6 8 10 12 14 16 18 20 22 24 26
##
## $counts
## [1] 34 14 2 0 7 8 21 16 14 11 9 11 3
##
## $density
## [1] 0.113333333 0.046666667 0.006666667 0.000000000 0.023333333
## [6] 0.026666667 0.070000000 0.053333333 0.046666667 0.036666667
## [11] 0.030000000 0.036666667 0.010000000
##
## $mids
## [1] 1 3 5 7 9 11 13 15 17 19 21 23 25
##
## $xname
## [1] "Data_PEC2$Visitas"
##
## $equidist
## [1] TRUE
##
## attr(,"class")
## [1] "histogram"
#Histograma Comercial
f5 <- plot(Data_PEC2$Comercial)
f5
## [,1]
## [1,] 0.7
## [2,] 1.9
## [3,] 3.1
Las variables cuantitativas presentan dos distribuciones diferenciadas:
Importe y Margen presentan una distribución similar a una campana de Gauss, algo más concentrada en el caso de Margen
Km y Visitas presentan una distribución muy similar. Con una alta concentración para valores bajos que desciende rápidamente para volver a crecer siguiendo una campana de Gauss a partir del tercer valor de la serie.
# 3.Estudiamos la relación existente entre las variables del fichero
# Estudiamos la relación entre variables mediante gráficos de dispersión
f6<- plot(Data_PEC2)
f6
## NULL
# Estudiamos la relación entre variables cuantitativas mediante correlaciones
cor(Data_PEC2[,c("Ingresos","Margen","Km","Visitas")], use="complete")
## Ingresos Margen Km Visitas
## Ingresos 1.0000000 -0.1093692 0.8717542 0.8179536
## Margen -0.1093692 1.0000000 -0.4205161 -0.3565441
## Km 0.8717542 -0.4205161 1.0000000 0.9627571
## Visitas 0.8179536 -0.3565441 0.9627571 1.0000000
Analizando los gráficos de dispersión, apuntamos una fuerte relación entre Visitas-Km, Ingresos-Km y Ingresos-Visitas que podemos validar con el coeficiente de correlación, estad�??stico que toma valores entre -1 y 1 y que mide la fuerza con la que dos variables quedan interrelacionadas (próximo a 1 cuando la relación es muy fuerte y próximo a -1 cuando la relación es fuerte pero inversa)
Coeficiente de Correlación Visitas-Km -> (0,96)
Coeficiente de Correlación Ingresos-Km -> (0,87)
Coeficiente de Correlación Ingresos-Visitas -> (0,82)
# Estudiamos la relación entre variables Km y Visitas
f7<-ggplot(Data_PEC2, aes(x=Km, y=Visitas)) + geom_point()
f7
# Estudiamos la relación entre variables Km y Visitas con tamaño ingresos
f8<-ggplot(Data_PEC2, aes(x=Km, y=Visitas)) + geom_point(aes(size=Ingresos))
f8
# Relación entre variables Km y Visitas con tamaño margen
f9<-ggplot(Data_PEC2, aes(x=Km, y=Visitas)) + geom_point(aes(size=Margen))
f9
# 3.Estudiamos la existencia de diferencias por Comercial
# promedio variables por comercial
tapply(Data_PEC2$Ingresos,Data_PEC2$Comercial,mean)
## A B C
## 5006 5936 6588
tapply(Data_PEC2$Margen,Data_PEC2$Comercial,mean)
## A B C
## 341.8 277.0 297.4
tapply(Data_PEC2$Km,Data_PEC2$Comercial,mean)
## A B C
## 14.64 42.60 55.52
tapply(Data_PEC2$Visitas,Data_PEC2$Comercial,mean)
## A B C
## 2.44 13.26 20.26
Vemos que existen diferencias remarcables en el promedio de cada una de las variables para cada Comercial:
El Comercial C es el Comercial con un Importe promedio mayor, con una valor ligeramente superior al de B
El Comercial A es el Comercial con un Margen promedio mayor
El Comercial C es el Comercial que hace más Visitas en promedio
El Comercial C es el Comercial que hace más Km en promedio, con un valor que es prácticamente el doble que el del B
Graficamos a continuación las variables cuantitativas diferenciando por Comercial.
# Relación entre variables Km y Visitas con tamaño ingresos y Color según Comercial
f10<-ggplot(Data_PEC2, aes(x=Km, y=Visitas, color=Comercial)) + geom_point(aes(size=Ingresos))
f10
# Relación entre variables Km y Visitas con tamaño ingresos y Color según Comercial, l�??nea tendencia y elipse
f11<-ggplot(Data_PEC2, aes(x=Km, y=Visitas, color=Comercial)) + geom_point(aes(size=Ingresos)) +
geom_smooth(method=lm, aes(fill=Comercial))+ stat_ellipse(type = "norm")
f11
Identificamos un comportamiento diferenciado donde Km y Visitas ya que son las variables que presentan una mayor capacidad de diferenciación.
Una vez analizado descriptivamente el fichero, consideramos necesario evaluar la capacidad predictiva de tres modelos predictivos:
K-Vecino próximo (K-NN)
Ãrboles de decisión simples
Ãrboles de decisión múltiples (random forest)
Con dicho objetivo, aplicaremos los algoritmos siguiendo la siguiente secuencia:
5 Clasificación de los clientes con K-NN
5.1 Construcción del Modelo de clasificación con _K-NN_
5.2 Validación del Modelo de clasificación con _K-NN_
6 Clasificación de los clientes con árboles de decisión simples
6.1 Construcción del Modelo de clasificación con el paquete _party_
6.2 Validación del Modelo de clasificación con el paquete _party_
6.3 Construcción del Modelo de clasificación con el paquete _rpart_
6.4 Validación del Modelo de clasificación con el paquete _rpart_
7 Clasificación de los clientes con árboles de decisión múltiples (random forest)
7.1 Construcción del Modelo de clasificación con el paquete _randomForest_
7.2 Validación del Modelo de clasificación con el paquete _randomForest_
Construimos un juego de datos de entrenamiento con el 70% de registros para construir los modelos y un juego de datos de pruebas con el 30% de registros restantes para validar los modelos.
# Dividimos el fichero en 70% entreno y 30% validación #
set.seed(1234)
ind <- sample(2, nrow(Data_PEC2), replace=TRUE, prob=c(0.7, 0.3))
trainData <- Data_PEC2[ind==1,]
testData <- Data_PEC2[ind==2,]
Aplicamos el modelo K-NN, pasándole como parámetros la matriz de entrenamiento compuesta por las 4 variables cuantitativas : Importe, Margen, Km y Visitas. No le pasamos el campo Comercial porque precisamente es el campo que el algoritmo debe predecir.
Dado que el modelo K-NN permite replicar el modelo para n valores diferentes de k, repetimos el análisis para k=1,2,3 y 4.
# Aplicamos el algoritmo K-NN seleccionando 1 como k inicial
KnnTestPrediccion_k1 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 1, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k1 )
## KnnTestPrediccion_k1
## A B C
## A 10 0 0
## B 0 9 3
## C 0 6 10
# Calculamos el % de aciertos para k=1
sum(KnnTestPrediccion_k1 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 76.31579
# Aplicamos el algoritmo K-NN seleccionando 2 como k inicial
KnnTestPrediccion_k2 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 2, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k2 )
## KnnTestPrediccion_k2
## A B C
## A 10 0 0
## B 2 8 2
## C 0 7 9
# Calculamos el % de aciertos para k=2
sum(KnnTestPrediccion_k2 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 71.05263
# Aplicamos el algoritmo K-NN seleccionando 3 como k inicial
KnnTestPrediccion_k3 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 3, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k3 )
## KnnTestPrediccion_k3
## A B C
## A 10 0 0
## B 2 7 3
## C 0 8 8
# Calculamos el % de aciertos para k=3
# Aplicamos el algoritmo K-NN seleccionando 4 como k inicial
KnnTestPrediccion_k4 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 4, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k4 )
## KnnTestPrediccion_k4
## A B C
## A 9 1 0
## B 2 7 3
## C 0 7 9
# Calculamos el % de aciertos para k=4
sum(KnnTestPrediccion_k4 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 65.78947
Una vez aplicados el algoritmo para k=1,2,3 y 4. Mediante la matriz de confusión valoramos el nivel de acierto del modelo. Con dicho objetivo, estudiamos el % de acierto de cada uno de ellos con el objetivo de escoger el valor de k que permite obtener un % de clasificación correcta más alto:
para k=1 el porcentaje de aciertos es 76%
para k=2 el porcentaje de aciertos es 71%
para k=3 el porcentaje de aciertos es 66%
para k=4 el porcentaje de aciertos es 74%
En consecuencia tomamos el valor k=1 con un 76% de clasificación correcta.
Para construir un árbol de decisión es necesario definir una función que relaciona una variable categórica dependiente (factor) con n variables independientes que pueden ser categóricas o numéricas. En nuestro caso trabajaremos con:
1 variable factor dependiente -> Comercial
4 variables independientes -> Ingresos, Margen, Km y Visitas
El algoritmo de clasificación busca cuál es la variable que permite obtener una submuestra más diferenciada para la variable dependiente (Comercial en nuestro caso) e identifica también qué intervalos (si la variable es cuantitativa) ó agrupación de categor�??as de la/s variable/s independiente/s permitir�??a/n maximizar dicha división.
Una vez identificada la variable independiente que permite obtener la clasificación con una mayor capacidad de diferenciación, el proceso se repite reiterativamente en cada uno de los nodos obtenidos hasta que el algoritmo no encuentra diferencias significativas que le permitan seguir profundizando en los nodos.
Una vez obtenido una primera versión del árbol, existen algoritmos que permiten hacer un podado del árbol (prunning), eliminando aquellas ramas que no acaban de justificar su presencia de acuerdo con algunos parámetros preestablecidos.
En todos los casos seguiremos la siguiente secuencia de pasos para obtener los árboles de clasificación:
Definir la muestra de entrenamiento y la muestra de prueba
Definir la función que relaciona la variable dependiente con las variables independientes
Estimar el árbol de decisión
Representar gráficamente una primera versión del árbol
Estudiar la aplicación práctica del resultado obtenido
Podar el árbol (si el algoritmo admite podado)
Una vez estudiados los datos de manera individual y evaluada la capacidad predictiva del algoritmo K-NN, estudiamos a continuación la capacidad predictiva del árbol de decisión simple, obtenido mediante el paquete party
# Dividimos el fichero en 70% entreno y 30% validación (parte recurrente en todo experimento)
set.seed(1234)
ind <- sample(2, nrow(Data_PEC2), replace=TRUE, prob=c(0.7, 0.3))
trainData <- Data_PEC2[ind==1,]
testData <- Data_PEC2[ind==2,]
#Declaramos función del árbol
ArbolParty <- Comercial ~ Ingresos + Margen + Km + Visitas
#Aplicamos algoritmo
ArbolParty_ctree <- ctree(ArbolParty, data=trainData)
#Obtenemos la relación de reglas de asociación del árbol en formato listado
print(ArbolParty_ctree)
##
## Conditional inference tree with 4 terminal nodes
##
## Response: Comercial
## Inputs: Ingresos, Margen, Km, Visitas
## Number of observations: 112
##
## 1) Km <= 19; criterion = 1, statistic = 104.637
## 2)* weights = 40
## 1) Km > 19
## 3) Visitas <= 17; criterion = 1, statistic = 48.939
## 4) Km <= 44; criterion = 0.974, statistic = 7.397
## 5)* weights = 21
## 4) Km > 44
## 6)* weights = 19
## 3) Visitas > 17
## 7)* weights = 32
#Obtenemos el árbol con un diseño gráfico cuidado
f12<-plot(ArbolParty_ctree)
f12
## NULL
# Validamos la capacidad de predicción del árbol con el fichero de validación
testPredParty <- predict(ArbolParty_ctree, newdata = testData)
table(testPredParty, testData$Comercial)
##
## testPredParty A B C
## A 10 0 0
## B 0 12 2
## C 0 0 14
# Calculamos el % de aciertos
sum(testPredParty == testData$Comercial)/ length(testData$Comercial)*100
## [1] 94.73684
El árbol de decisión obtenido mediante el paquete party clasifica correctamente un 26% de los registros. Un resultado demasiado pobre.
Una vez evaluada la capacidad predictiva del árbol de decisión obtenido con party, estudiamos a continuación la capacidad predictiva del árbol de decisión simple obtenido mediante el paquete rpart
# Dividimos el fichero en 70% entreno y 30% validación (parte recurrente en todo experimento)
set.seed(1234)
ind <- sample(2, nrow(Data_PEC2), replace=TRUE, prob=c(0.7, 0.3))
trainData <- Data_PEC2[ind==1,]
testData <- Data_PEC2[ind==2,]
#Declaramos función del árbol
ArbolRpart <- Comercial ~ Ingresos + Margen + Km + Visitas
#Aplicamos algoritmo
ArbolRpart_ctree <- rpart(ArbolRpart, method="class", data=trainData)
#Obtenemos la relación de reglas de asociación del árbol en formato listado
print(ArbolRpart_ctree) # estadÃ???sticas detalladas de cada nodo
## n= 112
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 112 72 A (0.3571429 0.3392857 0.3035714)
## 2) Km< 24.5 40 0 A (1.0000000 0.0000000 0.0000000) *
## 3) Km>=24.5 72 34 B (0.0000000 0.5277778 0.4722222)
## 6) Visitas< 17.5 40 3 B (0.0000000 0.9250000 0.0750000) *
## 7) Visitas>=17.5 32 1 C (0.0000000 0.0312500 0.9687500) *
#Obtenemos el árbol con un diseño gráfico cuidado
f13<-rpart.plot(ArbolRpart_ctree,extra=4) #visualizamos el árbol
f13
## $obj
## n= 112
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 112 72 A (0.3571429 0.3392857 0.3035714)
## 2) Km< 24.5 40 0 A (1.0000000 0.0000000 0.0000000) *
## 3) Km>=24.5 72 34 B (0.0000000 0.5277778 0.4722222)
## 6) Visitas< 17.5 40 3 B (0.0000000 0.9250000 0.0750000) *
## 7) Visitas>=17.5 32 1 C (0.0000000 0.0312500 0.9687500) *
##
## $snipped.nodes
## NULL
##
## $xlim
## [1] -0.2 1.2
##
## $ylim
## [1] -0.45 1.45
##
## $x
## [1] 0.37107240 0.08029439 0.66185040 0.39750676 0.92619405
##
## $y
## [1] 0.95286077 0.49393924 0.49393924 0.03501771 0.03501771
##
## $branch.x
## [,1] [,2] [,3] [,4] [,5]
## x 0.3710724 0.08029439 0.6618504 0.3975068 0.9261940
## NA 0.31291679 0.4292280 0.6089817 0.7147191
## NA 0.37107240 0.3710724 0.6618504 0.6618504
##
## $branch.y
## [,1] [,2] [,3] [,4] [,5]
## y 0.9621171 0.6221893 0.5031955 0.1632677 0.1632677
## NA 0.9528608 0.9528608 0.4939392 0.4939392
## NA 0.9528608 0.9528608 0.4939392 0.4939392
##
## $labs
## [1] NA "A\n1.00 .00 .00" NA
## [4] "B\n.00 .92 .07" "C\n.00 .03 .97"
##
## $cex
## [1] 1
##
## $boxes
## $boxes$x1
## [1] NA -0.04856926 NA 0.27938175 0.80806904
##
## $boxes$y1
## [1] NA 0.42145010 NA -0.03747143 -0.03747143
##
## $boxes$x2
## [1] NA 0.2091580 NA 0.5156318 1.0443191
##
## $boxes$y2
## [1] NA 0.6221893 NA 0.1632677 0.1632677
##
##
## $split.labs
## [1] ""
##
## $split.cex
## [1] 1
##
## $split.box
## $split.box$x1
## [1] 0.2809872 NA 0.5389527 NA NA
##
## $split.box$y1
## [1] 0.9249803 NA 0.4660588 NA NA
##
## $split.box$x2
## [1] 0.4611576 NA 0.7847481 NA NA
##
## $split.box$y2
## [1] 1.0365021 NA 0.5775806 NA NA
# Estudiamos la evolución del error a medida que el árbol va creciendo
summary(ArbolRpart_ctree) # estadÃ???sticas detalladas de cada nodo
## Call:
## rpart(formula = ArbolRpart, data = trainData, method = "class")
## n= 112
##
## CP nsplit rel error xerror xstd
## 1 0.5277778 0 1.00000000 1.15277778 0.06438675
## 2 0.4166667 1 0.47222222 0.55555556 0.07042952
## 3 0.0100000 2 0.05555556 0.08333333 0.03309688
##
## Variable importance
## Visitas Km Ingresos Margen
## 34 31 21 14
##
## Node number 1: 112 observations, complexity param=0.5277778
## predicted class=A expected loss=0.6428571 P(node) =1
## class counts: 40 38 34
## probabilities: 0.357 0.339 0.304
## left son=2 (40 obs) right son=3 (72 obs)
## Primary splits:
## Km < 24.5 to the left, improve=38.61111, (0 missing)
## Visitas < 8 to the left, improve=38.61111, (0 missing)
## Ingresos < 5450 to the left, improve=27.51111, (0 missing)
## Margen < 305 to the right, improve=16.75806, (0 missing)
## Surrogate splits:
## Visitas < 8 to the left, agree=1.000, adj=1.00, (0 split)
## Ingresos < 5450 to the left, agree=0.929, adj=0.80, (0 split)
## Margen < 335 to the right, agree=0.839, adj=0.55, (0 split)
##
## Node number 2: 40 observations
## predicted class=A expected loss=0 P(node) =0.3571429
## class counts: 40 0 0
## probabilities: 1.000 0.000 0.000
##
## Node number 3: 72 observations, complexity param=0.4166667
## predicted class=B expected loss=0.4722222 P(node) =0.6428571
## class counts: 0 38 34
## probabilities: 0.000 0.528 0.472
## left son=6 (40 obs) right son=7 (32 obs)
## Primary splits:
## Visitas < 17.5 to the left, improve=28.401390, (0 missing)
## Km < 47.5 to the left, improve=25.263500, (0 missing)
## Ingresos < 7050 to the left, improve= 6.469534, (0 missing)
## Margen < 295 to the left, improve= 2.688889, (0 missing)
## Surrogate splits:
## Km < 47.5 to the left, agree=0.917, adj=0.812, (0 split)
## Ingresos < 6350 to the left, agree=0.708, adj=0.344, (0 split)
## Margen < 295 to the left, agree=0.667, adj=0.250, (0 split)
##
## Node number 6: 40 observations
## predicted class=B expected loss=0.075 P(node) =0.3571429
## class counts: 0 37 3
## probabilities: 0.000 0.925 0.075
##
## Node number 7: 32 observations
## predicted class=C expected loss=0.03125 P(node) =0.2857143
## class counts: 0 1 31
## probabilities: 0.000 0.031 0.969
printcp(ArbolRpart_ctree) # estadÃ???sticas de resultados
##
## Classification tree:
## rpart(formula = ArbolRpart, data = trainData, method = "class")
##
## Variables actually used in tree construction:
## [1] Km Visitas
##
## Root node error: 72/112 = 0.64286
##
## n= 112
##
## CP nsplit rel error xerror xstd
## 1 0.52778 0 1.000000 1.152778 0.064387
## 2 0.41667 1 0.472222 0.555556 0.070430
## 3 0.01000 2 0.055556 0.083333 0.033097
plotcp(ArbolRpart_ctree) # evolución del error a medida que se incrementan los nodos
# Validamos la capacidad de predicción del árbol con el fichero de validación
testPredRpart <- predict(ArbolRpart_ctree, newdata = testData, type = "class")
table(testPredRpart, testData$Comercial)
##
## testPredRpart A B C
## A 10 0 0
## B 0 12 2
## C 0 0 14
# Calculamos el % de aciertos
sum(testPredRpart == testData$Comercial)/ length(testData$Comercial)*100
## [1] 94.73684
El árbol de decisión obtenido mediante el paquete rpart clasifica correctamente un 94,73% de los registros. Un resultado bastante alto y aceptable.
Una vez construida una primera versión del árbol, estudiamos la viabilidad de un podado de árbol.
# Podado del árbol
pArbolRpart_ctree<- prune(ArbolRpart_ctree, cp= ArbolRpart_ctree$cptable[which.min(ArbolRpart_ctree$cptable[,"xerror"]),"CP"])
pArbolRpart_ctree<- prune(ArbolRpart_ctree, cp= 0.02)
# Representación del árbol podado
f14<-rpart.plot(pArbolRpart_ctree,extra=4) #visualizamos el árbol
f14
## $obj
## n= 112
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 112 72 A (0.3571429 0.3392857 0.3035714)
## 2) Km< 24.5 40 0 A (1.0000000 0.0000000 0.0000000) *
## 3) Km>=24.5 72 34 B (0.0000000 0.5277778 0.4722222)
## 6) Visitas< 17.5 40 3 B (0.0000000 0.9250000 0.0750000) *
## 7) Visitas>=17.5 32 1 C (0.0000000 0.0312500 0.9687500) *
##
## $snipped.nodes
## NULL
##
## $xlim
## [1] -0.2 1.2
##
## $ylim
## [1] -0.45 1.45
##
## $x
## [1] 0.37107240 0.08029439 0.66185040 0.39750676 0.92619405
##
## $y
## [1] 0.95286077 0.49393924 0.49393924 0.03501771 0.03501771
##
## $branch.x
## [,1] [,2] [,3] [,4] [,5]
## x 0.3710724 0.08029439 0.6618504 0.3975068 0.9261940
## NA 0.31291679 0.4292280 0.6089817 0.7147191
## NA 0.37107240 0.3710724 0.6618504 0.6618504
##
## $branch.y
## [,1] [,2] [,3] [,4] [,5]
## y 0.9621171 0.6221893 0.5031955 0.1632677 0.1632677
## NA 0.9528608 0.9528608 0.4939392 0.4939392
## NA 0.9528608 0.9528608 0.4939392 0.4939392
##
## $labs
## [1] NA "A\n1.00 .00 .00" NA
## [4] "B\n.00 .92 .07" "C\n.00 .03 .97"
##
## $cex
## [1] 1
##
## $boxes
## $boxes$x1
## [1] NA -0.04856926 NA 0.27938175 0.80806904
##
## $boxes$y1
## [1] NA 0.42145010 NA -0.03747143 -0.03747143
##
## $boxes$x2
## [1] NA 0.2091580 NA 0.5156318 1.0443191
##
## $boxes$y2
## [1] NA 0.6221893 NA 0.1632677 0.1632677
##
##
## $split.labs
## [1] ""
##
## $split.cex
## [1] 1
##
## $split.box
## $split.box$x1
## [1] 0.2809872 NA 0.5389527 NA NA
##
## $split.box$y1
## [1] 0.9249803 NA 0.4660588 NA NA
##
## $split.box$x2
## [1] 0.4611576 NA 0.7847481 NA NA
##
## $split.box$y2
## [1] 1.0365021 NA 0.5775806 NA NA
Dado que el árbol original es muy simple. El podado no devuelve ninguna versión nueva reducida.
Una vez evaluada la capacidad predictiva del algoritmo K-NN, y los árboles de decisión simples obtenidos mediante los paquetes party y rpart, estimamos el modelo que obtendr�??amos si ejecutásemos n árboles de decisión simultáneamente (para n=100 en nuestro caso) mediante el algoritmo randomForest.
El algoritmo randomForest es un método de estimación combinado, donde el resultado de la estimación se construye a partir de los resultados obtenidos mediante el cálculo de n árboles donde los predictores son incluidos al azar.
Es un método complejo con ventajas e inconvenientes respecto a los árboles de clasificación simples:
Ventajas
Es uno de los algoritmos de aprendizaje más precisos
Se ejecuta eficientemente en grandes bases de datos
Permite trabajar con cientos de variables independientes sin excluir ninguna
Determina la importancia en la clasificación de cada variable
Recupera eficazmente los valores perdidos de un dataset (missings)
Permite evaluar la ganancia en clasificación obtenida a medida que incrementamos el número de árboles generados en el modelo.
Inconvenientes
A diferencia de los árboles de decisión, la clasificación hecha por random forests es dif�??cil de interpretar
Favorece las variables categóricas que tienen un mayor número de niveles por encima de aquéllas que tienen un número de categor�??a más reducido. Comprometiendo la fiabilidad del modelo para este tipo de datos.
Favorece los grupos más pequeños cuando las variables están correlacionadas
randomForest sobreajusta en ciertos grupos de datos con tareas de clasificación/regresión ruidosas
# Dividimos el fichero en 70% entreno y 30% validación (parte recurrente en todo experimento)
set.seed(1234)
ind <- sample(2, nrow(Data_PEC2), replace=TRUE, prob=c(0.7, 0.3))
trainData <- Data_PEC2[ind==1,]
testData <- Data_PEC2[ind==2,]
#Declaramos función del árbol
ArbolRF <- Comercial ~ Ingresos + Margen + Km + Visitas
#Aplicamos algoritmo
ArbolRF_ctree <- randomForest(ArbolRF, data=trainData, ntree=100,proximity=T) #indicamos el número de árboles mediante ntree=100
#Obtenemos la importancia de cada variable en el proceso de clasificación
importance(ArbolRF_ctree) #Importancia de las variables en formato text
## MeanDecreaseGini
## Ingresos 7.731585
## Margen 1.775483
## Km 28.376887
## Visitas 35.959795
f15<-varImpPlot(ArbolRF_ctree) #Importancia de las variables en formato gráfico
f15
## MeanDecreaseGini
## Ingresos 7.731585
## Margen 1.775483
## Km 28.376887
## Visitas 35.959795
#evolución del error según el número de árboles
f16<-plot(ArbolRF_ctree, main = "")
f16
## OOB A B C
## [1,] 0.04347826 0 0.05882353 0.07142857
## [2,] 0.05714286 0 0.11111111 0.06250000
## [3,] 0.08333333 0 0.10344828 0.16000000
## [4,] 0.08510638 0 0.09375000 0.16666667
## [5,] 0.07920792 0 0.08571429 0.15625000
## [6,] 0.07619048 0 0.08333333 0.14705882
## [7,] 0.07476636 0 0.08333333 0.14705882
## [8,] 0.07407407 0 0.08108108 0.14705882
## [9,] 0.07339450 0 0.07894737 0.14705882
## [10,] 0.06363636 0 0.07894737 0.11764706
## [11,] 0.06363636 0 0.07894737 0.11764706
## [12,] 0.05454545 0 0.07894737 0.08823529
## [13,] 0.05405405 0 0.07894737 0.08823529
## [14,] 0.05357143 0 0.07894737 0.08823529
## [15,] 0.05357143 0 0.07894737 0.08823529
## [16,] 0.05357143 0 0.07894737 0.08823529
## [17,] 0.05357143 0 0.07894737 0.08823529
## [18,] 0.05357143 0 0.07894737 0.08823529
## [19,] 0.05357143 0 0.07894737 0.08823529
## [20,] 0.05357143 0 0.07894737 0.08823529
## [21,] 0.05357143 0 0.07894737 0.08823529
## [22,] 0.05357143 0 0.07894737 0.08823529
## [23,] 0.05357143 0 0.07894737 0.08823529
## [24,] 0.05357143 0 0.07894737 0.08823529
## [25,] 0.05357143 0 0.07894737 0.08823529
## [26,] 0.05357143 0 0.07894737 0.08823529
## [27,] 0.05357143 0 0.07894737 0.08823529
## [28,] 0.05357143 0 0.07894737 0.08823529
## [29,] 0.05357143 0 0.07894737 0.08823529
## [30,] 0.05357143 0 0.07894737 0.08823529
## [31,] 0.05357143 0 0.07894737 0.08823529
## [32,] 0.05357143 0 0.07894737 0.08823529
## [33,] 0.05357143 0 0.07894737 0.08823529
## [34,] 0.05357143 0 0.07894737 0.08823529
## [35,] 0.05357143 0 0.07894737 0.08823529
## [36,] 0.05357143 0 0.07894737 0.08823529
## [37,] 0.05357143 0 0.07894737 0.08823529
## [38,] 0.05357143 0 0.07894737 0.08823529
## [39,] 0.05357143 0 0.07894737 0.08823529
## [40,] 0.04464286 0 0.07894737 0.05882353
## [41,] 0.05357143 0 0.07894737 0.08823529
## [42,] 0.04464286 0 0.07894737 0.05882353
## [43,] 0.04464286 0 0.07894737 0.05882353
## [44,] 0.04464286 0 0.07894737 0.05882353
## [45,] 0.04464286 0 0.07894737 0.05882353
## [46,] 0.04464286 0 0.07894737 0.05882353
## [47,] 0.04464286 0 0.07894737 0.05882353
## [48,] 0.04464286 0 0.07894737 0.05882353
## [49,] 0.05357143 0 0.07894737 0.08823529
## [50,] 0.04464286 0 0.07894737 0.05882353
## [51,] 0.04464286 0 0.07894737 0.05882353
## [52,] 0.04464286 0 0.07894737 0.05882353
## [53,] 0.04464286 0 0.07894737 0.05882353
## [54,] 0.04464286 0 0.07894737 0.05882353
## [55,] 0.04464286 0 0.07894737 0.05882353
## [56,] 0.04464286 0 0.07894737 0.05882353
## [57,] 0.04464286 0 0.07894737 0.05882353
## [58,] 0.04464286 0 0.07894737 0.05882353
## [59,] 0.04464286 0 0.07894737 0.05882353
## [60,] 0.04464286 0 0.07894737 0.05882353
## [61,] 0.04464286 0 0.07894737 0.05882353
## [62,] 0.04464286 0 0.07894737 0.05882353
## [63,] 0.04464286 0 0.07894737 0.05882353
## [64,] 0.04464286 0 0.07894737 0.05882353
## [65,] 0.04464286 0 0.07894737 0.05882353
## [66,] 0.04464286 0 0.07894737 0.05882353
## [67,] 0.04464286 0 0.07894737 0.05882353
## [68,] 0.04464286 0 0.07894737 0.05882353
## [69,] 0.04464286 0 0.07894737 0.05882353
## [70,] 0.04464286 0 0.07894737 0.05882353
## [71,] 0.04464286 0 0.07894737 0.05882353
## [72,] 0.04464286 0 0.07894737 0.05882353
## [73,] 0.04464286 0 0.07894737 0.05882353
## [74,] 0.04464286 0 0.07894737 0.05882353
## [75,] 0.04464286 0 0.07894737 0.05882353
## [76,] 0.04464286 0 0.07894737 0.05882353
## [77,] 0.04464286 0 0.07894737 0.05882353
## [78,] 0.04464286 0 0.07894737 0.05882353
## [79,] 0.04464286 0 0.07894737 0.05882353
## [80,] 0.04464286 0 0.07894737 0.05882353
## [81,] 0.04464286 0 0.07894737 0.05882353
## [82,] 0.04464286 0 0.07894737 0.05882353
## [83,] 0.04464286 0 0.07894737 0.05882353
## [84,] 0.04464286 0 0.07894737 0.05882353
## [85,] 0.04464286 0 0.07894737 0.05882353
## [86,] 0.04464286 0 0.07894737 0.05882353
## [87,] 0.04464286 0 0.07894737 0.05882353
## [88,] 0.04464286 0 0.07894737 0.05882353
## [89,] 0.04464286 0 0.07894737 0.05882353
## [90,] 0.04464286 0 0.07894737 0.05882353
## [91,] 0.04464286 0 0.07894737 0.05882353
## [92,] 0.04464286 0 0.07894737 0.05882353
## [93,] 0.04464286 0 0.07894737 0.05882353
## [94,] 0.04464286 0 0.07894737 0.05882353
## [95,] 0.04464286 0 0.07894737 0.05882353
## [96,] 0.04464286 0 0.07894737 0.05882353
## [97,] 0.04464286 0 0.07894737 0.05882353
## [98,] 0.04464286 0 0.07894737 0.05882353
## [99,] 0.04464286 0 0.07894737 0.05882353
## [100,] 0.04464286 0 0.07894737 0.05882353
# Validamos la capacidad de predicción del árbol con el fichero de validación
testPredRF <- predict(ArbolRF_ctree, newdata = testData)
table(testPredRF, testData$Comercial)
##
## testPredRF A B C
## A 10 0 0
## B 0 12 2
## C 0 0 14
# Calculamos el % de aciertos
sum(testPredRF == testData$Comercial)/ length(testData$Comercial)*100
## [1] 94.73684
El árbol de decisión obtenido mediante el paquete randomForest clasifica correctamente un 94,73% de los registros. Un resultado bastante alto y aceptable.
# Aplicamos el algoritmo K-NN seleccionando 5 como k inicial
KnnTestPrediccion_k5 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 5, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k5)
## KnnTestPrediccion_k5
## A B C
## A 9 1 0
## B 3 8 1
## C 0 7 9
# Calculamos el % de aciertos para k=5
sum(KnnTestPrediccion_k5 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 68.42105
# Aplicamos el algoritmo K-NN seleccionando 6 como k inicial
KnnTestPrediccion_k6 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 6, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k6)
## KnnTestPrediccion_k6
## A B C
## A 9 1 0
## B 3 8 1
## C 0 6 10
# Calculamos el % de aciertos para k=6
sum(KnnTestPrediccion_k6 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 71.05263
# Aplicamos el algoritmo K-NN seleccionando 7 como k inicial
KnnTestPrediccion_k7 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 7, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k7)
## KnnTestPrediccion_k7
## A B C
## A 9 1 0
## B 3 8 1
## C 0 6 10
# Calculamos el % de aciertos para k=7
sum(KnnTestPrediccion_k7 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 71.05263
# Aplicamos el algoritmo K-NN seleccionando 8 como k inicial
KnnTestPrediccion_k8 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 8, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k8)
## KnnTestPrediccion_k8
## A B C
## A 9 1 0
## B 3 7 2
## C 0 6 10
# Calculamos el % de aciertos para k=8
sum(KnnTestPrediccion_k8 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 68.42105
# Aplicamos el algoritmo K-NN seleccionando 9 como k inicial
KnnTestPrediccion_k9 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 9, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k9)
## KnnTestPrediccion_k9
## A B C
## A 9 1 0
## B 3 7 2
## C 0 5 11
# Calculamos el % de aciertos para k=9
sum(KnnTestPrediccion_k9 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 71.05263
# Aplicamos el algoritmo K-NN seleccionando 10 como k inicial
KnnTestPrediccion_k10 <- knn(trainData[,1:4],testData[,1:4], trainData$Comercial , k = 10, prob = TRUE )
table ( testData$Comercial , KnnTestPrediccion_k10)
## KnnTestPrediccion_k10
## A B C
## A 9 1 0
## B 3 7 2
## C 0 5 11
# Calculamos el % de aciertos para k=10
sum(KnnTestPrediccion_k10 == testData$Comercial)/ length(testData$Comercial)*100
## [1] 71.05263
# Al aumentar la k hasta 10, no hemos conseguido superar la capacidad predictiva de k=1. Valores grandes de k reducen el efecto de ruido en la clasificación, pero crean límites entre clases parecidas.
# En el modelo K-NN, utiliza el valor de los k valores más cercanos y ello determina la variable DISTANCIA. La idea que fundamenta este algoritmo es que el nuevo objeto se clasificará en la clase más frecuente de sus K vecinos más próximos. Respecto del peso de las variables cuantitativas, hemos de decir que todas tiene el mismo peso salvo que decidamos otorgar mayor peso a alguna de las variables, en ese caso nos encontraremos frente un caso de Algoritmo K-NN con pesado de variables. Por otra parte, en el caso de valores de k pares, y en que se de la situación en que exista igualdad de casos para cada una de las etiquetas posibles, el resultado se determinará en función de los pesos de cada etiqueta que se atribuyen en función de la distancia al punto que queremos predecir (p.e. método de Shepard).
# En el modelo de clasificación con árboles de decisión simples, el algoritmo busca cuál es la variable más influyente, que permite obtener una submuestra más diferenciada para la variable dependiente, e identifica también qué intervalos ó agrupación de categorías de la/s variable/s independiente/s permitiría/n maximizar dicha división. A partir de esa varible más influyentes, continua estableciendo clasificaciones en funcioón del resto de variables por orden de importancia.
# En el modelo de clasificación con árboles de decisión múltiples, el aldoritmo puede determina la importancia de cada una de las variables. Para ello se utiliza la función importance(ArbolRF_ctree).
# Basándonos en la capacidad predictiva de los tres modelos, los más efectivoso son los modelos rpart y randomForest. De los dos modelos más efectivos, el rpart es bastante más fácil de calcular y de más sencilla interpretación. Por tanto el modelo más decuado para hace predicciones en el actual modelo de trabajo es el ARBOLES DE DECISION SIMPLES, utlizando el paquete RPART.
# SI, ambos modelos están asignado los mismos individuos a cada grupo de Comerciales.
# En los modelos rpart y randomForest se clasifica un total de 38 individuos (A-10 ; B-12; C-16), en cambio en el modelo KNN con K=2, se clasifica el mismo número de individuos, 38, pero con resultados diferentes (A-12; B-15; C-11)
# Clasificación de los 10 nuevos registros:
#Ingresos Margen Km Visitas Comercial
# 6900 310 49 15 B
# 5800 270 41 10 B
# 6800 300 55 21 C
# 5800 270 39 12 B
# 5000 340 15 2 A
# 4600 360 10 2 A
# 5800 270 51 19 C
# 4900 310 15 1 A
# 6100 300 49 18 C
# 6300 290 43 13 B
# Desarolla la solución aplicando las reglas obtenidas en *rpart* en una hoja de cálculo y aplicando los algoritmos sobre el un nuevo fichero de datos que incluya los 160 registros (150 originales + 10 nuevos registros)
#cargamos el fichero de datos que utilizamos para desarrollar la PEC2NR
nombreruta_PEC2 <- paste(getwd(),"/PEC2new.csv", sep = "")
Data_PEC2 <- read.csv(nombreruta_PEC2, encoding="UTF-8", header=TRUE, sep=";", na.strings="NA", dec=".", strip.white=TRUE)
library(rpart)
library(rpart.plot)
# Dividimos el fichero en 70% entreno y 30% validación #
set.seed(1234)
ind <- sample(2, nrow(Data_PEC2), replace=TRUE, prob=c(0.7, 0.3))
trainData <- Data_PEC2[ind==1,]
testData <- Data_PEC2[ind==2,]
#Declaramos función del árbol
ArbolRpart <- Comercial ~ Ingresos + Margen + Km + Visitas
#Aplicamos algoritmo
ArbolRpart_ctree <- rpart(ArbolRpart, method="class", data=trainData)
#Obtenemos la relación de reglas de asociación del árbol en formato listado
print(ArbolRpart_ctree) # estadÃ???sticas detalladas de cada nodo
## n= 119
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 119 76 B (0.35294118 0.36134454 0.28571429)
## 2) Km< 24.5 42 0 A (1.00000000 0.00000000 0.00000000) *
## 3) Km>=24.5 77 34 B (0.00000000 0.55844156 0.44155844)
## 6) Visitas< 16.5 45 2 B (0.00000000 0.95555556 0.04444444) *
## 7) Visitas>=16.5 32 0 C (0.00000000 0.00000000 1.00000000) *
#Obtenemos el árbol con un diseño gráfico cuidado
f13<-rpart.plot(ArbolRpart_ctree,extra=4) #visualizamos el árbol
f13
## $obj
## n= 119
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 119 76 B (0.35294118 0.36134454 0.28571429)
## 2) Km< 24.5 42 0 A (1.00000000 0.00000000 0.00000000) *
## 3) Km>=24.5 77 34 B (0.00000000 0.55844156 0.44155844)
## 6) Visitas< 16.5 45 2 B (0.00000000 0.95555556 0.04444444) *
## 7) Visitas>=16.5 32 0 C (0.00000000 0.00000000 1.00000000) *
##
## $snipped.nodes
## NULL
##
## $xlim
## [1] -0.2 1.2
##
## $ylim
## [1] -0.45 1.45
##
## $x
## [1] 0.36868024 0.07977676 0.65758371 0.39494419 0.92022324
##
## $y
## [1] 0.95286077 0.49393924 0.49393924 0.03501771 0.03501771
##
## $branch.x
## [,1] [,2] [,3] [,4] [,5]
## x 0.3686802 0.07977676 0.6575837 0.3949442 0.9202232
## NA 0.31089954 0.4264609 0.6050558 0.7101116
## NA 0.36868024 0.3686802 0.6575837 0.6575837
##
## $branch.y
## [,1] [,2] [,3] [,4] [,5]
## y 0.9621171 0.6221893 0.5031955 0.1632677 0.1632677
## NA 0.9528608 0.9528608 0.4939392 0.4939392
## NA 0.9528608 0.9528608 0.4939392 0.4939392
##
## $labs
## [1] NA "A\n1.00 .00 .00" NA
## [4] "B\n.00 .96 .04" "C\n.00 .00 1.00"
##
## $cex
## [1] 1
##
## $boxes
## $boxes$x1
## [1] NA -0.04908688 NA 0.27681918 0.79135959
##
## $boxes$y1
## [1] NA 0.42145010 NA -0.03747143 -0.03747143
##
## $boxes$x2
## [1] NA 0.2086404 NA 0.5130692 1.0490869
##
## $boxes$y2
## [1] NA 0.6221893 NA 0.1632677 0.1632677
##
##
## $split.labs
## [1] ""
##
## $split.cex
## [1] 1
##
## $split.box
## $split.box$x1
## [1] 0.278595 NA 0.534686 NA NA
##
## $split.box$y1
## [1] 0.9249803 NA 0.4660588 NA NA
##
## $split.box$x2
## [1] 0.4587655 NA 0.7804815 NA NA
##
## $split.box$y2
## [1] 1.0365021 NA 0.5775806 NA NA
# Estudiamos la evolución del error a medida que el árbol va creciendo
summary(ArbolRpart_ctree) # estadÃ???sticas detalladas de cada nodo
## Call:
## rpart(formula = ArbolRpart, data = trainData, method = "class")
## n= 119
##
## CP nsplit rel error xerror xstd
## 1 0.5526316 0 1.00000000 1.21052632 0.06011581
## 2 0.4210526 1 0.44736842 0.44736842 0.06484281
## 3 0.0100000 2 0.02631579 0.02631579 0.01845104
##
## Variable importance
## Visitas Km Ingresos Margen
## 34 31 20 14
##
## Node number 1: 119 observations, complexity param=0.5526316
## predicted class=B expected loss=0.6386555 P(node) =1
## class counts: 42 43 34
## probabilities: 0.353 0.361 0.286
## left son=2 (42 obs) right son=3 (77 obs)
## Primary splits:
## Km < 24.5 to the left, improve=40.95034, (0 missing)
## Visitas < 8 to the left, improve=40.95034, (0 missing)
## Ingresos < 5450 to the left, improve=27.32013, (0 missing)
## Margen < 305 to the right, improve=17.43176, (0 missing)
## Surrogate splits:
## Visitas < 8 to the left, agree=1.000, adj=1.000, (0 split)
## Ingresos < 5450 to the left, agree=0.916, adj=0.762, (0 split)
## Margen < 335 to the right, agree=0.840, adj=0.548, (0 split)
##
## Node number 2: 42 observations
## predicted class=A expected loss=0 P(node) =0.3529412
## class counts: 42 0 0
## probabilities: 1.000 0.000 0.000
##
## Node number 3: 77 observations, complexity param=0.4210526
## predicted class=B expected loss=0.4415584 P(node) =0.6470588
## class counts: 0 43 34
## probabilities: 0.000 0.558 0.442
## left son=6 (45 obs) right son=7 (32 obs)
## Primary splits:
## Visitas < 16.5 to the left, improve=34.151800, (0 missing)
## Km < 47.5 to the left, improve=27.341100, (0 missing)
## Ingresos < 6150 to the left, improve= 7.022609, (0 missing)
## Margen < 295 to the left, improve= 3.685137, (0 missing)
## Surrogate splits:
## Km < 50.5 to the left, agree=0.909, adj=0.781, (0 split)
## Ingresos < 6350 to the left, agree=0.740, adj=0.375, (0 split)
## Margen < 295 to the left, agree=0.688, adj=0.250, (0 split)
##
## Node number 6: 45 observations
## predicted class=B expected loss=0.04444444 P(node) =0.3781513
## class counts: 0 43 2
## probabilities: 0.000 0.956 0.044
##
## Node number 7: 32 observations
## predicted class=C expected loss=0 P(node) =0.2689076
## class counts: 0 0 32
## probabilities: 0.000 0.000 1.000
printcp(ArbolRpart_ctree) # estadÃ???sticas de resultados
##
## Classification tree:
## rpart(formula = ArbolRpart, data = trainData, method = "class")
##
## Variables actually used in tree construction:
## [1] Km Visitas
##
## Root node error: 76/119 = 0.63866
##
## n= 119
##
## CP nsplit rel error xerror xstd
## 1 0.55263 0 1.000000 1.210526 0.060116
## 2 0.42105 1 0.447368 0.447368 0.064843
## 3 0.01000 2 0.026316 0.026316 0.018451
plotcp(ArbolRpart_ctree) # evolución del error a medida que se incrementan los nodos
# Validamos la capacidad de predicción del árbol con el fichero de validación
testPredRpart <- predict(ArbolRpart_ctree, newdata = testData, type = "class")
table(testPredRpart, testData$Comercial)
##
## testPredRpart A B C
## A 11 0 0
## B 0 9 2
## C 0 2 17
# Calculamos el % de aciertos
sum(testPredRpart == testData$Comercial)/ length(testData$Comercial)*100
## [1] 90.2439