El presente trabajo muestra el desarrollo de algunos de los ejercicios prácticos propuestos en el libro “An Introduction to Statistical Learning with Applications in R”.
library(ggplot2)
library(pROC)
library(e1071)
library(ISLR)
library(ggplot2)
library(MLmetrics)
library(tree)
library(MASS)
library(class)
library(randomForest)
library(tidyverse)
library(glmnet)
library(gbm)
En el siguiente estudio, se presentan resultados analíticos del set de datos Weekly del paquete ISLR, este set de datos contiene los datos del porcentaje de retorno del índice S&P 500 a lo largo de las semanas en 20 años, desde 1990 hasta 2010.
El set de datos contiene las variables año, el retorno porcentual de la semana, 5 variables del retorno porcentual de cada una de las semanas anteriores, una variable volumen (número promedio de acciones comerciadas diariamente, en billones), y finalmente la dirección, que indica si el retorno fue positivo o negativo dicha semana.
head(Weekly)
## Year Lag1 Lag2 Lag3 Lag4 Lag5 Volume Today Direction
## 1 1990 0.816 1.572 -3.936 -0.229 -3.484 0.1549760 -0.270 Down
## 2 1990 -0.270 0.816 1.572 -3.936 -0.229 0.1485740 -2.576 Down
## 3 1990 -2.576 -0.270 0.816 1.572 -3.936 0.1598375 3.514 Up
## 4 1990 3.514 -2.576 -0.270 0.816 1.572 0.1616300 0.712 Up
## 5 1990 0.712 3.514 -2.576 -0.270 0.816 0.1537280 1.178 Up
## 6 1990 1.178 0.712 3.514 -2.576 -0.270 0.1544440 -1.372 Down
El resumen de los datos muestra un promedio de crecimiento porcentual positivo del día de \(0.14\%\), lo que indica que a lo largo del tiempo el porcentaje de retorno del S&P es bastante variable y tiende a mantener un equilibrio entre incremento y disminución del mismo.
La variable ‘Direction’ muestra \(605\) subidas contra \(484\) caídas, lo que indica que a la larga el S&P incrementa su valor en el tiempo.
summary(Weekly)
## Year Lag1 Lag2 Lag3
## Min. :1990 Min. :-18.1950 Min. :-18.1950 Min. :-18.1950
## 1st Qu.:1995 1st Qu.: -1.1540 1st Qu.: -1.1540 1st Qu.: -1.1580
## Median :2000 Median : 0.2410 Median : 0.2410 Median : 0.2410
## Mean :2000 Mean : 0.1506 Mean : 0.1511 Mean : 0.1472
## 3rd Qu.:2005 3rd Qu.: 1.4050 3rd Qu.: 1.4090 3rd Qu.: 1.4090
## Max. :2010 Max. : 12.0260 Max. : 12.0260 Max. : 12.0260
## Lag4 Lag5 Volume Today
## Min. :-18.1950 Min. :-18.1950 Min. :0.08747 Min. :-18.1950
## 1st Qu.: -1.1580 1st Qu.: -1.1660 1st Qu.:0.33202 1st Qu.: -1.1540
## Median : 0.2380 Median : 0.2340 Median :1.00268 Median : 0.2410
## Mean : 0.1458 Mean : 0.1399 Mean :1.57462 Mean : 0.1499
## 3rd Qu.: 1.4090 3rd Qu.: 1.4050 3rd Qu.:2.05373 3rd Qu.: 1.4050
## Max. : 12.0260 Max. : 12.0260 Max. :9.32821 Max. : 12.0260
## Direction
## Down:484
## Up :605
##
##
##
##
En el siguiente Diagrama de Caja se pueden identificar la varianza de los datos en cada año
Los años con una varianza menor se podrían relacionar con años con poca incertidumbre económica, mientras que los años con una varianza mayor podrían relacionarse con años en los que el S&P se comportó de una manera más volátil, un ejemplo de esto es el año 2008, donde ocurrió una crisis financiera y una crisis bursátil mundial
Weekly$YFactor <- as.factor(Weekly$Year) # Año como factor para producir un Box Plot
ggplot(data= Weekly, mapping = aes(x = YFactor, y= Today)) +
geom_boxplot() +
xlab("Año") +
ylab("Porcentaje de Retorno")
La gráfica histórica de los puntos muestra el constante incremento y disminución del porcentaje de retorno, sobresalen los puntos alrededor del año 2008 debido a la crisis financiera ya mencionada.
ggplot(data= Weekly, mapping = aes(x = c(1:length(Year)), y= Today)) +
geom_line() +
geom_point() +
xlab("Registro") +
ylab("Porcentaje de Retorno") +
labs(title="Serie histórica de Porcentaje de Retorno")
Se realiza una gráfica con menos puntos para poder visualizar de una mejor manera.
ggplot(data= Weekly[1:300,], mapping = aes(x = c(1:length(Year)), y= Today)) +
geom_line() +
geom_point() +
xlab("Registro") +
ylab("Porcentaje de Retorno") +
labs(title="Serie histórica de Porcentaje de Retorno")
Se realiza una regresión logística con todos los datos, tienendo como variable respuesta la dirección, las 5 variables de delay (Lag) más el volumen (Volume) como predictores.
weekly_glm <- glm(Direction ~ Lag1+Lag2+Lag3+Lag4+Lag5+Volume,
data= Weekly, family="binomial")
summary(weekly_glm)
##
## Call:
## glm(formula = Direction ~ Lag1 + Lag2 + Lag3 + Lag4 + Lag5 +
## Volume, family = "binomial", data = Weekly)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.6949 -1.2565 0.9913 1.0849 1.4579
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.26686 0.08593 3.106 0.0019 **
## Lag1 -0.04127 0.02641 -1.563 0.1181
## Lag2 0.05844 0.02686 2.175 0.0296 *
## Lag3 -0.01606 0.02666 -0.602 0.5469
## Lag4 -0.02779 0.02646 -1.050 0.2937
## Lag5 -0.01447 0.02638 -0.549 0.5833
## Volume -0.02274 0.03690 -0.616 0.5377
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1496.2 on 1088 degrees of freedom
## Residual deviance: 1486.4 on 1082 degrees of freedom
## AIC: 1500.4
##
## Number of Fisher Scoring iterations: 4
El único predictor que parece ser un estadísticamente significante es la variable Lag2, pero no demuestra mayor significancia.
contrasts(as.factor(Weekly$Direction)) # Nos indica que Down es un 0 y Up es un 1, para interpretar los resultados de la predicción
## Up
## Down 0
## Up 1
La matriz de confusión demuestra que el error más grande son los falsos positivos, en este caso el positivo se da cuando se predice un incremento en el porcentaje de retorno, y el falso es que realmente era un decrecimiento, la matriz de confusión también muestra que el modelo en la mayor parte de los datos predice un incremento, y tan solo alrededor de 100 veces predice una disminución.
predicted <- round(predict(weekly_glm, newdata=Weekly, type="response")) # Predicción
real <- weekly_glm$y # Reales
c_matrix <- ConfusionMatrix(predicted, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted,real)*100, "%"))
## [1] "El porcentaje de aciertos es de 56.106520%"
c_matrix
## y_pred
## y_true 0 1
## 0 54 430
## 1 48 557
Se realiza otra regresión logística, teniendo en cuenta esta vez solamente la variable Lag2, y usando los datos de entrenamiento desde el 1990 hasta el 2008.
weekly_tr <- subset(Weekly, Year <= 2008) # Datos de entrenamiento
weekly_vl <- subset(Weekly, Year > 2008) # Datos de validación
weekly_glm2 <- glm(Direction ~ Lag2, data= weekly_tr, family="binomial")
summary(weekly_glm2)
##
## Call:
## glm(formula = Direction ~ Lag2, family = "binomial", data = weekly_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.536 -1.264 1.021 1.091 1.368
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 0.20326 0.06428 3.162 0.00157 **
## Lag2 0.05810 0.02870 2.024 0.04298 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1354.7 on 984 degrees of freedom
## Residual deviance: 1350.5 on 983 degrees of freedom
## AIC: 1354.5
##
## Number of Fisher Scoring iterations: 4
La matriz de confusión muestra unos resultados similares a los anteriores, en los que el mayor error se presenta en los falsos positivos.
predicted <- round(predict(weekly_glm2, newdata=weekly_vl, type="response")) # Predicción
real <- ifelse(weekly_vl$Direction=="Up",1,0) # Reales
c_matrix2 <- ConfusionMatrix(predicted, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted,real)*100, "%"))
## [1] "El porcentaje de aciertos es de 62.500000%"
c_matrix2
## y_pred
## y_true 0 1
## 0 9 34
## 1 5 56
weekly_lda <- lda(Direction ~ Lag2, data = weekly_tr)
weekly_lda
## Call:
## lda(Direction ~ Lag2, data = weekly_tr)
##
## Prior probabilities of groups:
## Down Up
## 0.4477157 0.5522843
##
## Group means:
## Lag2
## Down -0.03568254
## Up 0.26036581
##
## Coefficients of linear discriminants:
## LD1
## Lag2 0.4414162
Las predicciones realizadas por el LDA son identicas a las realizadas por el GLM.
predicted <- predict(weekly_lda, newdata=weekly_vl) # Predicción
real <- weekly_vl$Direction # Reales
c_matrix_lda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos es de 62.500000%"
c_matrix_lda
## y_pred
## y_true Down Up
## Down 9 34
## Up 5 56
weekly_qda <- qda(Direction ~ Lag2, data = weekly_tr)
weekly_qda
## Call:
## qda(Direction ~ Lag2, data = weekly_tr)
##
## Prior probabilities of groups:
## Down Up
## 0.4477157 0.5522843
##
## Group means:
## Lag2
## Down -0.03568254
## Up 0.26036581
El QDA muestra los peores resultados en terminos de generalidad ya que no marca ninguna disminución.
predicted <- predict(weekly_qda, newdata=weekly_vl) # Predicción
real <- weekly_vl$Direction # Reales
c_matrix_lda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos es de 58.653846%"
c_matrix_lda
## y_pred
## y_true Down Up
## Down 0 43
## Up 0 61
# Preparación de los datos
x_tr <- cbind(weekly_tr$Lag2)
x_vl <- cbind(weekly_vl$Lag2)
y_tr <- weekly_tr$Direction
y_vl <- weekly_vl$Direction
La aproximación por KNN muestra unos resultados más alejados a los otros modelos, y predice correctamente el \(50\%\) de los datos, con más variabilidad entre respuestas de incremento y disminución.
set.seed(2020)
predicted = knn(train = x_tr, test = x_vl, cl = y_tr, k = 1)
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted,y_vl)*100, "%"))
## [1] "El porcentaje de aciertos es de 50.000000%"
table(predicted, y_vl)
## y_vl
## predicted Down Up
## Down 21 30
## Up 22 31
Los modelos lineales (GLM y LDA) son los que demuestran el mejor porcentaje de aciertos, ambos con \(65\) aciertos, aunque con un claro desbalance a predecir incrementos en el porcentaje de retorno. El QDA es el modelo más desbalanceados ya que no predice ni una sola disminución. Por último el modelo de agrupación con KNN muestra los resultados con mejor generalidad ya que tiene una buena cantidad de aciertos \(52\) y estos se reparten en predicciones de incremento y disminución.
Agregar la variable volumen, aunque no aumente el porcentaje de aciertos, si le agrega cierto nivel de variación a las predicciones, ya que se predicen más disminuciones que en las aproximaciones anteriores. Se obtiene el mejor resultado al realizar KNN con \(k=1\) con un \(55\%\) de aciertos, aún así siendo un resultado bastante bajo para un problema de clasificación binaria.
weekly_glm <- glm(Direction ~ Lag2 + Volume, data = weekly_tr,
family = "binomial")
predicted <- round(predict(weekly_glm, newdata = weekly_vl, type="response"))
real <- ifelse(weekly_vl$Direction=="Up",1,0)
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted,real)*100, "%"))
## [1] "El porcentaje de aciertos es de 53.846154%"
ConfusionMatrix(predicted, real)
## y_pred
## y_true 0 1
## 0 20 23
## 1 25 36
weekly_lda <- lda(Direction ~ Lag2 + Volume, data= weekly_tr)
predicted <- predict(weekly_lda, newdata=weekly_vl) # Predicción
real <- weekly_vl$Direction # Reales
c_matrix_lda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos es de 53.846154%"
c_matrix_lda
## y_pred
## y_true Down Up
## Down 20 23
## Up 25 36
weekly_qda <- qda(Direction ~ Lag2 + Volume, data= weekly_tr)
predicted <- predict(weekly_qda, newdata=weekly_vl) # Predicción
real <- weekly_vl$Direction # Reales
c_matrix_lda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos es de 47.115385%"
c_matrix_lda
## y_pred
## y_true Down Up
## Down 32 11
## Up 44 17
# Preparación de los datos
x_tr <- cbind(weekly_tr$Lag2,weekly_tr$Volume)
x_vl <- cbind(weekly_vl$Lag2,weekly_vl$Volume)
y_tr <- weekly_tr$Direction
y_vl <- weekly_vl$Direction
for (k in c(1:10)){
set.seed(2020)
predicted = knn(train = x_tr, test = x_vl, cl = y_tr, k = k)
print(sprintf("El porcentaje de aciertos para k=%i es de %f%s",k,Accuracy(predicted,y_vl)*100, "%"))
}
## [1] "El porcentaje de aciertos para k=1 es de 55.769231%"
## [1] "El porcentaje de aciertos para k=2 es de 54.807692%"
## [1] "El porcentaje de aciertos para k=3 es de 54.807692%"
## [1] "El porcentaje de aciertos para k=4 es de 48.076923%"
## [1] "El porcentaje de aciertos para k=5 es de 52.884615%"
## [1] "El porcentaje de aciertos para k=6 es de 48.076923%"
## [1] "El porcentaje de aciertos para k=7 es de 47.115385%"
## [1] "El porcentaje de aciertos para k=8 es de 50.961538%"
## [1] "El porcentaje de aciertos para k=9 es de 50.000000%"
## [1] "El porcentaje de aciertos para k=10 es de 52.884615%"
KNN con \(k=1\) ha sido el método que ha demostrado el mejor comportamiento, y por ende se seguirá experimentando con el mismo.
El porcentaje de aciertos disminuye al usar todas las variables con KNN \(k=1\).
x_tr <- cbind(weekly_tr$Lag1,weekly_tr$Lag2, weekly_tr$Lag3, weekly_tr$Lag4,weekly_tr$Lag5,weekly_tr$Volume)
x_vl <- cbind(weekly_vl$Lag1,weekly_vl$Lag2, weekly_vl$Lag3, weekly_vl$Lag4,weekly_vl$Lag5,weekly_vl$Volume)
y_tr <- weekly_tr$Direction
y_vl <- weekly_vl$Direction
set.seed(2020)
predicted = knn(train = x_tr, test = x_vl, cl = y_tr, k = 1)
print(sprintf("El porcentaje de aciertos es de %f%s",Accuracy(predicted,y_vl)*100, "%"))
## [1] "El porcentaje de aciertos es de 48.076923%"
ConfusionMatrix(predicted, y_vl)
## y_pred
## y_true Down Up
## Down 21 22
## Up 32 29
Se realiza una comparación del comportamiento del modelo variando los predictores.
y_tr <- weekly_tr$Direction
y_vl <- weekly_vl$Direction
predictors <- c("Lag1", "Lag2", "Lag3", "Lag4", "Lag5")
for (i in predictors){
x_tr <- cbind(weekly_tr[[as.name(i)]], weekly_tr$Volume)
x_vl <- cbind(weekly_vl[[as.name(i)]], weekly_vl$Volume)
set.seed(2020)
predicted = knn(train = x_tr, test = x_vl, cl = y_tr, k = 1)
print(sprintf("El porcentaje de aciertos con el predictor %s es de %f%s",i,Accuracy(predicted,y_vl)*100, "%"))
}
## [1] "El porcentaje de aciertos con el predictor Lag1 es de 52.884615%"
## [1] "El porcentaje de aciertos con el predictor Lag2 es de 55.769231%"
## [1] "El porcentaje de aciertos con el predictor Lag3 es de 46.153846%"
## [1] "El porcentaje de aciertos con el predictor Lag4 es de 45.192308%"
## [1] "El porcentaje de aciertos con el predictor Lag5 es de 51.923077%"
Realizando diversos modelos variando los predictores de delay, se ha encontrado que el modelo más efectivo es el KNN con \(k=1\), utilizando Lag2 y Volume como predictores. Aún así ninguno de los modelos refleja buenos resultados, como máximo se alcanza un \(55\%\), porcentaje bastante bajo para un problema de clasificación binario. Es posible que se necesiten más datos, o sea necesario realizar limpieza en los datos para expulsar los datos anomalos.
En este problema el objetivo es obtener un modelo para predecir si un automóvil obtiene un buen rendimiento de gasolina, basándose en el set de datos Auto.
El dataset cuenta con varios datos acerca de las especificaciones del automóvil, y las millas por galón como el dato que da a entender el rendimiento del carro.
summary(Auto)
## mpg cylinders displacement horsepower weight
## Min. : 9.00 Min. :3.000 Min. : 68.0 Min. : 46.0 Min. :1613
## 1st Qu.:17.00 1st Qu.:4.000 1st Qu.:105.0 1st Qu.: 75.0 1st Qu.:2225
## Median :22.75 Median :4.000 Median :151.0 Median : 93.5 Median :2804
## Mean :23.45 Mean :5.472 Mean :194.4 Mean :104.5 Mean :2978
## 3rd Qu.:29.00 3rd Qu.:8.000 3rd Qu.:275.8 3rd Qu.:126.0 3rd Qu.:3615
## Max. :46.60 Max. :8.000 Max. :455.0 Max. :230.0 Max. :5140
##
## acceleration year origin name
## Min. : 8.00 Min. :70.00 Min. :1.000 amc matador : 5
## 1st Qu.:13.78 1st Qu.:73.00 1st Qu.:1.000 ford pinto : 5
## Median :15.50 Median :76.00 Median :1.000 toyota corolla : 5
## Mean :15.54 Mean :75.98 Mean :1.577 amc gremlin : 4
## 3rd Qu.:17.02 3rd Qu.:79.00 3rd Qu.:2.000 amc hornet : 4
## Max. :24.80 Max. :82.00 Max. :3.000 chevrolet chevette: 4
## (Other) :365
Se procede a crear una variable binaria mpg01 la cuál es verdadera si el mpg es superior a la mediana del mpg a lo largo del dataset, la mediana en este caso es de \(22.75\).
Auto$mpg01 <- (Auto$mpg >= median(Auto$mpg))
median(Auto$mpg)
## [1] 22.75
Efectivamente el ejercicio anterior resulta en una división igualitaria de los autos.
summary(Auto$mpg01)
## Mode FALSE TRUE
## logical 196 196
FALSE indica un \(0\) y TRUE indica un \(1\).
contrasts(as.factor(Auto$mpg01))
## TRUE
## FALSE 0
## TRUE 1
Se realizará un análisis de cada variable contra la variable mpg para decidir cuáles serán los predictores usados en los modelos.
Se realiza una gráfica de puntos agregando la línea roja de la mediana, donde los valores encima o sobre esta tienen un valor de \(mpg01 = 1\) y las que estén por debajo un valor de \(mpg01 = 0\).
La gráfica muestra que para cada número de cilindros es posible tener un buen rendimiento de mpg, destaca que los autos con 4 cilindros tienen más ocurrencias en valores altos de mpg, y los de 8 cilindros en valores bajos, se alcanza a notar una pequeña tendencia a entre más cilindros, peor rendimiento de mpg, pero no es del todo clara.
# Cilindros
ggplot(data = Auto, mapping=aes(x = cylinders, y=mpg)) + geom_point() + geom_line(mapping= aes(x = cylinders,y = median(mpg), col="Mediana")) + labs(title="Comportamiento del No. de Cilindros",x = "Número de Cilindros", y = "Millas por galón", color="Leyenda") + scale_color_manual(values = c("Mediana" = "red"))
En esta gráfica se nota una clara tendencia en la que los vehículos con un desplazamiento más bajo muestran el mejor rendimiento de mpg.
# Displacement
displacement_g <- ggplot(data = Auto, mapping=aes(x = displacement, y=mpg))
displacement_g + geom_point() + geom_line(mapping= aes(x = displacement,y = median(mpg), col="Mediana")) + labs(title="Comportamiento del Desplazamiento" ,x = "Desplazamiento en Pulgadas Cúbicas", y = "Millas por galón", color="Leyenda") + scale_color_manual(values = c("Mediana" = "red"))
Al igual que con el desplazamiento, al tener menos caballos de fuerza mejor es el rendimiento en mpg.
horsepower_g <- ggplot(data = Auto, mapping=aes(x = horsepower, y=mpg))
horsepower_g + geom_point() + geom_line(mapping= aes(x = horsepower,y = median(mpg), col="Mediana")) + labs(title="Comportamiento de los Caballos de Fuerza",x = "Caballos de fuerza", y = "Millas por galón", color="Leyenda") + scale_color_manual(values = c("Mediana" = "red"))
Al igual que el desplazamiento y los caballos de fuerza, los carros más livianos presentan un mejor rendimiento en mpg. Este comportamiento de las 3 variables podría sugerir una correlación de las mismas.
weight_g <- ggplot(data = Auto, mapping=aes(x = weight, y=mpg))
weight_g + geom_point() + geom_line(mapping= aes(x = weight,y = median(mpg), col="Mediana")) + labs(title="Comportamiento de la Masa",x = "Masa del carro en libras", y = "Millas por galón", color="Leyenda") + scale_color_manual(values = c("Mediana" = "red"))
La gráfica no sugiere una relación directa entre el tiempo de aceleración, al menos para los valores entre 11 y 23 segundos, aproximadamente, sin embargo se identifica que los autos que presentan una aceleración de 10 o menos segundos generalmente presentan un mal rendimiento en mpg.
accel_g <- ggplot(data = Auto, mapping=aes(x = acceleration, y=mpg))
accel_g + geom_point() + geom_line(mapping= aes(x = acceleration,y = median(mpg), col="Mediana")) + labs(titile="Comportamiento de la aceleración",x = "Tiempo en segundos para acelerar a 60 mph", y = "Millas por galón", color="Leyenda") + scale_color_manual(values = c("Mediana" = "red"))
La diferenciación por país de origen demuestra una clara diferencia en el rendimiento en mpg, donde los autos americanos presentan el peor, y los europeos y japoneses el mejor.
# Factor de origen
Auto$forigin <- as.factor(Auto$origin)
origin_g <- ggplot(data = Auto, mapping=aes(x = forigin, y=mpg))
origin_g + geom_boxplot() + geom_line(mapping= aes(x = forigin,y = median(mpg), col="Mediana")) + labs(title="Comportamiento del Origen del Automóvil",x = "Origen del Automóvil", y = "Millas por galón", color="Leyenda") + scale_x_discrete(labels = c("1" = "Americano", "2" = "Europeo", "3" = "Japonés"))
Se muestra que a medida que aumenta el año se reduce el mpg, sin embargo no hay una diferenciación absoluta, todos los años tienen al menos un carro con buen rendimiento en mpg y con mal rendimiento en mpg.
year_g <- ggplot(data = Auto, mapping=aes(x = year, y=mpg))
year_g + geom_point() + geom_line(mapping= aes(x = year,y = median(mpg), col="Mediana")) + labs(title="Comportamiento por Año" ,x = "Año", y = "Millas por galón", color="Leyenda") + scale_color_manual(values = c("Mediana" = "red")) + scale_x_continuous(breaks = c(70:82))
La variable de nombre del carro posee muchos niveles y una diferenciación por el mismo no sería del todo buena, ya que no se cuentan con muchos datos.
length(levels(Auto$name))
## [1] 304
Los predictores elegidos según el análisis serán: - Desplazamiento (displacement) - Caballos de fuerza (horsepower) - Masa del vehículo (weight) - Origen del auto (forigin)
formula <- mpg01 ~ displacement + horsepower + weight + forigin
Para la división del set de datos se toma una muestra aleatoria del \(80\%\) para entrenamiento y el \(20\%\) restante para validación.
# Se encuentra el tamaño del set de datos (tomando el 80% para entrenamiento)
sample_size = floor(0.8*nrow(Auto))
set.seed(2020)
# Dividir el set de datos aleatoriamente
picked = sample(seq_len(nrow(Auto)),size = sample_size)
auto_tr =Auto[picked,]
auto_vl =Auto[-picked,]
auto_lda <- lda(formula, data = auto_tr)
auto_lda
## Call:
## lda(formula, data = auto_tr)
##
## Prior probabilities of groups:
## FALSE TRUE
## 0.5111821 0.4888179
##
## Group means:
## displacement horsepower weight forigin2 forigin3
## FALSE 273.8250 130.18125 3634.881 0.0687500 0.0500000
## TRUE 113.3889 78.35294 2312.418 0.2941176 0.3856209
##
## Coefficients of linear discriminants:
## LD1
## displacement -0.006321321
## horsepower 0.005530063
## weight -0.001196922
## forigin2 0.366420649
## forigin3 0.394776068
predicted <- predict(auto_lda, newdata=auto_vl) # Predicción
real <- auto_vl$mpg01 # Reales
c_matrix_lda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos para es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos para es de 87.341772%"
c_matrix_lda
## y_pred
## y_true FALSE TRUE
## FALSE 29 7
## TRUE 3 40
auto_qda <- qda(formula, data = auto_tr)
auto_qda
## Call:
## qda(formula, data = auto_tr)
##
## Prior probabilities of groups:
## FALSE TRUE
## 0.5111821 0.4888179
##
## Group means:
## displacement horsepower weight forigin2 forigin3
## FALSE 273.8250 130.18125 3634.881 0.0687500 0.0500000
## TRUE 113.3889 78.35294 2312.418 0.2941176 0.3856209
predicted <- predict(auto_qda, newdata=auto_vl) # Predicción
real <- auto_vl$mpg01 # Reales
c_matrix_qda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos para es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos para es de 89.873418%"
c_matrix_qda
## y_pred
## y_true FALSE TRUE
## FALSE 30 6
## TRUE 2 41
auto_glm <- glm(formula, data= auto_tr, family="binomial")
summary(auto_glm)
##
## Call:
## glm(formula = formula, family = "binomial", data = auto_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.4910 -0.2100 -0.0057 0.3187 3.3680
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 12.1057415 1.8999057 6.372 1.87e-10 ***
## displacement -0.0101779 0.0081147 -1.254 0.2097
## horsepower -0.0323690 0.0158900 -2.037 0.0416 *
## weight -0.0026066 0.0009031 -2.886 0.0039 **
## forigin2 0.2320536 0.6745525 0.344 0.7308
## forigin3 0.1129592 0.6377234 0.177 0.8594
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 433.75 on 312 degrees of freedom
## Residual deviance: 156.08 on 307 degrees of freedom
## AIC: 168.08
##
## Number of Fisher Scoring iterations: 7
predicted <- round(predict(auto_glm, newdata=auto_vl, type="response")) # Predicción
real <- auto_vl$mpg01 # Reales
c_matrix_glm <- ConfusionMatrix(predicted, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos para es de %f%s", Accuracy(predicted,real)*100, "%"))
## [1] "El porcentaje de aciertos para es de 86.075949%"
c_matrix_glm
## y_pred
## y_true 0 1
## FALSE 29 7
## TRUE 4 39
# Preparación de los datos
x_tr <- cbind(auto_tr$displacement,auto_tr$horsepower, auto_tr$weight, auto_tr$forigin)
x_vl <- cbind(auto_vl$displacement,auto_vl$horsepower, auto_vl$weight, auto_vl$forigin)
y_tr <- auto_tr$mpg01
y_vl <- auto_vl$mpg01
La aproximación por KNN muestra unos resultados más alejados al resto en términos de efectividad, los \(k\) que presentaron el mejor desempeño fueron los \(k = 4\) y \(k = 7\)
set.seed(2020)
for (k in c(1:10)) {
predict = knn(train = x_tr, test = x_vl, cl = y_tr, k = k)
print(sprintf("El porcentaje de aciertos para el k=%i es de %f%s", k, Accuracy(predict,y_vl)*100, "%"))
}
## [1] "El porcentaje de aciertos para el k=1 es de 84.810127%"
## [1] "El porcentaje de aciertos para el k=2 es de 82.278481%"
## [1] "El porcentaje de aciertos para el k=3 es de 82.278481%"
## [1] "El porcentaje de aciertos para el k=4 es de 86.075949%"
## [1] "El porcentaje de aciertos para el k=5 es de 83.544304%"
## [1] "El porcentaje de aciertos para el k=6 es de 84.810127%"
## [1] "El porcentaje de aciertos para el k=7 es de 86.075949%"
## [1] "El porcentaje de aciertos para el k=8 es de 84.810127%"
## [1] "El porcentaje de aciertos para el k=9 es de 83.544304%"
## [1] "El porcentaje de aciertos para el k=10 es de 82.278481%"
El modelo que obtuvo un mejor porcentaje de aciertos fue el del QDA, seguido del LDA, por último la regresión logística y el mejor modelo de KNN obtuvieron el mismo porcentaje de aciertos.
Power <- function(){
print(2^3)
}
Power()
## [1] 8
Power2 <- function(x,a){
print(x^a)
}
Power2(3,8)
## [1] 6561
Power2(10,3)
## [1] 1000
Power2(8,17)
## [1] 2.2518e+15
Power2(131,3)
## [1] 2248091
Power3 <- function(x,a){
return(x^a)
}
plot(x = c(1:10), y = Power3(c(1:10), 2), type = "b", main = "f(x) = x^2", xlab = "x", ylab="y", las = 1)
plot(x = c(1:10), y = Power3(c(1:10), 2), type = "b", main = "f(x) = x^2", xlab = "x", ylab="y", las = 1, log="xy")
PlotPower <- function(x,a){
plot(x = x, y = Power3(x, a), type = "b", main = sprintf("f(x) = x^%i", a), xlab = "x", ylab="y", las = 1)
}
PlotPower(c(1:15), 3)
En el siguiente punto el objetivo es predecir a partir de los datos si un suburbio tiene una tasa de criminalidad superior a la mediana. Se usará el set de datos Boston del paquete MASS.
El dataset cuenta con las siguientes variables:
summary(Boston)
## crim zn indus chas
## Min. : 0.00632 Min. : 0.00 Min. : 0.46 Min. :0.00000
## 1st Qu.: 0.08205 1st Qu.: 0.00 1st Qu.: 5.19 1st Qu.:0.00000
## Median : 0.25651 Median : 0.00 Median : 9.69 Median :0.00000
## Mean : 3.61352 Mean : 11.36 Mean :11.14 Mean :0.06917
## 3rd Qu.: 3.67708 3rd Qu.: 12.50 3rd Qu.:18.10 3rd Qu.:0.00000
## Max. :88.97620 Max. :100.00 Max. :27.74 Max. :1.00000
## nox rm age dis
## Min. :0.3850 Min. :3.561 Min. : 2.90 Min. : 1.130
## 1st Qu.:0.4490 1st Qu.:5.886 1st Qu.: 45.02 1st Qu.: 2.100
## Median :0.5380 Median :6.208 Median : 77.50 Median : 3.207
## Mean :0.5547 Mean :6.285 Mean : 68.57 Mean : 3.795
## 3rd Qu.:0.6240 3rd Qu.:6.623 3rd Qu.: 94.08 3rd Qu.: 5.188
## Max. :0.8710 Max. :8.780 Max. :100.00 Max. :12.127
## rad tax ptratio black
## Min. : 1.000 Min. :187.0 Min. :12.60 Min. : 0.32
## 1st Qu.: 4.000 1st Qu.:279.0 1st Qu.:17.40 1st Qu.:375.38
## Median : 5.000 Median :330.0 Median :19.05 Median :391.44
## Mean : 9.549 Mean :408.2 Mean :18.46 Mean :356.67
## 3rd Qu.:24.000 3rd Qu.:666.0 3rd Qu.:20.20 3rd Qu.:396.23
## Max. :24.000 Max. :711.0 Max. :22.00 Max. :396.90
## lstat medv
## Min. : 1.73 Min. : 5.00
## 1st Qu.: 6.95 1st Qu.:17.02
## Median :11.36 Median :21.20
## Mean :12.65 Mean :22.53
## 3rd Qu.:16.95 3rd Qu.:25.00
## Max. :37.97 Max. :50.00
Se procede a crear una variable binaria crim01 la cuál es verdadera si la tasa de criminalidad es superior a la mediana de la tasa a lo largo del dataset, la mediana en este caso es de \(0.25651\)
Boston$crim01 <- (Boston$crim >= median(Boston$crim))
median(Boston$crim)
## [1] 0.25651
FALSE indica un \(0\) y TRUE indica un \(1\)
contrasts(as.factor(Boston$crim01))
## TRUE
## FALSE 0
## TRUE 1
Para la división del set de datos se toma una muestra aleatoria del \(80\%\) para entrenamiento y el \(20\%\) restante para validación.
# Se encuentra el tamaño del set de datos (tomando el 80% para entrenamiento)
sample_size = floor(0.8*nrow(Boston))
set.seed(2020)
# Dividir el set de datos aleatoriamente
picked = sample(seq_len(nrow(Boston)),size = sample_size)
boston_tr =Boston[picked,]
boston_vl =Boston[-picked,]
Se realizarán diversos modelos con regresión logística, utilizando diferentes sets de predictores, los predictores se separarán según su tipo:
Las variables nox y tax, se incluiran en los modelos finales ya que no se encasillan en ninguno de los grupos
De cada modelo luego se tomaran las variables que presentaron la mayor significancia y estas serán las que se usarán para cada uno de los modelos posteriores.
Las variables con mayor significancia fueron dis,rad, zn.
model_glm1 <- glm(crim01 ~ zn + indus + chas + dis + rad, data = boston_tr, family = "binomial")
summary(model_glm1)
##
## Call:
## glm(formula = crim01 ~ zn + indus + chas + dis + rad, family = "binomial",
## data = boston_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.72341 -0.51300 0.00348 0.00806 2.53603
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.02371 0.87044 -1.176 0.2396
## zn -0.03332 0.01523 -2.188 0.0287 *
## indus 0.03820 0.02808 1.360 0.1738
## chas 0.27502 0.55134 0.499 0.6179
## dis -0.60935 0.12642 -4.820 1.44e-06 ***
## rad 0.54076 0.11702 4.621 3.81e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 560.02 on 403 degrees of freedom
## Residual deviance: 255.65 on 398 degrees of freedom
## AIC: 267.65
##
## Number of Fisher Scoring iterations: 8
predicted <- round(predict(model_glm1, newdata = boston_vl, type = "response"))
real <- boston_vl$crim01
acc <- Accuracy(predicted, real)* 100
print(sprintf("El porcentaje de aciertos fue del %f%s", acc, "%"))
## [1] "El porcentaje de aciertos fue del 81.372549%"
ConfusionMatrix(predicted, real) # Matriz de confusión
## y_pred
## y_true 0 1
## FALSE 44 9
## TRUE 10 39
Para las variables de vivienda, la de mayor significancia fue age.
model_glm2 <- glm(crim01 ~ rm + age + medv, data= boston_tr, family = "binomial")
summary(model_glm2)
##
## Call:
## glm(formula = crim01 ~ rm + age + medv, family = "binomial",
## data = boston_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.9926 -0.6806 0.5119 0.6675 2.7922
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -4.807012 1.417786 -3.391 0.000698 ***
## rm 0.091781 0.252728 0.363 0.716486
## age 0.062754 0.006403 9.801 < 2e-16 ***
## medv -0.007696 0.020459 -0.376 0.706793
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 560.02 on 403 degrees of freedom
## Residual deviance: 378.67 on 400 degrees of freedom
## AIC: 386.67
##
## Number of Fisher Scoring iterations: 5
predicted <- round(predict(model_glm2, newdata = boston_vl, type = "response"))
real <- boston_vl$crim01
acc <- Accuracy(predicted, real)* 100
print(sprintf("El porcentaje de aciertos fue del %f%s", acc, "%"))
## [1] "El porcentaje de aciertos fue del 77.450980%"
ConfusionMatrix(predicted, real) # Matriz de confusión
## y_pred
## y_true 0 1
## FALSE 34 19
## TRUE 4 45
Para las variables poblacionales, las de mayor significancia fueron las variables black y lstat.
model_glm3 <- glm(crim01 ~ ptratio + black + lstat, data = boston_tr, family = "binomial")
summary(model_glm3)
##
## Call:
## glm(formula = crim01 ~ ptratio + black + lstat, family = "binomial",
## data = boston_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.5860 -0.8707 0.0107 0.9099 1.9611
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 5.685163 2.485582 2.287 0.022181 *
## ptratio 0.034861 0.058975 0.591 0.554444
## black -0.021138 0.006211 -3.403 0.000666 ***
## lstat 0.142127 0.023182 6.131 8.74e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 560.02 on 403 degrees of freedom
## Residual deviance: 430.38 on 400 degrees of freedom
## AIC: 438.38
##
## Number of Fisher Scoring iterations: 7
predicted <- round(predict(model_glm3, newdata = boston_vl, type = "response"))
real <- boston_vl$crim01
acc <- Accuracy(predicted, real)* 100
print(sprintf("El porcentaje de aciertos fue del %f%s", acc, "%"))
## [1] "El porcentaje de aciertos fue del 74.509804%"
ConfusionMatrix(predicted, real) # Matriz de confusión
## y_pred
## y_true 0 1
## FALSE 40 13
## TRUE 13 36
Los predictores elegidos serán: - dis - rad - age - black - lstat - nox - tax
Se realiza una regresión logística con los predictores escogidos.
model_glm <- glm(crim01 ~ dis + rad + age + black + lstat + nox + tax, data = boston_tr, family = "binomial")
summary(model_glm)
##
## Call:
## glm(formula = crim01 ~ dis + rad + age + black + lstat + nox +
## tax, family = "binomial", data = boston_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.90854 -0.25996 0.00008 0.00414 2.61963
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -19.450861 4.350661 -4.471 7.79e-06 ***
## dis 0.136719 0.168015 0.814 0.415800
## rad 0.666387 0.133441 4.994 5.92e-07 ***
## age 0.007796 0.010460 0.745 0.456059
## black -0.007433 0.005568 -1.335 0.181947
## lstat 0.004825 0.039166 0.123 0.901955
## nox 39.128187 6.635208 5.897 3.70e-09 ***
## tax -0.009910 0.002701 -3.669 0.000243 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 560.02 on 403 degrees of freedom
## Residual deviance: 190.33 on 396 degrees of freedom
## AIC: 206.33
##
## Number of Fisher Scoring iterations: 8
El porcentaje de aciertos si aumenta respecto a los modelos anteriores, pero se sospecha que es por la inclusión de las variables nox y tax. Se realizará un modelo con todas las variables para ver el contraste.
predicted <- round(predict(model_glm, newdata = boston_vl, type = "response"))
real <- boston_vl$crim01
acc <- Accuracy(predicted, real) * 100
print(sprintf("El porcentaje de aciertos fue del %f%s", acc, "%"))
## [1] "El porcentaje de aciertos fue del 83.333333%"
ConfusionMatrix(predicted, real) # Matriz de confusión
## y_pred
## y_true 0 1
## FALSE 44 9
## TRUE 8 41
A continuación se realiza una regresión logística con todas las variables.
model_glm <- glm(crim01 ~ zn + indus + chas + nox + rm + age + dis + rad + tax + ptratio + black + lstat + medv, data = boston_tr, family = "binomial")
summary(model_glm)
##
## Call:
## glm(formula = crim01 ~ zn + indus + chas + nox + rm + age + dis +
## rad + tax + ptratio + black + lstat + medv, family = "binomial",
## data = boston_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.8878 -0.1486 0.0000 0.0022 3.2456
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -31.498628 6.802443 -4.630 3.65e-06 ***
## zn -0.071444 0.034115 -2.094 0.03624 *
## indus -0.004212 0.053722 -0.078 0.93750
## chas 0.478901 0.807239 0.593 0.55301
## nox 44.803595 8.223846 5.448 5.09e-08 ***
## rm -0.486381 0.778876 -0.624 0.53232
## age 0.016017 0.012749 1.256 0.20900
## dis 0.569745 0.228907 2.489 0.01281 *
## rad 0.725147 0.172624 4.201 2.66e-05 ***
## tax -0.008332 0.003035 -2.745 0.00605 **
## ptratio 0.271237 0.134621 2.015 0.04392 *
## black -0.008655 0.005567 -1.555 0.12001
## lstat 0.068000 0.057365 1.185 0.23586
## medv 0.174126 0.073687 2.363 0.01813 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 560.02 on 403 degrees of freedom
## Residual deviance: 171.87 on 390 degrees of freedom
## AIC: 199.87
##
## Number of Fisher Scoring iterations: 9
El porcentaje de aciertos hasta ahora es el mejor de todos los modelos, sin embargo se realizará un modelo con las variables que parecen tener significancia del modelo.
predicted <- round(predict(model_glm, newdata = boston_vl, type = "response"))
real <- boston_vl$crim01
acc <- Accuracy(predicted, real)* 100
print(sprintf("El porcentaje de aciertos fue del %f%s", acc, "%"))
## [1] "El porcentaje de aciertos fue del 87.254902%"
ConfusionMatrix(predicted, real) # Matriz de confusión
## y_pred
## y_true 0 1
## FALSE 45 8
## TRUE 5 44
model_glm <- glm(crim01 ~ zn + nox + dis + rad + tax + ptratio + medv, data = boston_tr, family = "binomial")
summary(model_glm)
##
## Call:
## glm(formula = crim01 ~ zn + nox + dis + rad + tax + ptratio +
## medv, family = "binomial", data = boston_tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.04249 -0.20026 0.00006 0.00343 3.06622
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -30.508465 5.637643 -5.412 6.25e-08 ***
## zn -0.062811 0.030345 -2.070 0.03846 *
## nox 43.648472 6.933642 6.295 3.07e-10 ***
## dis 0.363455 0.200774 1.810 0.07025 .
## rad 0.682218 0.149559 4.562 5.08e-06 ***
## tax -0.007849 0.002667 -2.943 0.00325 **
## ptratio 0.176106 0.113791 1.548 0.12171
## medv 0.077650 0.033965 2.286 0.02224 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 560.02 on 403 degrees of freedom
## Residual deviance: 181.24 on 396 degrees of freedom
## AIC: 197.24
##
## Number of Fisher Scoring iterations: 9
El porcentaje de aciertos no mejora respecto al modelo con todas las variables, entonces se usarán todas las variables como predictores.
predicted <- round(predict(model_glm, newdata = boston_vl, type = "response"))
real <- boston_vl$crim01
acc <- Accuracy(predicted, real)* 100
print(sprintf("El porcentaje de aciertos fue del %f%s", acc, "%"))
## [1] "El porcentaje de aciertos fue del 85.294118%"
boston_fml <- crim01 ~ zn + indus + chas + nox + rm + age + dis + rad + tax + ptratio + black + lstat + medv
boston_qda <- qda(boston_fml, data = boston_tr)
boston_qda
## Call:
## qda(boston_fml, data = boston_tr)
##
## Prior probabilities of groups:
## FALSE TRUE
## 0.4950495 0.5049505
##
## Group means:
## zn indus chas nox rm age dis
## FALSE 21.770000 6.85325 0.06000000 0.4707995 6.396955 50.81350 5.135899
## TRUE 1.490196 15.20843 0.09313725 0.6369216 6.210858 85.17059 2.496911
## rad tax ptratio black lstat medv
## FALSE 4.1450 306.5650 17.90500 388.4158 9.24765 24.94350
## TRUE 14.7402 506.2353 18.82108 331.0183 15.59593 20.38284
predicted <- predict(boston_qda, newdata=boston_vl) # Predicción
real <- boston_vl$crim01 # Reales
c_matrix_qda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos para es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos para es de 89.215686%"
c_matrix_qda
## y_pred
## y_true FALSE TRUE
## FALSE 51 2
## TRUE 9 40
boston_lda <- lda(boston_fml, data = boston_tr)
boston_lda
## Call:
## lda(boston_fml, data = boston_tr)
##
## Prior probabilities of groups:
## FALSE TRUE
## 0.4950495 0.5049505
##
## Group means:
## zn indus chas nox rm age dis
## FALSE 21.770000 6.85325 0.06000000 0.4707995 6.396955 50.81350 5.135899
## TRUE 1.490196 15.20843 0.09313725 0.6369216 6.210858 85.17059 2.496911
## rad tax ptratio black lstat medv
## FALSE 4.1450 306.5650 17.90500 388.4158 9.24765 24.94350
## TRUE 14.7402 506.2353 18.82108 331.0183 15.59593 20.38284
##
## Coefficients of linear discriminants:
## LD1
## zn -0.0059989846
## indus 0.0354609587
## chas -0.1896438257
## nox 7.8437023277
## rm 0.0522461281
## age 0.0108681241
## dis 0.0339569971
## rad 0.0965538073
## tax -0.0022916846
## ptratio -0.0024566866
## black -0.0006313999
## lstat 0.0172151193
## medv 0.0418635460
predicted <- predict(boston_lda, newdata=boston_vl) # Predicción
real <- boston_vl$crim01 # Reales
c_matrix_lda <- ConfusionMatrix(predicted$class, real) # Matriz de confusión
print(sprintf("El porcentaje de aciertos para es de %f%s", Accuracy(predicted$class,real)*100, "%"))
## [1] "El porcentaje de aciertos para es de 83.333333%"
c_matrix_lda
## y_pred
## y_true FALSE TRUE
## FALSE 48 5
## TRUE 12 37
# Preparación de los datos
x_tr <- cbind(boston_tr)
x_vl <- cbind(boston_vl)
y_tr <- boston_tr$crim01
y_vl <- boston_vl$crim01
El k que genera el mejor porcentaje de aciertos es \(k=4\).
for (k in c(1:10)) {
set.seed(2020)
predict = knn(train = x_tr, test = x_vl, cl = y_tr, k = k)
print(sprintf("El porcentaje de aciertos para el k=%i es de %f%s", k, Accuracy(predict,y_vl)*100, "%"))
}
## [1] "El porcentaje de aciertos para el k=1 es de 93.137255%"
## [1] "El porcentaje de aciertos para el k=2 es de 93.137255%"
## [1] "El porcentaje de aciertos para el k=3 es de 95.098039%"
## [1] "El porcentaje de aciertos para el k=4 es de 96.078431%"
## [1] "El porcentaje de aciertos para el k=5 es de 95.098039%"
## [1] "El porcentaje de aciertos para el k=6 es de 94.117647%"
## [1] "El porcentaje de aciertos para el k=7 es de 94.117647%"
## [1] "El porcentaje de aciertos para el k=8 es de 94.117647%"
## [1] "El porcentaje de aciertos para el k=9 es de 93.137255%"
## [1] "El porcentaje de aciertos para el k=10 es de 94.117647%"
Los resultados del KNN con \(k=4\).
set.seed(2020)
predict = knn(train = x_tr, test = x_vl, cl = y_tr, k = 4)
print(sprintf("El porcentaje de aciertos para el k=%i es de %f%s", 4, Accuracy(predict,y_vl)*100,"%"))
## [1] "El porcentaje de aciertos para el k=4 es de 96.078431%"
table(predict, y_vl)
## y_vl
## predict FALSE TRUE
## FALSE 51 2
## TRUE 2 47
El modelo que presentó la mejor métrica de porcentaje de aciertos fue KNN con \(k=4\), con un \(96\%\). Las otras aproximaciones como el LDA, GLM, QDA presentan un rendimiento más bajo, yendo desde \(83\%\) hasta \(89\%\). Realizando el análisis de predictores con la regresión logística, se definió que todas las variables aportaban un poco de significancia a la predicción, presentando el mejor rendimiento al usar todas las variables en el modelo.
En el laboratorio, aplicamos bosques aleatorios a los datos de Boston usando \(mtry = 6\) y usando \(ntree = 25\) y \(ntree = 500\). Cree un gráfico que muestre el error de prueba resultante de bosques aleatorios en este conjunto de datos para obtener un rango más completo de valores para \(mtry\) y \(ntree\). Puede modelar su diagrama según la Figura 8.10. Describe los resultados obtenidos.
Figura 8.10 (Libro)
Graficamente se puede observar el resultado de bosques aleatorios para el conjunto de datos Boston (Valores de la vivienda en los suburbios de Boston), donde el error de prueba \((MSE)\) se reduce en la medida que se van agregando más árboles y tiende a estabilizarse alredor de \(80\) árboles. El valor de \(m\) representa el número de predictores disponibles para dividir cada nodo del árbol y se llega a la conclusión que entre menor sea el valor de p, es decir \(m<p\) se tiene un menor \(MSE\) y por lo tanto hay una mejora en el modelo.
En el laboratorio, se aplicó un árbol de clasificación al conjunto de datos de Asientos para automóvil después de convertir Ventas en una variable de respuesta cualitativa. Ahora buscaremos predecir las ventas utilizando árboles de regresión y enfoques relacionados, tratando la respuesta como una variable cuantitativa.
Divida el conjunto de datos en un conjunto de entrenamiento y un conjunto de prueba.
set.seed(123456)
train <- sample(dim(Carseats)[1], dim(Carseats)[1]/2)
train_Carseats <- Carseats[train, ]
test_Carseats <- Carseats[-train, ]
Ajuste un árbol de regresión al conjunto de entrenamiento. Trace el árbol e interprete los resultados. ¿Qué tasa de error de prueba obtiene?
##
## Regression tree:
## tree(formula = Sales ~ ., data = train_Carseats)
## Variables actually used in tree construction:
## [1] "ShelveLoc" "Price" "Age" "Income" "CompPrice"
## [6] "Education" "Population" "US"
## Number of terminal nodes: 16
## Residual mean deviance: 2.092 = 385 / 184
## Distribution of residuals:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -3.55400 -1.03000 -0.01708 0.00000 0.94840 3.66700
Del resumen del árbol de regresión ajustado se observa que de las 10 covariables solo \(8\) han sido utilizadas en la construcción del árbol, este árbol proporcioda una suma de cuadrados de los errores de \(184\).
El árbol de regresión contiene \(15\) nodos intermedios y \(16\) nodos terminales, se observa que el nivel Good del factor ShelveLoc no es de importancia y para la división solo se tienen en cuenta los niveles Bad y Medium, cuando este factor esta en Bad se encuentra otro nodo interno, si Price es menor a \(123.5\) se despliegan otros dos nodos intermedios, el de la izquierda relacionado con la variable Age y el de la derecha con CompPrice; si ShelveLoc es Medium se encuentra un nodo interno relacionado con la variable Price, si esta es menor a \(109.5\) se despliegan dos nodos intermedios que involucrans la variable CompPrice y US, cuando esta última es No la predicción para Sales es \(7.499\). La predicción para Sales cuando ShelveLoc es Bad, Price es menor a \(105.5\), Age es menor a \(50\), Price es menor a \(80.5\) es \(9.55\), de manera similar se interpretan las otras predicciones para la variable respuesta Sales.
set.seed(1234)
pred_Carseats <- predict(tree_Carseats, test_Carseats)
paste("El error de prueba es:", mean((test_Carseats$Sales - pred_Carseats)^2))
## [1] "El error de prueba es: 5.0324577229447"
Utilice la validación cruzada para determinar el nivel óptimo de complejidad del árbol. ¿La poda del árbol mejora la tasa de error de prueba?
set.seed(1234)
cv_Carseats <- cv.tree(tree_Carseats, FUN = prune.tree)
El nivel óptimo de complejidad del árbol es de \(8\) nodos terminales, a continuación, se presenta el ajuste del árbol de regresión con \(8\) nodos terminales.
p_Carseats <- prune.tree(tree_Carseats, best = 8)
ppruned <- predict(p_Carseats, test_Carseats)
paste("El error de prueba es:", mean((test_Carseats$Sales - ppruned)^2))
## [1] "El error de prueba es: 4.87611548961474"
esta tsa es menor a la obtenida con el árbol sin podar, es decir que la poda del árbol mejoro el ajuste.
Utilice el método de \(bagging\) para analizar estos datos. Qué tasa de error de prueba que obtiene? Utilice la función de \(importance()\) para determinar qué variables son más importantes.
set.seed(1234)
embolsado_Carseats <- randomForest(Sales ~ ., data = train_Carseats,
mtry = 10, ntree = 500, importance = T)
embolsado_pred <- predict(embolsado_Carseats, test_Carseats)
paste("El error de prueba es:",
mean((test_Carseats$Sales - embolsado_pred)^2))
## [1] "El error de prueba es: 2.98353481792896"
esta tasa de error es mucho menor que el obtenido en los literales anteriores.
importance(embolsado_Carseats)
## %IncMSE IncNodePurity
## CompPrice 24.7104427 181.982752
## Income 10.3732873 115.215011
## Advertising 16.3417929 109.833777
## Population -2.1288904 51.722072
## Price 48.1234357 356.453668
## ShelveLoc 60.2725206 457.515905
## Age 16.0661998 151.183964
## Education 0.7957303 36.296672
## Urban -0.3120038 7.093213
## US 7.1717362 16.766946
Se observa que cuando la Variable ShelveLoc es retirada del modelo el \(MSE\) se incrementa en un \(60.27\%\) y cuando se retira Price dicho \(MSE\) aumenta en \(48.12\%\).
Los resultados indican que en todos los árboles considerados en el bosque aleatorio, el precio que cobra la empresa por los asientos de seguridad en cada sitio (Price) y el que indica la calidad de la ubicación de las estanterías para los asientos del automóvil en cada sitio (ShelveLoc) son las dos variables más importantes.
Utilice bosques aleatorios para analizar estos datos. ¿Qué tasa de error de prueba obtiene? Utilice la función de \(importance()\) para determinar qué variables son más importantes. Describa el efecto de \(m\), el número de variables consideradas en cada división, sobre la tasa de error obtenida.
Para el ajuste se usa \(m=8\) ya que es el valor que disminuye el error de prueba.
bosques_Carseats <- randomForest(Sales ~ ., data = train_Carseats,
mtry = 8, ntree = 500, importance = T)
bosques_pred <- predict(bosques_Carseats, test_Carseats)
paste("El error de prueba es:",
mean((test_Carseats$Sales - bosques_pred)^2))
## [1] "El error de prueba es: 3.01317456599399"
un poco mayor a la obtenida cuando se usa el método de \(bagging\).
importance(bosques_Carseats)
## %IncMSE IncNodePurity
## CompPrice 24.0654029 177.494697
## Income 9.3877917 117.014835
## Advertising 14.5452522 106.266632
## Population 0.2175140 56.304910
## Price 44.9379411 354.508881
## ShelveLoc 62.0919159 430.398167
## Age 17.5754922 152.541774
## Education -0.2325020 40.519237
## Urban 0.3138798 7.102657
## US 7.2092058 19.184242
Se observa que cuando la Variable ShelveLoc es retirada del modelo el \(MSE\) se incrementa en un \(57.76\%\) y cuando se retira Price dicho \(MSE\) aumenta en \(47.20\%\).
Este problema involucra al conjunto de datos de OJ que hace parte del paquete ISLR.
Crear un conjunto de entrenamiento que contenga una muestra aleatoria de \(800\) observaciones, y un conjunto de pruebas que contiene las observaciones restantes.
set.seed(1234)
train <- sample(dim(OJ)[1], 800)
OJtrain <- OJ[train, ]
OJtest <- OJ[-train, ]
Ajustar un árbol a los datos de entrenamiento, con la respuesta “Purchase”. y las otras variables como predictores. Utilice la función \(summary()\) para producir estadísticas resumidas sobre el árbol, y describir la resultados obtenidos. ¿Cuál es la tasa de error de entrenamiento? ¿Cuántos nodos terminales que tiene el árbol?
set.seed(1234)
OJtree <- tree(Purchase ~ ., data = OJtrain)
summary(OJtree)
##
## Classification tree:
## tree(formula = Purchase ~ ., data = OJtrain)
## Variables actually used in tree construction:
## [1] "LoyalCH" "PriceDiff"
## Number of terminal nodes: 7
## Residual mean deviance: 0.7482 = 593.3 / 793
## Misclassification error rate: 0.165 = 132 / 800
Las estadísticas resumidas obtenidas por la función \(summary\) se tiene que el árbol usa \(2\) variables predictoras, las cuales son LoyalCH y PriceDiff. El árbol tiene \(7\) nodos terminales y su tasa de error es de \(0.165\).
Escriba el nombre del objeto de árbol para obtener una salida de texto detallada. Elija uno de los nodos terminales e interprete la información que se muestra.
Se escogió el nodo terminal “3)”. La variable dividida en este nodo es LoyalCH, el valor de division en este nodo es de \(0.48285\) y hay \(498\) puntos en el subarbol debajo de este nodo. La desviación para todos los puntos contenidos en la región por debajo de este nodo es de \(442.3\). La predicción de este nodo es \(Sales=CH\). Alrededor de \(83.735\%\) puntos en este nodo tienen a CH como valor de Sales, el otro \(16.265\%\) restante tienen a MM como valor de Sales.
Crear un gráfico del árbol e interpretar los resultados.
La variable mas importantes del árbol es LoyalCH, estando en los primeros tres nodos del árbol. Si la variable LoyalCH es menor que \(0.26\) el árbol predice MM, si LoyalCH es mayor a \(0.76\) el árbol predice CH.
Predecir la respuesta en los datos de la prueba, y producir una matriz de confusión que compara las etiquetas de prueba con las etiquetas de prueba predichas. ¿Cuál es la tasa de error de la prueba?
set.seed(1234)
OJpred <- predict(OJtree, OJtest, type = "class")
table(OJtest$Purchase, OJpred)
## OJpred
## CH MM
## CH 126 44
## MM 17 83
La tasa de error de prueba es de \(21.11%\).
Aplicar la función \(cv.tree()\) al conjunto de entrenamiento para determinar el tamaño óptimo del árbol.
OJcv = cv.tree(OJtree, FUN = prune.tree)
Elaborar un gráfico con el tamaño del árbol en el eje x y validarlo de forma cruzada con la tasa de error de clasificación en el eje Y.
plot(OJcv$size, OJcv$dev, type = "b", xlab = "Tamaño del árbol", ylab = "Desviación",las=1)
¿Qué tamaño de árbol corresponde a la clasificación validada cruzada más baja tasa de error?
Un árbol con \(5\) nodos terminales arrojaría la menor tasa de error de validación cruzada.
Producir un árbol podado que corresponda al tamaño óptimo del árbol obtenido mediante validación cruzada. Si la validación cruzada no conduce a la selección de un árbol podado, luego crear un árbol podado con cinco nodos terminales.
set.seed(1234)
p_OJ <- prune.tree(OJtree, best = 5)
summary(p_OJ)
##
## Classification tree:
## snip.tree(tree = OJtree, nodes = 5L)
## Variables actually used in tree construction:
## [1] "LoyalCH" "PriceDiff"
## Number of terminal nodes: 5
## Residual mean deviance: 0.7755 = 616.5 / 795
## Misclassification error rate: 0.165 = 132 / 800
Las estadística resumidas obtenidas por la función \(summary\) se tiene que el árbol usa \(2\) variables predictoras, las cuales son LoyalCH y PriceDiff El árbol tiene \(5\) nodos terminales y su tasa de error es de \(0.1825\).
Comparar las tasas de error de entrenamiento entre los podados y los no podados árboles. ¿Cuál es más alto?
Al hacer el ajuste de los árboles se obtiene que la tasa de error de entrenamiento para el árbol sin podar es \(14.75%\) y para el árbol podado es \(18.25\) que es levemente mayor, por lo tanto la poda del árbol no mejor significativamente el error.
Comparar los índices de error de la prueba entre los podados y los no podados árboles. ¿Cuál es más alto?
## [1] "El MSE de prueba para el árbol no podado es 22.593"
## [1] "El MSE de prueba para el árbol podado es 22.593"
En cuanto a error de prueba es mejor usar el árbol podado para realizar las predicciones.
Para el punto número 10, se hará uso del método boosting, para predicción de salarios, en el set de datos Hitters.
Primero se eliminan las observaciones, para las que la información asociada a la variable salary es desconocida, y luego se aplica una transformación logarítmica.
Hitters <- na.omit(Hitters) #remoción de NA's.
Hitters$Salary <- log(Hitters$Salary) #Transformación logarítmica
Se generará un set de entrenamiento, con las primeras \(200\) observaciones y un set de prueba con las observaciones restantes.
set.seed(0)
filas <- nrow(Hitters)
variables <- ncol(Hitters) - 1 #Se omite la variable respuesta
train <- 1:200
test <- 201:filas
train_set <- Hitters[train, ]
test_set <- Hitters[test, ]
Ahora, se generará una lista con un rango de parámetros lambda, con el fin de calcular el \(MSE\) asociado para cada lambda, tanto para los datos de entrenamiento, como de prueba. Se usará un modelo \(boosting\), con una distribución gaussiana, debido a que la variable respuesta es de tipo numérico.
set.seed(0)
lambda_set <- seq(1e-03, 0.05, by = 0.001) #Shrinkage lambdas.
#Listas de NA's con la longitud del lambda_set, para almacenar el MSE de training y testing
train_set_mse <- rep(NA, length(lambda_set))
test_set_mse <- rep(NA, length(lambda_set))
# Iteración y guardado de los MSE_ test y MSE_train
for (i in 1:length(lambda_set)) {
ld <- lambda_set[i]
boost.hitters <- gbm(Salary ~., data = train_set, distribution = "gaussian", n.trees =1000, interaction.depth = 4, shrinkage = ld)
y_hat <- predict(boost.hitters, newdata = train_set, n.trees = 1000)
#MSE_train
train_set_mse[i] <- mean((y_hat - train_set$Salary)^2)
y_hat <- predict(boost.hitters, newdata = test_set, n.trees = 1000)
#MSE_test
test_set_mse[i] <- mean((y_hat - test_set$Salary)^2)
}
#Gráfica MSE vs. Lambda
plot(lambda_set, train_set_mse, type = "b", pch = 19, col = "black", xlab = "Lambda Value", ylab = "train_MSE")
plot(lambda_set, test_set_mse, type = "b", pch = 20, col = "blue", xlab = "Lambda Value", ylab = "Test Set MSE")
grid()
Se realizará un modelo de regresión lineal con este set de datos, con el fin de realizar un comparativo con el \(MSE\) del modelo \(boosting\).
lr <- lm(Salary ~., data = train_set)
y_hat_tr <- predict(lr, newdata = train_set)
y_hat_t <- predict(lr, newdata = test_set)
MSE_train <- mean((y_hat_tr - train_set$Salary)^2)
MSE_test <- mean((y_hat_t - test_set$Salary)^2)
sprintf("MSE_train: %f, MSE_test: %f", MSE_train, MSE_test)
## [1] "MSE_train: 0.320373, MSE_test: 0.491796"
Se puede observar, que el \(MSE\), tanto en los datos de prueba, como en los datos de entrenamiento sigue siendo menor para el modelo \(boosting\), el cual posee un \(MSE_test\) de \(0.01086731\).
Por último se realiza un modelo de regresión tipo Lasso.
lss <- model.matrix(Salary ~., data = train_set)
lss2 <- model.matrix(Salary ~., data = test_set)
cv.out <- cv.glmnet(lss, train_set$Salary, alpha = 1)
bestld <- cv.out$lambda.1se
y_hat_tr <- predict(cv.out, s = bestld, newx = lss)
y_hat_t <- predict(cv.out, s = bestld,
newx = lss2)
MSE_train <- mean((y_hat_tr - train_set$Salary)^2)
MSE_test <- mean((y_hat_t - test_set$Salary)^2)
sprintf("lasso CV best value of lambda (one standard error): %f", bestld)
## [1] "lasso CV best value of lambda (one standard error): 0.172520"
sprintf("lasso regression MSE_train: %f", MSE_train)
## [1] "lasso regression MSE_train: 0.431836"
sprintf("lasso regression MSE_train: %f", MSE_test)
## [1] "lasso regression MSE_train: 0.440617"
En este caso, nuevamente sigue teniendo un \(MSE\) más bajo el modelo \(boosting\).
Ahora se identifican las variables más importantes para el modelo \(boosted\).
summary(boost.hitters)
## var rel.inf
## CAtBat CAtBat 27.0020209
## CWalks CWalks 10.6163551
## CHits CHits 7.6902661
## Walks Walks 6.8483932
## PutOuts PutOuts 6.1286755
## CRBI CRBI 6.0907884
## Years Years 4.4675957
## CRuns CRuns 4.4102640
## Assists Assists 3.7882081
## RBI RBI 3.7876623
## AtBat AtBat 3.7557979
## CHmRun CHmRun 3.5852874
## Runs Runs 2.8328845
## HmRun HmRun 2.7786882
## Hits Hits 2.7428142
## Errors Errors 2.1044565
## NewLeague NewLeague 0.7478656
## Division Division 0.4581761
## League League 0.1638003
Es claro que las variables más importantes son CAtBat y CWalks.
bag.hitters <- randomForest(Salary ~., data = train_set, mtry = variables, ntree = 1000, importance = TRUE)
y_hat <- predict(bag.hitters, newdata = test_set)
mse <- mean((test_set$Salary - y_hat)^2)
sprintf("Bagging MSE_test: %f", MSE_test)
## [1] "Bagging MSE_test: 0.440617"
En este caso, el argumento \(mtyr=variables\), nos indica que todos los predictores deberían ser considerados en cada una de las divisiones del arbol, en otras palabras, que se debe hacer uso del método \(bagging\).
Para la realización de este punto, se hace uso del set de datos Caravan
En principio se creará un set de datos, donde las primeras \(1000\) observaciones serán consideradas como el set de entrenamiento y las restantes como el set de prueba.
set.seed(0)
df <- read.csv("data.csv")
#Se omiten los NA's
df <- na.omit(df)
filas <- nrow(df)
variables <- ncol(df) - 1 #Se omite la variable respuesta
train <- 1:1000
test <- 1001:filas
#Estas variables no presentan variación en el modelo, por lo que son eliminadas ("variable 50: PVRAAUT has no variation.variable 71: AVRAAUT has no variation").
df$PVRAAUT <- NULL
df$AVRAAUT <- NULL
#La variable 'Purchase' se transformará en una variable binaria (0, 1), para hacer uso del boosting model.
Purchase <- ifelse(df$Purchase == "Yes", 1, 0)
df$Purchase <- Purchase
train_set <- df[train, ]
test_set <- df[test, ]
Para abordar este problema, se realiza un modelo tipo \(boosting\) haciendo uso del set de entrenamineto, la variable respuesta será \(Purchase\), se hará uso de \(1000\) árboles y un valor \(\lambda=0.01\). En este caso se hará uso de la distribución Bernoulli, debido a que la variable respuesta es binaria.
#Entrenamiento del modelo.
ld <- 0.01 #Shrinkage lambda
boost.caravan <- gbm(Purchase ~., data = train_set, distribution = "bernoulli", n.trees = 1000, interaction.depth = 2, shrinkage = ld)
summary(boost.caravan)
## var rel.inf
## PPERSAUT PPERSAUT 9.83047713
## MKOOPKLA MKOOPKLA 5.67101078
## MOPLHOOG MOPLHOOG 5.57015086
## PBRAND PBRAND 5.53090647
## MGODGE MGODGE 5.50146339
## MBERMIDD MBERMIDD 4.66053217
## MOSTYPE MOSTYPE 3.71528842
## MINK3045 MINK3045 3.29167392
## MGODPR MGODPR 3.15189659
## MAUT2 MAUT2 2.75860820
## MBERARBG MBERARBG 2.41585129
## ABRAND ABRAND 2.34750399
## MSKC MSKC 2.07742330
## MSKA MSKA 2.03539655
## MAUT1 MAUT1 2.00290825
## MRELGE MRELGE 1.91903070
## MSKB1 MSKB1 1.88713704
## PWAPART PWAPART 1.88354710
## MFWEKIND MFWEKIND 1.86568208
## MGODOV MGODOV 1.75362888
## MINK7512 MINK7512 1.68185238
## MFGEKIND MFGEKIND 1.62053883
## MBERHOOG MBERHOOG 1.47386158
## MBERARBO MBERARBO 1.45496977
## MINKM30 MINKM30 1.45332376
## MHKOOP MHKOOP 1.44894919
## MGODRK MGODRK 1.42859782
## MRELOV MRELOV 1.35136073
## MINKGEM MINKGEM 1.33514219
## MAUT0 MAUT0 1.20352717
## MZFONDS MZFONDS 1.17292916
## MINK4575 MINK4575 1.16903944
## MOSHOOFD MOSHOOFD 1.13985697
## MHHUUR MHHUUR 1.04951077
## MGEMLEEF MGEMLEEF 1.03005616
## APERSAUT APERSAUT 0.99864198
## MSKB2 MSKB2 0.97672510
## PBYSTAND PBYSTAND 0.87858256
## MOPLMIDD MOPLMIDD 0.87431940
## PMOTSCO PMOTSCO 0.83289524
## MFALLEEN MFALLEEN 0.82850043
## MZPART MZPART 0.82588303
## PLEVEN PLEVEN 0.72568141
## MGEMOMV MGEMOMV 0.70719044
## MSKD MSKD 0.69605715
## MBERBOER MBERBOER 0.63402319
## MBERZELF MBERZELF 0.38036763
## MRELSA MRELSA 0.32946406
## MINK123M MINK123M 0.21200829
## MOPLLAAG MOPLLAAG 0.19163868
## MAANTHUI MAANTHUI 0.02438834
## PWABEDR PWABEDR 0.00000000
## PWALAND PWALAND 0.00000000
## PBESAUT PBESAUT 0.00000000
## PAANHANG PAANHANG 0.00000000
## PTRACTOR PTRACTOR 0.00000000
## PWERKT PWERKT 0.00000000
## PBROM PBROM 0.00000000
## PPERSONG PPERSONG 0.00000000
## PGEZONG PGEZONG 0.00000000
## PWAOREG PWAOREG 0.00000000
## PZEILPL PZEILPL 0.00000000
## PPLEZIER PPLEZIER 0.00000000
## PFIETS PFIETS 0.00000000
## PINBOED PINBOED 0.00000000
## AWAPART AWAPART 0.00000000
## AWABEDR AWABEDR 0.00000000
## AWALAND AWALAND 0.00000000
## ABESAUT ABESAUT 0.00000000
## AMOTSCO AMOTSCO 0.00000000
## AAANHANG AAANHANG 0.00000000
## ATRACTOR ATRACTOR 0.00000000
## AWERKT AWERKT 0.00000000
## ABROM ABROM 0.00000000
## ALEVEN ALEVEN 0.00000000
## APERSONG APERSONG 0.00000000
## AGEZONG AGEZONG 0.00000000
## AWAOREG AWAOREG 0.00000000
## AZEILPL AZEILPL 0.00000000
## APLEZIER APLEZIER 0.00000000
## AFIETS AFIETS 0.00000000
## AINBOED AINBOED 0.00000000
## ABYSTAND ABYSTAND 0.00000000
Es claro que para este modelo, las variables más importantes son PPERSAUT y MKOOPKLA.
# Predicción del error de prueba
y_hat <- predict(boost.caravan, newdata = test_set, n.trees = 1000)
p_hat <- exp(y_hat)/(1 + exp(y_hat))
# Conversión de los odd logarítmicos en probabilidades
si_compra <- rep(0, length(test))
si_compra[p_hat > 0.2]<-1
# Creación de matriz de confusión.
table(si_compra, test_set$Purchase)
##
## si_compra 0 1
## 0 4357 253
## 1 176 36
Ahora se genera un modelo de regresión lógistica, con el fin de generar un comparativo.
lg <- glm(Purchase ~., data = train_set, family = "binomial")
#Predicciones
y_hat <- predict(lg, newdata = test_set)
#Conversión de probabiliades
p_hat <- exp(y_hat)/(1 + exp(y_hat))
si_compra <- rep(0, length(test))
si_compra[p_hat > 0.2] <- 1
#Matriz de confusión
table(si_compra, test_set$Purchase)
##
## si_compra 0 1
## 0 4183 231
## 1 350 58
El modelo de regresión lógistica presenta una mayor cantidad de observaciones mal clasificadas.
Aplicar el potenciamiento, el embolsamiento y los bosques aleatorios a un conjunto de datos de su elección. Asegúrate de que los modelos encajen en datos de entrenamiento y de que evalúen su rendimiento en datos de prueba. ¿Cómo de precisos son los resultados comparados a métodos simples como la regresión lineal o logística? ¿Cuál de estos que los enfoques de la investigación dan el mejor resultado?
Por comodidad se usará la base de datos Caravan.
train <- 1:1000
library(tidyverse)
Caravan <- Caravan%>%
mutate(Purchase=case_when(Purchase == "Yes" ~ 1, TRUE~0))
Ctrain <- Caravan[train, ]
Ctest <- Caravan[-train, ]
#Usando regresión logistica
logist <- glm(Purchase ~ ., data = Ctrain, family = binomial)
logistp <- predict(logist, Ctest, type = "response")
prediccion <- ifelse(logistp > 0.2, 1, 0)
table(Ctest$Purchase, prediccion)
## prediccion
## 0 1
## 0 4183 350
## 1 231 58
El error de prueba es de \(12.04\%\).
#Usando potenciamiento
set.seed(1234)
library(gbm)
cpotencido <- gbm(Purchase ~ ., data = Ctrain, n.trees = 1000,
shrinkage = 0.01,
distribution = "bernoulli")
potenciado <- predict(cpotencido, Ctest, n.trees = 1000, type = "response")
potenciadop <- ifelse(potenciado > 0.2, 1, 0) #mayor a 20%
table(Ctest$Purchase, potenciadop)
## potenciadop
## 0 1
## 0 4406 127
## 1 258 31
Test de error es de \(7.98\%\).
#Usando embolsamiento
set.seed(1234)
cembolsado <- randomForest(Purchase ~ ., data = Ctrain, mtry = 6)
cpredembolsado <- predict(cembolsado, newdata = Ctest)
embolsadop <- ifelse(cpredembolsado > 0.2, 1, 0) #mayor a 20%
table(embolsadop, Ctest$Purchase)
##
## embolsadop 0 1
## 0 4310 249
## 1 223 40
Test de error es de \(9.78\%\).
#Usando bosques aleatorios
set.seed(1234)
cbosques <- randomForest(Purchase ~ ., data = Ctrain, mtry = 2)
cbosquesp <- predict(cbosques, newdata = Ctest)
bp <- ifelse(cbosquesp > 0.2, 1, 0) #mayor a 20%
table(bp, Ctest$Purchase)
##
## bp 0 1
## 0 4447 270
## 1 86 19
Test de error es de \(7.38\%\)
El error de test más bajo fue el de bosques aleatorios.
El objetivo de este punto es crear dos conjuntos de puntos (clases) no lineales para comparar el rendimiento de las máquinas de soporte vectorial con un kernel diferente.
Se crean dos conjuntos de puntos y se grafican para identificar si son no lineales.
set.seed(69)
x <- rnorm(100)
y <- 4 * x^2 + 0 + rnorm(100)
set <- sample(100, 50)
y[set] <- y[set] + 3
y[-set] <- y[-set] - 3
plot(x[set], y[set], col = "red", xlab = "X", ylab = "Y", ylim = c(-5, 25))
points(x[-set], y[-set], col = "blue")
Se crean los datasets de entrenamiento y de prueba.
z <- rep(0, 100)
z[set] <- 1
data <- data.frame(x = x, y = y, z = as.factor(z))
train <- sample(100, 50)
data.train <- data[train, ]
data.test <- data[-train, ]
Entrenamos la maquina de soporte vectorial con un kernel linear
svm.linear <- svm(z ~ ., data = data.train, kernel = "linear", cost = 10)
plot(svm.linear, data.train)
Se visualizan los errores
table(predict = predict(svm.linear, data.train), truth = data.train$z)
## truth
## predict 0 1
## 0 19 1
## 1 5 25
Se entrena a la máquina de soporte vectorial con un kernel radial.
svm.radial <- svm(z ~ ., data = data.train, kernel = "radial", gamma = 1, cost = 10)
plot(svm.radial, data.train)
Se visualizan los errores
table(predict = predict(svm.radial, data.train), truth = data.train$z)
## truth
## predict 0 1
## 0 24 0
## 1 0 26
El entrenamiento con un kernel radial tiene menos errores que el entrenamiento con kernel lineal por lo tanto tiene mejor rendimiento.
El objetivo de este punto es aprender cómo obtener límites de decisión para clasificación a partir de una regresión logística aplicando transformaciones no lineales
Se crean los puntos (como nos indica el libro)
x1 = runif (10000) -0.5
x2 = runif (10000) -0.5
y =1*( x1 ^2 - x2 ^2 > 0)
Se realiza el gráfico del dataset creado anteriormente usando diferentes colores para cada clase.
plot(x1[y == 0], x2[y == 0], col = "red", xlab = "X1", ylab = "X2", pch = "+")
points(x1[y == 1], x2[y == 1], col = "blue", pch = "x")
Se realiza el ajuste de una regresión logística al dataset.
logit.fit <- glm(y ~ x1 + x2, family = "binomial")
summary(logit.fit)
##
## Call:
## glm(formula = y ~ x1 + x2, family = "binomial")
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.180 -1.168 -1.157 1.187 1.199
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.02245 0.02000 -1.122 0.262
## x1 -0.02213 0.06978 -0.317 0.751
## x2 0.03735 0.06896 0.542 0.588
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 13862 on 9999 degrees of freedom
## Residual deviance: 13861 on 9997 degrees of freedom
## AIC: 13867
##
## Number of Fisher Scoring iterations: 3
Las variables \(X1\) y \(X2\) no son siginificativas para el modelo ajustado.
Se aplica el modelo y se realiza un gráfico con el fin de visualizar de una manera mas clara.
data = data.frame(x1 = x1, x2 = x2, y = y)
lm.prob = predict(logit.fit, data, type = "response")
lm.pred = ifelse(lm.prob > 0.5, 1, 0)
data.pos = data[lm.pred == 1, ]
data.neg = data[lm.pred == 0, ]
plot(data.pos$x1, data.pos$x2, col = "blue", xlab = "X1", ylab = "X2", pch = "+",xlim = c(-0.5, 0.5), ylim = c(-0.5, 0.5))
points(data.neg$x1, data.neg$x2, col = "red", pch = "x")
Como se esperaba el límite de decisión es lineal y no se ajusta correctamente a los datos.
Ahora se ajusta una regresión logística, pero usando funciones no lineales como “predictors”.
logitnl.fit <- glm(y ~ poly(x1, 2) + poly(x2, 2) + I(x1 * x2), data = data, family = "binomial")
summary(logitnl.fit)
##
## Call:
## glm(formula = y ~ poly(x1, 2) + poly(x2, 2) + I(x1 * x2), family = "binomial",
## data = data)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -0.4171 0.0000 0.0000 0.0000 0.3745
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1569 1173 -1.337 0.181
## poly(x1, 2)1 -72032 53319 -1.351 0.177
## poly(x1, 2)2 6015847 4300776 1.399 0.162
## poly(x2, 2)1 38052 29447 1.292 0.196
## poly(x2, 2)2 -6040513 4322410 -1.397 0.162
## I(x1 * x2) -235 1465 -0.160 0.873
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1.3862e+04 on 9999 degrees of freedom
## Residual deviance: 4.5154e-01 on 9994 degrees of freedom
## AIC: 12.452
##
## Number of Fisher Scoring iterations: 25
Ninguna de las fuunciones no lineales usadas logro agregar significancia al modelo.
Se aplica el nuevo modelo y se realiza un gráfico con el fin de visualizar de una manera mas clara.
lm.prob = predict(logitnl.fit, data, type = "response")
lm.pred = ifelse(lm.prob > 0.5, 1, 0)
data.pos = data[lm.pred == 1, ]
data.neg = data[lm.pred == 0, ]
plot(data.pos$x1, data.pos$x2, col = "blue", xlab = "X1", ylab = "X2", pch = "+",xlim = c(-0.5, 0.5), ylim = c(-0.5, 0.5))
points(data.neg$x1, data.neg$x2, col = "red", pch = "x")
Ahora el límite de decisión es no lineal y se ajusta mejor a los datos
Para este caso se utilizará una máquina de soporte vectorial con kernel linear y se grafican los resultados.
svm.fit = svm(as.factor(y) ~ x1 + x2, data, kernel = "linear", cost = 10)
svm.pred = predict(svm.fit, data)
data.pos = data[svm.pred == 1, ]
data.neg = data[svm.pred == 0, ]
plot(data.pos$x1, data.pos$x2, col = "blue", xlab = "X1", ylab = "X2", pch = "+",xlim = c(-0.5, 0.5), ylim = c(-0.5, 0.5))
points(data.neg$x1, data.neg$x2, col = "red", pch = "x")
De igual forma que con la regresión logística el límite de decisión es lineal y no se ajusta correctamente a los datos.
Se ajusta un máquina de soporte vectorial con kernel radial.
svm.fit = svm(as.factor(y) ~ x1 + x2, data, kernel="radial", gamma = 1, cost=10)
svm.pred = predict(svm.fit, data)
data.pos = data[svm.pred == 1, ]
data.neg = data[svm.pred == 0, ]
plot(data.pos$x1, data.pos$x2, col = "blue", xlab = "X1", ylab = "X2", pch = "+",xlim = c(-0.5, 0.5), ylim = c(-0.5, 0.5))
points(data.neg$x1, data.neg$x2, col = "red", pch = 4)
En este punto se identifica que si se usa una máquina de soporte vectorial con kernel no-lineal o una regresión logística con transformaciones puede ser muy útil para encontrar límites de decisión no lineales, en cambio si se usa un kernel lineal o no se usan transformaciones los resultados están muy alejados de la realidad para este tipo de problemas.
Al final de la Sección \(9.6.1\), se afirma que en el caso de datos que son apenas separables linealmente, un clasificador de vectores de soporte con un valor pequeño de \(cost\) que clasifica erróneamente un par de observaciones de entrenamiento puede funcionar mejor en datos de prueba que uno con un valor de \(cost\) enorme que no clasifica erróneamente ninguna observación de entrenamiento. Ahora investigará este reclamo.
Genere datos de dos clases con \(p = 2\) de tal manera que las clases sean apenas separables linealmente.
Se inicia fijando una semilla, con el fin de obtener resultados iguales si el ejericio es simulado por otra persona, se simularan dos variables de una \(N(0,1)\), se crea la variable \(y\) que contiene las verdaderas clases a las que pertenecen las observaciones, se hace un cambio en la media para garantizar que las clases sean realmente separables.
set.seed (123456)
x <- matrix (rnorm (1000*2) , ncol =2)
y <- c(rep (-1,50) , rep (1 ,50) )
x[y==1 ,] <- x[y==1,] + 3
Observe que las clases son apenas linealmente separables.
Calcule las tasas de error de validación cruzada para clasificadores de vectores de soporte con un rango de valores de costo. ¿Cuántos valores de entrenamiento se clasifican erróneamente para cada valor de costo considerado y cómo se relaciona esto con los errores de validación cruzada obtenidos?
Es necesario crear un data frame con la variable respuesta codificada como factor y generar la división del conjunto en entrenamiento y prueba, a demás se cambiaran los nombres de las columnas para que sean más claros y finalmente se procede con el ajuste del clasificador de soporte vectorial con diferentes valores del parámetro \(Cost\), para esto se hace uso de la función \(tune()\) de la librería \(e1071\).
#Creación y corrección de nombres de columnas
data <- data.frame(x, as.factor(y))
colnames(data) <- c("X1", "X2", "Y")
#División del conjunto de datos
set.seed(123456)
index <- sample(nrow(data), 700)
train <- data[index, ]
test <- data[-index, ]
#Ajuste del clasificador lineal
tune.out <- tune(svm, Y ~ ., data = train,
kernel = "linear",
ranges = list(cost = c(0.001, 0.01, 0.1, 1, 5, 10, 15, 20)),
scale = TRUE)
Como es necesario identificar cuantas observaciones del conjunto de entrenamiento están mal clasificadas, se debe ajustar un calsificador de soporte vectorial para cada valor considerado del parámetro \(cost\), realizar las predicciones y calcular su tasa de error de mala clasificación.
svmfit0.001 <- svm(Y~., data = train, kernel ="linear", cost = 0.001,
scale = T)
predict0.001 <- predict(svmfit0.001, train)
table(Predict = predict0.001 , Truth = train$Y)
## Truth
## Predict -1 1
## -1 343 9
## 1 5 343
## [1] "Error de entrenamiento: 2 %"
La matriz anterior permite concluir que con valor del parámetro \(cost=0.001\), \(686\) de las observaciones se han clasificado de forma correcta, las restantes \(14\) de las \(700\) observaciones del conjunto de entrenamiento quedaron mal clasificadas y por lo tanto el \(MSE\) de entrenamiento es de \(2\%\).
svmfit0.01 <- svm(Y~., data = train, kernel ="linear", cost = 0.01,
scale = T)
predict0.01 <- predict(svmfit0.01, train)
table(Predict = predict0.01 , Truth= train$Y)
## Truth
## Predict -1 1
## -1 342 7
## 1 6 345
## [1] "Error de entrenamiento: 1.857 %"
La matriz anterior permite concluir que con valor el parámetro \(cost=0.01\), \(687\) de las observaciones se han clasificado de forma correcta, solo \(13\) de las \(700\) observaciones del conjunto de entrenamiento quedaron mal clasificadas y por lo tanto el \(MSE\) de entrenamiento es del \(1.857\%\).
svmfit0.1 <- svm(Y~., data = train, kernel ="linear", cost = 0.1,
scale = T)
predict0.1 <- predict(svmfit0.1, train)
table(Predict = predict0.1 , Truth= train$Y)
## Truth
## Predict -1 1
## -1 341 5
## 1 7 347
## [1] "Error de entrenamiento: 1.714 %"
svmfit1 <- svm(Y~., data = train, kernel ="linear", cost = 1,
scale = T)
predict1 <- predict(svmfit1, train)
table(Predict = predict1 , Truth= train$Y)
## Truth
## Predict -1 1
## -1 341 5
## 1 7 347
## [1] "Error de entrenamiento: 1.714 %"
Observe que para los valores de \(cost=0.1\) y \(cost=1\) las tasas de mala clasificación son iguales, ambas son pequeñas.
svmfit5 <- svm(Y~., data = train, kernel ="linear", cost = 5,
scale = T)
predict5 <- predict(svmfit5, train)
table(Predict = predict5 , Truth= train$Y)
## Truth
## Predict -1 1
## -1 343 5
## 1 5 347
## [1] "Error de entrenamiento: 1.429 %"
Cuando el parámetro \(cost\) es fijado en \(0.01\), \(690\) de las observaciones se han clasificado de forma correcta, solo \(10\) de las \(700\) observaciones del conjunto de entrenamiento quedaron mal clasificadas y por lo tanto el \(MSE\) de entrenamiento es del \(1.429\%\).
svmfit10 <- svm(Y~., data = train, kernel ="linear", cost = 10,
scale = T)
predict10 <- predict(svmfit10, train)
table(Predict = predict10 , Truth= train$Y)
## Truth
## Predict -1 1
## -1 344 5
## 1 4 347
## [1] "Error de entrenamiento: 1.286 %"
svmfit15 <- svm(Y~., data = train, kernel ="linear", cost = 15,
scale = T)
predict15 <- predict(svmfit15, train)
table(Predict = predict15 , Truth= train$Y)
## Truth
## Predict -1 1
## -1 344 5
## 1 4 347
## [1] "Error de entrenamiento: 1.286 %"
svmfit20 <- svm(Y~., data = train, kernel ="linear", cost = 20,
scale = T)
predict20 <- predict(svmfit20, train)
table(Predict = predict20 , Truth= train$Y)
## Truth
## Predict -1 1
## -1 344 5
## 1 4 347
## [1] "Error de entrenamiento: 1.286 %"
A partir del valor de \(cost=10\), los valores de \(MSE\) se estabilizan, es decir que no cambian cuando se incrementa el valor del parámetro.
El resultado de la aplicación de la función \(tune()\) se guardo en un objeto llamado \(tune.out\), este objeto contiene un dataframe con información sobre los errores producidos con los diferentes valores de \(Cost\), dicho dataframe se presenta a continuación.
tune.out$performances
## cost error dispersion
## 1 0.001 0.02142857 0.01214052
## 2 0.010 0.01714286 0.01475422
## 3 0.100 0.02142857 0.01543033
## 4 1.000 0.01714286 0.01475422
## 5 5.000 0.01428571 0.01649572
## 6 10.000 0.01428571 0.01649572
## 7 15.000 0.01571429 0.01572150
## 8 20.000 0.01571429 0.01572150
La columna error contiene el error de validación para cada uno de los valores del parámetro \(cost\), observe que estos valores son un poco diferentes a los obtenidos calculando el \(MSE\) a partir de la matriz de confusión, esto puede deberse a que internamente la función \(tune()\) realiza una validación cruzada con \(k-folds\).
Generar un conjunto de datos de prueba apropiado y calcular los errores de prueba correspondientes a cada uno de los valores de costo considerados. ¿Qué valor de costo conduce a la menor cantidad de errores de prueba y cómo se compara esto con los valores de costo que producen la menor cantidad de errores de entrenamiento y la menor cantidad de errores de validación cruzada?
No es necesario generar un nuevo conjunto de datos de prueba ya que los simulados en el literal (a) fueron divididos en entrenamiento y validación.
svmfit0.001 <- svm(Y~., data = train, kernel ="linear", cost = 0.001,
scale = T)
predict0.001 <- predict(svmfit0.001, test)
table(Predict = predict0.001 , Truth = test$Y)
## Truth
## Predict -1 1
## -1 148 1
## 1 4 147
## [1] "Error de entrenamiento: 1.667 %"
La matriz anterior permite concluir que con valor del parámetro \(cost=0.001\), \(295\) de las observaciones se han clasificado de forma correcta, las restantes \(5\) de las \(300\) observaciones del conjunto de prueba quedaron mal clasificadas y por lo tanto el \(MSE\) de prueba es de \(1.667\%\).
svmfit0.01 <- svm(Y~., data = train, kernel ="linear", cost = 0.01,
scale = T)
predict0.01 <- predict(svmfit0.01, test)
table(Predict = predict0.01 , Truth= test$Y)
## Truth
## Predict -1 1
## -1 147 1
## 1 5 147
## [1] "Error de entrenamiento: 2 %"
svmfit0.1 <- svm(Y~., data = train, kernel ="linear", cost = 0.1,
scale = T)
predict0.1 <- predict(svmfit0.1, test)
table(Predict = predict0.1 , Truth= test$Y)
## Truth
## Predict -1 1
## -1 147 1
## 1 5 147
## [1] "Error de entrenamiento: 2 %"
svmfit1 <- svm(Y~., data = train, kernel ="linear", cost = 1,
scale = T)
predict1 <- predict(svmfit1, test)
table(Predict = predict1 , Truth= test$Y)
## Truth
## Predict -1 1
## -1 147 1
## 1 5 147
## [1] "Error de entrenamiento: 2 %"
Para valores de \(cost\) igual a \((0.01, 0.1, 1)\) las tasas de mala clasificación en el conjunto de prueba son iguales.
svmfit5 <- svm(Y~., data = train, kernel ="linear", cost = 5,
scale = T)
predict5 <- predict(svmfit5, test)
table(Predict = predict5 , Truth= test$Y)
## Truth
## Predict -1 1
## -1 145 2
## 1 7 146
## [1] "Error de entrenamiento: 3 %"
Cuando el parámetro \(cost\) es fijado en \(5\), \(291\) de las observaciones se han clasificado de forma correcta, solo \(9\) de las \(300\) observaciones del conjunto de entrenamiento quedaron mal clasificadas y por lo tanto el \(MSE\) de prueba es del \(3\%\).
svmfit10 <- svm(Y~., data = train, kernel ="linear", cost = 10,
scale = T)
predict10 <- predict(svmfit10, test)
table(Predict = predict10 , Truth= test$Y)
## Truth
## Predict -1 1
## -1 148 2
## 1 4 146
## [1] "Error de entrenamiento: 2 %"
svmfit15 <- svm(Y~., data = train, kernel ="linear", cost = 15,
scale = T)
predict15 <- predict(svmfit15, test)
table(Predict = predict15 , Truth= test$Y)
## Truth
## Predict -1 1
## -1 148 2
## 1 4 146
## [1] "Error de entrenamiento: 2 %"
svmfit20 <- svm(Y~., data = train, kernel ="linear", cost = 20,
scale = T)
predict20 <- predict(svmfit20, test)
table(Predict = predict20 , Truth= test$Y)
## Truth
## Predict -1 1
## -1 148 2
## 1 4 146
## [1] "Error de entrenamiento: 2 %"
A partir del valor de \(cost=5\), los valores de \(MSE\) se estabilizan, es decir que no cambian cuando se incrementa el valor del parámetro.
En el conjunto de entrenamiento se evidencia que el valor óptimo para el parámetro \(cost\) se encuentra entre los sigueintes valores \((10, 15, 20)\), mientras que para el conjunto de validación el valor de \(cost\) que produce la tasa de mala clasificación más baja es \(0.001\), cuando se usa este valor en el entrenamiento se obtiene que la tasa de mala clasificación es del \(2\%\), por lo tanto, es preferible un valor del parámetro que produzca mayores observaciones mal clasificadas en el conjunto de entrenamiento pero que tenga un desempeño mejor en el conjunto de validación.
En este problema, utilizará enfoques de vectores de soporte para predecir si un automóvil determinado obtiene un consumo alto o bajo de combustible según el conjunto de datos de Auto.
A continuación se presenta las primeras seis filas del conjunto de datos Auto, este conjunto contiene 9 variables.
library(ISLR)
head(Auto)
## mpg cylinders displacement horsepower weight acceleration year origin
## 1 18 8 307 130 3504 12.0 70 1
## 2 15 8 350 165 3693 11.5 70 1
## 3 18 8 318 150 3436 11.0 70 1
## 4 16 8 304 150 3433 12.0 70 1
## 5 17 8 302 140 3449 10.5 70 1
## 6 15 8 429 198 4341 10.0 70 1
## name mpg01 forigin
## 1 chevrolet chevelle malibu FALSE 1
## 2 buick skylark 320 FALSE 1
## 3 plymouth satellite FALSE 1
## 4 amc rebel sst FALSE 1
## 5 ford torino FALSE 1
## 6 ford galaxie 500 FALSE 1
-Mpg: Millas por galón.
-Cylinders: Número de cilindros entre 4 y 8.
-Displacement: Desplazamiento del motor (pulgadas cúbicos).
-Horsepower: Potencia del motor.
-Weight: Peso del vehículo (libras).
-Acceleration: Tiempo para acelerar de 0 60 mph (segundos).
-Year: Año del modelo (módulo 100).
-Origin: Origen del automóvil (1: Americano, 2: Europeo, 3: Japonés).
-Name: Nombre del vehículo.
Cree una variable binaria que tome el valor de \(1\) para los automóviles con rendimiento de gasolina por encima de la mediana y el valor de \(0\) para automóviles con rendimiento de combustible por debajo de la mediana.
medianamillaje <- median(Auto$mpg)
Auto$High <- ifelse(Auto$mpg < medianamillaje, "0", "1")
Auto$High <- as.factor(Auto$High)
La mediana de millas por galón es de \(22.75\) y la proporción de las categorías de la nueva variable llamada High es de \(50\%\).
Ajuste un clasificador de vectores de soporte a los datos con varios valores de \(cost\), para predecir si un automóvil posee un alto o bajo consumo de combustible. Informe los errores de validación cruzada asociados con diferentes valores de este parámetro. Comente sus resultados.
Inicialmente el conjunto de datos será dividido, el \(70\%\) de las observaciones se asignan a la base de entrenamiento y el restante a la base de prueba.
Luego de esto se usa la función tune() perteneciente a la librería e1071 que realiza una validación cruzada de diez folds en un conjunto de modelos de interés. El parámetro \(Cost\) tomara valores en el vector \((0.001, 0.01, 0.1, 1, 5, 10, 100)\), como se muestra a continuación,
library(e1071)
set.seed(123456)
tune.out.l <- tune(svm, High~., data=train, kernel ="linear",
ranges =list(cost=c(0.001, 0.01, 0.1, 1, 5, 10, 100)),
scale = T)
En la salida \(tune.out.l\) se guarda un conjunto de datos que contiene los valores del parámetro \(cost\), sus errores y dispersión, en base a esta información se construye el siguiente gráfico.
Se evidencia que el mínimo error se produce cuando el parámetro \(cost=0.01\), dicho error es igual a \(0\), a continuación se presenta el mismo gráfico pero con los errores para el conjunto de prueba.
Cuando el parámetro \(cost\) es \(0.01\) se obtiene un valor de \(Error=0.025\), es decir que hay muy pocas observaciones mal clasificadas.
Ahora repita (b), esta vez usando SVMs con núcleos de base radial y polinomial, con diferentes valores de \(\gamma\) y \(degree\) y \(cost\). Comente sus resultados.
Nuevamente se hace uso de la función tune(), variando los parámetros de \(Cost\) y \(\gamma\).
set.seed(1233456)
tune.out.r <- tune(svm, High~., data = train, kernel = "radial",
ranges =list(cost=c(0.001, 0.01, 0.1, 1, 5, 10, 100),
gamma=c(0.1, 0.5, 1, 2, 3, 4, 5)),
scale = T)
Se identifica que la combinación óptima de los parámetros \(Cost\) y \(\gamma\) son \(1\) y \(0.1\) resectivamente.
Se procede a ajustar la SMV de Kernell radial, con la combinación óptima de los parámetros \(Cost\) y \(\gamma\).
##
## Call:
## best.tune(method = svm, train.x = High ~ ., data = train, ranges = list(cost = c(0.001,
## 0.01, 0.1, 1, 5, 10, 100), gamma = c(0.1, 0.5, 1, 2, 3, 4, 5)),
## kernel = "radial", scale = T)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 1
##
## Number of Support Vectors: 67
##
## ( 34 33 )
##
##
## Number of Classes: 2
##
## Levels:
## 0 1
Después de realizar el mejor modelo se obtiene que hay \(67\) vectores de soporte, \(34\) de una clase y \(33\) de la otra. Ahora se predicen las etiquetas de clase de las observaciones de prueba creadas anteriomente, para el mejor modelo usando validación cruzada.
## Truht
## Predict 0 1
## 0 59 0
## 1 0 59
Finalmente se puede concluir que con valor asignado a \(cost=1\) y \(\gamma=0.1\), todas las observaciones del conjunto de prueba se han clasificado de manera y por lo tanto el \(MSE\) de prueba es del \(0\%\).
Nuevamente se hace uso de la función tune(), variando los parámetros de \(Cost\) y \(degree\), ya que el kernell es polinomial.
set.seed(123456)
tune.out.p <- tune(svm, High~., data = train, kernel = "polynomial",
ranges =list(cost = c(0.001,0.01, 0.1, 1, 10,100),
degree = c(2, 3, 4, 5, 6)),
scale = TRUE)
Este kernell produce errores bastante grandes, aún así se identifica que la combinación óptima de los parámetros \(Cost\) y \(degree\) son \(100\) y \(2\) resectivamente.
##
## Call:
## best.tune(method = svm, train.x = High ~ ., data = train, ranges = list(cost = c(0.001,
## 0.01, 0.1, 1, 10, 100), degree = c(2, 3, 4, 5, 6)), kernel = "polynomial",
## scale = TRUE)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: polynomial
## cost: 100
## degree: 2
## coef.0: 0
##
## Number of Support Vectors: 224
##
## ( 111 113 )
##
##
## Number of Classes: 2
##
## Levels:
## 0 1
Después de realizar el ajuste del mejor modelo se obtiene que hay \(224\) vectores de soporte, \(111\) de una clase y \(113\) de la otra. Ahora se predicen las etiquetas de clase de las observaciones de prueba creadas anteriomente, para el mejor modelo usando validación cruzada.
## Truht
## Predict 0 1
## 0 50 1
## 1 9 58
Finalmente se puede concluir que con valor asignado a \(cost=100\) y \(degree = 2\), \(108\) de las observaciones se han clasificado de forma correcta y \(10\) de ellas quedaron mal clasificadas, por lo tanto el \(MSE\) de prueba es de \(8.47\%\).
Haga algunas gráficas para respaldar sus afirmaciones en (b) y (c).
Es necesario verificar si las dos clases son completamente separables.
En los gráficos presentados anteriormente se puede concluir que las observaciones no son completamente separables, se ajustó el clasificador de soporte vectorial con un kernel lineal, donde la región del espacio de atributos que se asignó fue a la clase \(0\) que se muestra en amarillo claro. Recordar que se obtuvo que el valor óptimo de \(cost=5\), con \(47\) vectores de soporte. Finalmente por medio de las curvas ROC a pesar de que los datos no son completamente separables, el clasificador de soporte se ajusta bien a los datos.
Nuevamente necesario verificar si las dos clases son completamente separables bajo este modelo.
Los gráficos presentados anteriormente permiten concluir que las observaciones no son completamente separables, se ajusto una máquina de soporte vectorial en la cual se obtuvo que el valor óptimo de \(cost=1\) siendo grande, \(gamma=0.1\) y con \(67\) vectores de soporte, las curvas ROC muestran que la máquina de soporte vectorial con kernel radial es un buen clasificador.
Los gráficos previamente mostrados permiten concluir que las observaciones no son completamente separables, se ajustó el clasificador de soporte vectorial con un kernel polinomial, donde la región del espacio de atributos que se asignó fue a la clase \(1\) que se muestra en purpura y en algunos casos se evidencio una región de color amarillo claro que pertenece a la clase \(0\). Recordar que se obtuvo que el valor óptimo de \(cost=100\) siendo grande, con \(224\). Finalmente a partir de las curvas ROC se observa que se produce mayor error de test, lo que indica que no es tan buen clasificador.
Este problema involucra el conjunto de datos OJ que forma parte del paquete ISLR.
Se presenta el encabezado del conjunto de datos a trabajar, este contiene \(18\) variables.
## Purchase WeekofPurchase StoreID PriceCH PriceMM DiscCH DiscMM SpecialCH
## 1 CH 237 1 1.75 1.99 0.00 0.0 0
## 2 CH 239 1 1.75 1.99 0.00 0.3 0
## 3 CH 245 1 1.86 2.09 0.17 0.0 0
## 4 MM 227 1 1.69 1.69 0.00 0.0 0
## 5 CH 228 7 1.69 1.69 0.00 0.0 0
## 6 CH 230 7 1.69 1.99 0.00 0.0 0
## SpecialMM LoyalCH SalePriceMM SalePriceCH PriceDiff Store7 PctDiscMM
## 1 0 0.500000 1.99 1.75 0.24 No 0.000000
## 2 1 0.600000 1.69 1.75 -0.06 No 0.150754
## 3 0 0.680000 2.09 1.69 0.40 No 0.000000
## 4 0 0.400000 1.69 1.69 0.00 No 0.000000
## 5 0 0.956535 1.69 1.69 0.00 Yes 0.000000
## 6 1 0.965228 1.99 1.69 0.30 Yes 0.000000
## PctDiscCH ListPriceDiff STORE
## 1 0.000000 0.24 1
## 2 0.000000 0.24 1
## 3 0.091398 0.23 1
## 4 0.000000 0.00 1
## 5 0.000000 0.00 0
## 6 0.000000 0.30 0
También es de importancia identificar la distribución de la variable respuesta, la mayoría pertenece a la categoría CH, en una prorporción de \(61\%\) y el restante (\(39\%\)) para MM.
Cree un conjunto de entrenamiento que contenga una muestra aleatoria de 800 observaciones y un conjunto de prueba que contenga las observaciones restantes.
set.seed(123456)
index <- sample(1:nrow(OJ), 800)
train <- OJ[index,]
test <- OJ[-index,]
Ajuste un clasificador de vector de soporte a los datos de entrenamiento usando \(cost = 0.01\), con Purchase como respuesta y las otras variables como predictores. Utilice la función \(summary()\) para producir estadísticas de resumen y describir los resultados obtenidos.
svmfit <- svm(Purchase~., data = train, kernel ="linear", cost = 0.01,
scale = TRUE)
summary(svmfit)
##
## Call:
## svm(formula = Purchase ~ ., data = train, kernel = "linear", cost = 0.01,
## scale = TRUE)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: linear
## cost: 0.01
##
## Number of Support Vectors: 443
##
## ( 221 222 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
La variable respuesta Purchase es un factor que posee dos clases, una de ellas es CH y la otra MM, se uso un kernell lineal para el ajuste de clasificador de soporte vectorial, este clasificador tiene \(443\) vectores de soporte, tomo \(221\) de una clase y los restantes \(222\) de la otra clase, al asignar un valor tan pequeño al parámetro \(cost\) la margen es grande y habrán mucho vectores de sporte.
¿Cuáles son las tasas de error de entrenamiento y prueba?
predict_train <- predict(svmfit, train)
table(Predict = predict_train, Truth = train$Purchase)
## Truth
## Predict CH MM
## CH 423 75
## MM 59 243
Se obtiene que \(134\) de las \(800\) observaciones de entrenamiento estan mal clasificadas, es decir, que se obtiene una tasa de mala clasificación del \(16.75\%\).
predict_test <- predict(svmfit, test)
table(Predict = predict_test, Truth = test$Purchase)
## Truth
## Predict CH MM
## CH 152 23
## MM 19 76
En el conjunto de prueba \(42\) de las \(270\) observaciones estan mal clasificadas, el casificador de soporte vectorial tiene una tasa de mala clasificación del \(15.55\%\) en el conjunto de prueba.
Utilice la función tune () para seleccionar un costo óptimo. Considere valores en el rango de 0.01 a 10.
set.seed(123456)
tune.out <- tune(svm ,Purchase~., data = train, kernel ="linear",
ranges =list(cost=c(seq(0.01, 10, 0.1))), scale = T)
El gráfico anterior permite concluir que el valor óptimo para el parámetro \(Cost\) es \(0.01\).
Calcule las tasas de error de entrenamiento y prueba utilizando este nuevo valor de costo.
svmoptimo <- svm(Purchase~., data = train, kernel ="linear", cost = 0.01,
scale = TRUE)
predict_trainoptimo <- predict(svmoptimo, train)
table(Predict = predict_trainoptimo, Truth = train$Purchase)
## Truth
## Predict CH MM
## CH 423 75
## MM 59 243
Se obtiene que \(134\) de las \(800\) observaciones de entrenamiento estan mal clasificadas, es decir, que se ontiene una tasa de mala clasificación del \(16.75\%\).
predict_testoptimo <- predict(svmoptimo, test)
table(Predict = predict_testoptimo, Truth = test$Purchase)
## Truth
## Predict CH MM
## CH 152 23
## MM 19 76
En el conjunto de prueba \(42\) de las \(270\) observaciones estan mal clasificadas, el casificador de soporte vectorial tiene una tasa de mala clasificación del \(15.55\%\) que igual a las tasas de error calculadas en el literal (c).
Repita las partes (b) a (e) usando una máquina de vectores de soporte con un núcleo radial. Utilice el valor predeterminado para gamma.
svmfit <- svm(Purchase~., data = train, kernel ="radial", cost = 0.01,
scale = TRUE)
summary(svmfit)
##
## Call:
## svm(formula = Purchase ~ ., data = train, kernel = "radial", cost = 0.01,
## scale = TRUE)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 0.01
##
## Number of Support Vectors: 639
##
## ( 318 321 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
Se uso un kernel radial para el ajuste de la máquina de soporte vectorial, este clasificador tiene \(639\) vectores de soporte, tomo \(318\) de una clase y los restantes \(321\) de la otra clase.
Ahora se calculan las tasas de error producidas por esta máquina.
predict_train <- predict(svmfit, train)
table(Predict = predict_train, Truth = train$Purchase)
## Truth
## Predict CH MM
## CH 482 318
## MM 0 0
Se obtiene que \(318\) de las \(800\) observaciones de entrenamiento estan mal clasificadas, es decir, que se obtiene una tasa de mala clasificación del \(39.75\%\).
predict_test <- predict(svmfit, test)
table(Predict = predict_test, Truth = test$Purchase)
## Truth
## Predict CH MM
## CH 171 99
## MM 0 0
En el conjunto de prueba \(99\) de las \(270\) observaciones estan mal clasificadas, la máquina de soporte vectorial con kernel radial tiene una tasa de mala clasificación del \(36.66\%\) en el conjunto de prueba.
set.seed(123456)
tune.out <- tune(svm, Purchase~., data = train, kernel ="radial",
ranges =list(cost=c(seq(0.01, 10, 0.1))), scale = TRUE)
El gráfico anterior perite concluir que el valor óptimo para el parámetro \(Cost\) es \(0.51\).
svmfit <- svm(Purchase~., data = train, kernel ="radial", cost = 0.51,
scale = TRUE)
Ahora se calculan las tasas de error producidas por la máquina con el parámetro de \(cost\) óptimo.
## Truth
## Predict CH MM
## CH 438 79
## MM 44 239
Se obtiene que \(123\) de las \(800\) observaciones de entrenamiento estan mal clasificadas, es decir, que se obtiene una tasa de mala clasificación del \(15.375\%\).
predict_test <- predict(svmfit, test)
table(Predict = predict_test, Truth = test$Purchase)
## Truth
## Predict CH MM
## CH 156 22
## MM 15 77
En el conjunto de prueba \(37\) de las \(270\) observaciones estan mal clasificadas, la máquina de sorporte vectorial con kernel radial tiene una tasa de mala clasificación del \(13.70%\) en el conjunto de prueba. Ambos errores son menores a los obtenidos cuando se uso el parámetro \(cost=0.01\).
Repita las partes (b) a (e) usando una máquina de vectores de soporte con un núcleo polinomial. Establecer \(degree = 2\).
svmfit <- svm(Purchase~., data = train, kernel ="polynomial", cost = 0.01,
scale = TRUE, degree = 2)
summary(svmfit)
##
## Call:
## svm(formula = Purchase ~ ., data = train, kernel = "polynomial",
## cost = 0.01, degree = 2, scale = TRUE)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: polynomial
## cost: 0.01
## degree: 2
## coef.0: 0
##
## Number of Support Vectors: 639
##
## ( 318 321 )
##
##
## Number of Classes: 2
##
## Levels:
## CH MM
Se uso un kernel polinomial de \(2\) grados para el ajuste de la máquina de soporte vectorial, este clasificador tiene \(639\) vectores de soporte, tomo \(318\) de una clase y los restantes \(321\) de la otra clase.
Ahora se calculan las tasas de error producidas por esta máquina.
## Truth
## Predict CH MM
## CH 482 312
## MM 0 6
Se obtiene que \(312\) de las \(800\) observaciones de entrenamiento estan mal clasificadas, es decir, que se obtiene una tasa de mala clasificación del \(39\%\).
## Truth
## Predict CH MM
## CH 171 98
## MM 0 1
En el conjunto de prueba \(98\) de las \(270\) observaciones estan mal clasificadas, la máquina de soporte vectorial con kernel polinomial tiene una tasa de mala clasificación del \(36.2\%\) en el conjunto de prueba.
set.seed(123456)
tune.out <- tune(svm, Purchase~., data = train, kernel ="polynomial",
degree = 2, ranges =list(cost=c(seq(0.01, 10, 0.1))),
scale = TRUE)
El gráfico anterior permite concluir que el valor óptimo para el parámetro \(Cost\) es \(3.41\).
svmfit <- svm(Purchase~., data = train, kernel ="polynomial", cost = 3.41,
scale = TRUE, degree = 2)
Ahora se calculan las tasas de error producidas por la máquina con el parámetro de \(cost\) óptimo.
## Truth
## Predict CH MM
## CH 448 93
## MM 34 225
Se obtiene que \(127\) de las \(800\) observaciones de entrenamiento estan mal clasificadas, es decir, que se obtiene una tasa de mala clasificación del \(15.875\%\).
## Truth
## Predict CH MM
## CH 157 26
## MM 14 73
En el conjunto de prueba \(40\) de las \(270\) observaciones estan mal clasificadas, la máquina de soporte vectorial con kernell polinomial tiene una tasa de mala clasificación del \(14.8148\%\) en el conjunto de prueba.
Ambos errores son menores a los obtenidos cuando se uso el parámetro \(cost=0.01\).
En general, ¿qué enfoque parece dar los mejores resultados con estos datos?
El método que parece proporcionar los mejores resultados es la maquina de soporte vectorial con un kernell radial con \(\gamma = 0.1\) y parámetro \(cost=0.51\).
Finalmente se adjunta el enlace para acceder al ensayo, este fue elaborado sobre el tema de inseguridad en Medellín.