Comparación entre Máquina de Soporte Vectorial, Naive Bayes, Árboles de Decisión y Métodos Lineales

De lo que trata esta entrada.

En la entrada no explico a detalles técnicas sobre cada una de los algoritmos empleados, pero pueden consultarse en las referencias o en las categorías Machine Learning en R project y Machine Learning en Python.

Para el ejemplo solo uso código en R, la intención es usar tres muestras de datos simulados para mostrar las estimaciones que realiza la función svm de la librería e1071, solo en el caso de usarla para clasificar. Y por último uso unos datos  de correos clasificados como spam o no-spam provenientes del repositorio UCI Machine Learning Repository los cuales se encuentran cargados en la librería kernlab de  R project para aplicar las técnicas y comparar svm con otras técnicas.

Ejemplo.-Solo Suppor Vector Machine

En este ejemplo solo hago dos muestras de datos simulados, con distribuciones  Gaussianas y la intención es compartir los detalles de qué es en rasgos generales lo que hace el algoritmo de maquina de soporte vectorial al clasificar datos, esto es para dos dimensiones. Es decir, sobre un plano ya que visualmente se vuelve claro y con esa idea se puede pensar en el tipo de cosas que hace el algoritmo en más dimensiones.

Los primeros datos no se mezclan, por lo cual es visualmente claro como separarlos.

#Datos
#Librerías requeridas para el ejemplo

library(ggplot2)
library(e1071)

#Datos de mezcla 1

N<-500
x1<- rnorm(N) * 0.1
y1<- rnorm(N) * 0.1
X1<- t(as.matrix(rbind(x1, y1)))
x2<- rnorm(N) * 0.1 + 0.5
y2<- rnorm(N) * 0.1 + 0.5
X2<- t(as.matrix(rbind(x2, y2)))
X<- as.matrix(rbind(X1, X2))
X=data.frame(X)
X['Clus']=1
X[500:1000,3]=2
ggplot(X,aes(x=x1,y=y1))+geom_point(size=3,aes(colour=factor(Clus)))+ggtitle('Mezcla 1')+theme(plot.title=element_text(lineheight = 2,face='bold'))+
 xlab('Variable X1')+ylab('Variable Y1')

La gráfica de los puntos se ve así:Mezcla1_Gas

Para la siguiente mezcla considero tres muestras donde las clasifico en dos categorías.

#Mezcla 2
N<-500
x1<- rnorm(500,mean=0,sd=3)*0.1 
y1<- rnorm(500,mean=0,sd=3)*0.1 
X1<- t(as.matrix(rbind(x1, y1)))
x3<- rnorm(250,mean=0,sd=3)*0.1 
y3<- rnorm(250,mean=0,sd=3)*0.1+0.7 
X3<- t(as.matrix(rbind(x3, y3)))
x2<- rnorm(N,mean=1.5,sd=4)*0.1 + 0.5
y2<- rnorm(N,mean=0,sd=3)*0.1 + 0.5
X2<- t(as.matrix(rbind(x2, y2)))
Datos2<- as.matrix(rbind(X1, X3,X2))
Datos2=data.frame(Datos2)
Datos2['Clus']=1
Datos2[600:1250,3]=2
ggplot(Datos2,aes(x=x1,y=y1,colour=factor(Clus)))+geom_point(size=3)+ggtitle('Mezcla 2')+theme(plot.title=element_text(lineheight = 2,face='bold'))+
 xlab('Variable X1')+ylab('Variable Y1')

Mez2_GaussLa gráfica de los datos se ve como la anterior imagen.

Los datos muestran comportamientos distintos, los primeros es claro que se puede separar por una recta, pero la gráfica de la segunda muestra no se ve claramente que lo mejor sea separar los datos por una recta.

Como una buena práctica se debe de tomar una muestra de datos para entrenar el algoritmo (train set) y una cantidad de datos de prueba(test set). Para los siguientes ejemplos considero todos los datos, para ilustrar cual sería la gráfica de los datos predichos por el modelo.

La técnica de SVM para clasificar tienen de fondo la idea de encontrar el mejor “hiperplano” por medio del cual separar los datos. En este ejemplo el concepto de hiperplano es una recta, es decir; los datos están en dos dimensiones (x,y) y se busca la mejor recta que separe los datos, si uno piensa en datos con tres dimensiones (x,y,z) que pueden pensarse como alto, largo y ancho lo que se busca es encontrar el mejor plano que separa los datos, por ello el nombre de hiperplano.

Uso la librería e1071 para estimar el algoritmo SVM con el kernel lineal y radial para la primera muestra de datos, para la segunda uso lineal, polinomial, radial y sigmoid. La intención de este ultimo es compara cual de las cuatro muestra una similitud gráfica más parecida a los datos originales y comparo la tasa de predicciones correctas. Existen más librerías para hacer uso de SVM, dejo en la referencia las ligas.

Primera muestra de datos.

#SVM con Kernel Lineal
#Se procede a dejar una semilla para hacer una elección del mejor valor de parámetro cost

set.seed (1)
#Se hace cross-validation de k-fold, con k=10. Esto mediante la función tune()

tune.out=tune(svm,factor(Clus)~.,data=Datos1,kernel="linear",type='C-classification',scale=FALSE,ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)

#Se elige el mejor modelo con el mejor valor para el parámetro cost

bestmod=tune.out$best.model
summary(bestmod)
# Gráfica del mejor modelo con kernel lineal

plot(bestmod,Datos1)

#Predicción
Pred=predict(bestmod,Datos1)

table(predicción=Pred,Valores_reales=Datos1$Clus)

# Valores_reales
# predicción 1 2
#         1 499 1
#         2 0 500
#Con los valores obtenidos se tiene un 99.9% de eficiencia 

Algunas observaciones, el modelo pasa por un proceso de validación cruzada usando la función tune(), esto siempre es recomendable para elegir un buen modelo. El parámetro cost, significa el nivel de penalización que permite el modelo, en otras palabras el algoritmo busca la mejor recta que separe los datos y como tal el costo para encontrar esa recta requiere tolerar posibles datos que afectan a la estimación de dicha recta. Esto quizás es una explicación burda y mala, pero detrás de todo algoritmo de Machine Learning está un proceso de optimización el cual determina el valor de los parámetros que hacen que el algoritmo tenga el mejor valor posible.

La gráfica que se obtiene de este modelo es la siguiente:

SVM_Muestra1_ker-lineal

 

Esta gráfica muestra las dos clases que se buscaban definir.La eficiencia es muy alta, de 1000 datos clasifica correctamente el 99.9%.

Lo que se espera de otro kernel es que prevalezca la eficiencia de SVM y más aún que la gráfica de la clasificación sea casi igual a la obtenido cuando se usa un kernel lineal.

#Kernel radial
set.seed (1)
tune.out=tune(svm,factor(Clus)~.,data=Datos1,kernel="radial",type='C-classification',scale=FALSE,ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)
bestmod_r=tune.out$best.model
summary(bestmod_r)
plot(bestmod_r,Datos1)
Pred=predict(bestmod_r,Datos1)
table(predicción=Pred,Valores_reales=Datos1$Clus)
# Valores_reales
# predicción 1 2
# 1 499 1
# 2 0 500
#Eficiencia de la clasificación 99.9%

Al obtener la gráfica del modelo por SVM se tiene:

SVM_Muestra1_ker-radial

Lo cual muestra una imagen muy similar a la obtenida con el kernel lineal. La tasa de eficiencia al clasificar es prácticamente la misma, 99.9%

Con la segunda muestra de datos pensar en separar por una recta no parece lo natural. Primero hago la estimación con cuatro tipo de kernels de la función svm y muestro la gráfica que regresa el modelo.

#Segunda muestra de datos
#Se usa primero el kernel lineal

set.seed (1)
tune.out=tune(svm,factor(Clus)~.,data=Datos2,kernel="linear",type='C-classification',scale=FALSE,ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)
bestmod_l=tune.out$best.model
summary(bestmod_l)
plot(bestmod_l,Datos2)
Pred=predict(bestmod_l,Datos2)
table(predicción=Pred,Valores_reales=Datos2$Clus)
# Valores_reales
# predicción 1 2
# 1 504 99
# 2 95 552
#Eficiencia de la clasificación 84.4%

Se tiene la siguiente gráfica como resultado de implementar el algoritmo:

SVM_Mezcla2_ker-lineal

Si se compara los datos que predice el modelo con respecto a los originales se tienen lo siguiente:

Orig_vs_Ker-lineal

Se observa que la predicción muestra totalmente separadas las dos clases y cabe notar que se tiene el 84.4% eficiencia.

#Kernel polinomial

set.seed (1)
tune.out=tune(svm,factor(Clus)~.,data=Datos2,kernel="polynomial",type='C-classification',scale=FALSE,ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)
bestmod_p=tune.out$best.model
summary(bestmod_p)
plot(bestmod_p,Datos2)
Pred=predict(bestmod_p,Datos2)
table(predicción=Pred,Valores_reales=Datos2$Clus)
# Valores_reales
# predicción 1 2
# 0 543 174
# 1 56 477
#Eficiencia de la clasificación 81.6%, con kernel polinomial

La gráfica que se obtiene del modelo es:

SVM_Mezcla2_ker-polin

Y otra vez haciendo una gráfica para comparar la predicción con los datos originales se tiene:

Orig_vs_Ker-pol

Se aprecia que no es tan definida la recta que separa las clases como en el ejemplo del kernel lineal, pero la eficiencia se reduce ya que es de 81.6%

#Kernel sigmoid

set.seed (1)
tune.out=tune(svm,factor(Clus)~.,data=Datos2,kernel="sigmoid",type='C-classification',scale=FALSE,ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)
bestmod_s=tune.out$best.model
summary(bestmod_s)
#Informa del tipo de modelo, del que puede considerarse como el mejor modelo
plot(bestmod_s,Datos2)
Pred=predict(bestmod_s,Datos2)
table(predicción=Pred,Valores_reales=Datos2$Clus)
# Valores_reales
# predicción 1 2
#         1 509 102
#         2 90 549
#Eficiencia de la clasificación 84.6%, con kernel Sigmoid

La gráfica que se obtiene del modelo es la siguiente:

SVM_Mezcla2_ker-sigmoid

Haciendo la gráfica comparativa de predicción y datos originales se obtiene:Orig_vs_Ker-sigmoid

 

Se aprecia que es muy similar a la que se obtiene con el kernel lineal y hasta el nivel de eficiencia resulta muy aproximado, ya que es del 84.6%

#Kernel Radial
set.seed (1)
tune.out=tune(svm,factor(Clus)~.,data=Datos2,kernel="radial",type='C-classification',scale=FALSE,ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)
bestmod_r=tune.out$best.model
summary(bestmod_r)
plot(bestmod_r,Datos2)
Pred=predict(bestmod_r,Datos2)
table(predicción=Pred,Valores_reales=Datos2$Clus)
# Valores_reales
# predicción 1 2
# 1 497 94
# 2 102 557
#Eficiencia de la clasificación 84.3%, con kernel lineal

La gráfica obtenida con este kernel es la siguiente:

SVM_Mezcla2_ker-radial

 

Y al comparar las predicciones con los datos originales se tiene:

Orig_vs_Ker-radial

Se aprecia que es similar a la obtenida por el kernel lineal y sigmoid, más aún la eficiencia resulta ser del 84.3%.

Entonces en resumen los datos al ser clasificados mediante SVM con distintos kernel resultó en estos datos resulta tener mejor eficiencia el kernel sigmoid, por un porcentaje mínimo sobre el lineal.

Para mostrar como se comporta SVM con una muestra de datos altamente no lineales o que resulta difícil separar por medio de una recta , genero una muestra más.

#Datos altamente no lineales

#Distribución uniforme 1250 valores
x1=runif(1250)-0.5
x2=runif (1250)-0.5
#Variable Indicadora
y=1*(x1^2-x2^2> 0)

#Gráfica donde se muestran los puntos pintados por etiqueta de y
#Se contruye un data.frame con los datos
X=data.frame(x1,x2,y)
ggplot(data=X,aes(x=x1,y=x2))+geom_point(aes(colour=factor(y),shape=factor(y)))+ggtitle('Datos Originales')+theme(plot.title=element_text(lineheight = 2,face='bold'))+
 xlab('Variable X1')+ylab('Variable X2')

La gráfica de los datos es la siguiente:

Datos_No-lineales

En esta muestra de datos se aprecia que separar las clases por una recta no parece lo más eficiente, para constatarlo estimo la clasificación con el kernel lineal.

#Kernel lineal
set.seed (1)
tune.out=tune(svm,factor(y)~.,data=X,kernel="linear",type='C-classification',scale=FALSE,ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)
bestmod=tune.out$best.model
summary(bestmod)
#Informa del tipo de modelo, del que puede considerarse como el mejor modelo
plot(bestmod,X)
Pred=predict(bestmod,X)
table(predicción=Pred,Valores_reales=X$y)
# Valores_reales
# predicción 0 1
# 0 305 201
# 1 301 443
#Eficiencia de la clasificación 59.8%

La gráfica que se obtiene del SVM con kernel lineal es:

SVM_Mezcla3_ker-lineal

Haciendo la comparación entre datos originales y las predicciones se tiene lo siguiente:

Orig3_vs_Ker-lineal

Se aprecia que no es muy favorable usar el kernel lineal con estos datos, la eficiencia de la clasificación es del 59.4%

Para comparar con otro kernel uso el radial para hacer la clasificación.

#Kernel Radial

set.seed(1)
tune.out=tune(svm,factor(y)~.,data=X,kernel="radial",sacale=FALSE,type='C-classification',ranges=list(cost=c(0.001,0.01, 0.1, 1,5,10,100)))
tune.out
summary(tune.out)
bestmod=tune.out$best.model
summary(bestmod)
#Informa del tipo de modelo, del que puede considerarse como el mejor modelo
Pred=predict(bestmod,X)
table(predicción=Pred,Valores_reales=X$y)
# Valores_reales
# predicción 0 1
# 0 603 7
# 1 3 637
#Eficiencia de la clasificación 99.2%, con kernel radial

La gráfica que se obtiene con este kernel es la siguiente:

SVM_Mezcla3_ker-radial

Esta imagen muestra que las curvas que se obtienen con el kernel radial son parecidas a las de los datos originales. Haciendo la comparación entre los datos y las estimaciones se obtiene lo siguiente:

Orig3_vs_Ker-Radial

Se aprecia que es muy similar y más aún la eficiencia es del 99.2%, lo cual comparado con el lineal es sumamente mejor usar el kernel radial.

Ejemplo con datos de correos clasificados

Los datos se encuentran cargados en la librería kernelabs, con la cual también se puede estimar la máquina de soporte vectorial. Las comparaciones las hago con varias técnicas:

  • Naive Bayes
  • LDA y Regresión Logística
  • Redes Neuronales
  • Árboles de decisión y random forest

Antes de eso aplico con los cuatro kernel disponibles en svm de e1071 para elegir el que mejor clasificación realiza en la muestra de prueba (test set).

Primero reviso los datos.

#Exploración breve de los datos
#Se cargan primero las librerías

library(kernlab)
library(e1071)
library(MASS)
library(nnet)
librery(randomForest)
data(spam)

#Datos
head(spam)
dim(spam)
#4601 58
str(spam)

#############################################
#Preparación de datos

index=sort(sample.int(4601,1150))
spam.train=spam[-index,]
spam.test=spam[index,]

Se puede hacer algo más al explorar la información, diseñar algunas gráficas o usar alguna técnica de estadística de exploración.

Lo que se hace en el código anterior es dividir los datos entre una conjunto de entrenamiento y un conjunto de prueba.

Aplico los cuatro kernel para elegir el que mejor clasificación realiza.

#SVM con diferentes kernel
########################################
#Kernel lineal

svmfit=svm(type~.,data=spam.train,kernel="linear",cost=0.1,type='C-classification' )
summary(svmfit)
Pred=predict(svmfit,spam.test)
table(predicción=Pred,Valores_reales=spam.test$type)
#         Valores_reales
#predicción nonspam spam
#   nonspam 646 40
#   spam     40 424
#Eficiencia del modelo 93.04%
#######################################
#Kernel radial
svmfit=svm(type~.,data=spam.train,kernel="radial",cost=0.1,type='C-classification' )
summary(svmfit)

set.seed(1)
tune.out=tune(svm,type~.,data=spam.train,kernel="radial",type='C-classification',ranges=list(cost=c(0.001,0.01, 0.1, 1,10,100)))
tune.out
summary(tune.out)
bestmod_r=tune.out$best.model
summary(bestmod_r)
Pred=predict(bestmod_r,spam.test)
table(predicción=Pred,Valores_reales=spam.test$type)
#           Valores_reales
#predicción nonspam spam
#   nonspam     652 36
#   spam         34 428
#Eficiencia del modelo 93.91%
#################################################
#Kernel sigmoid
svmfit=svm(type~.,data=spam.train,kernel="sigmoid",cost=0.1,type='C-classification' )
summary(svmfit)
set.seed(1)
tune.out=tune(svm,type~.,data=spam.train,kernel="sigmoid",type='C-classification',ranges=list(cost=c(0.001,0.01, 0.1, 1,10,100)))
tune.out
summary(tune.out)
bestmod_s=tune.out$best.model
summary(bestmod_s)
Pred=predict(bestmod_s,spam.test)
table(predicción=Pred,Valores_reales=spam.test$type)
#           Valores_reales
#predicción nonspam spam
#    nonspam    649 78
#    spam        37 386
#Eficiencia del modelo 90%
################################################
#Kernel polynomial
svmfit=svm(type~.,data=spam.train,kernel="polynomial",cost=0.1,type='C-classification' )
summary(svmfit)
set.seed(1)
tune.out=tune(svm,type~.,data=spam.train,kernel="polynomial",type='C-classification',ranges=list(cost=c(0.001,0.01, 0.1, 1,10,100)))
tune.out
summary(tune.out)
bestmod_p=tune.out$best.model
summary(bestmod_p)
Pred=predict(bestmod_p,spam.test)
table(predicción=Pred,Valores_reales=spam.test$type)
#           Valores_reales
#predicción nonspam spam
#   nonspam     661 53
#   spam         25 411
#Eficiencia del modelo 93.2%

Se observa en las tasas de error que el mejor kernel de svm es el radial, así que considero este contra el cual comparo las otras técnicas.

Si bien no explico a detalle lo que hace el código en breve es estimar vía tune() la elección del mejor valor de cross-validation de varios valores.

Una técnica clásica para clasificar correos es Naive Bayes, la cual considera ciertas propiedades teóricas que permiten hacer un calculo rápido. Uso NaiveBayes de la librería e1071.

#Naive Bayes vs SVM elegido
NB=naiveBayes(type~.,data=spam.train)
Pred=predict(NB,spam.test)

table(predicción=Pred,Valores_reales=spam.test$type)
# Valores_reales
#predicción nonspam spam
# nonspam 362 18
# spam 324 446
#Se tiene una eficiencia del 70.2% de bien clasificados

Resulta que es mejor el modelo SVM ante el Naive Bayes por un porcentaje altamente mejor.

#Regresión Logística-LDA vs SVM elegido

Mod.lm=glm(type~.,data=spam.train,family='binomial')
summary(Mod.lm)
Mod.lmprob=predict(Mod.lm,newdata=spam.test,type="response")
Mod.pred=rep('nonspam',1150)
Mod.pred[Mod.lmprob>0.5]='spam'
table(Predicción=Mod.pred,Valores_Reales=spam.test$type)
#           Valores_Reales
#Predicción nonspam spam
#   nonspam 643 39
#   spam     43 425
#Predicción 92.86%
############################################
#Método LDA
lda.fit=lda(type~.,data=spam.train)
lda.pred=predict(lda.fit,spam.test)
lda.class=lda.pred$class
table(Predicción=lda.class,Valores_Reales=spam.test$type)
#lda.class nonspam spam
#   nonspam    650 91
#   spam        36 373
#Tasa de eficiencia 88.9%

Se tienen que el porcentaje de eficiencia en la clasificación de SVM 93.91% es mayor de casi 1% mejor que los métodos lineales, en este caso la regresión logística resulta ser la mejor entre las técnicas lineales.

Sin explicar detalles elijo un modelo de redes neuronales para clasificar, la librería es nnet y la función tienen el mismo nombre.

#Redes Neuronales
red=nnet(type~.,data=spam.train,size=2)
Pred=predict(red,spam.test,type="class")

table(Predicción=Pred,Valores_Reales=spam.test$type)
# Valores_Reales
#Predicción nonspam spam
# nonspam 650 29
# spam 36 435
#Tasa de eficiencia 94.34%

Resulta que el modelo de redes neuronales resulta ser mejor casi 0.5% mejor que el modelo de SVM. Lo cual faltaría hacer una revisión para definir el mejor modelo de redes neuronales y quizás la mejora es mejor o nula pero tendrías los valores óptimos de los parámetros.

#Dos técnicas de arboles
# La primera es por árboles y se hace cross-validation para elegir el mejor modelo
 
tree.spam=tree(type~.,spam.train)
set.seed (3)
cv =cv.tree(tree.spam,FUN=prune.misclass )

#Gráfica de Cross-validation para elegir el mejor valor de del parámetro best
par(mfrow =c(1,2))
plot(cv$size,cv$dev,type="b",col="2")
plot(cv$k,cv$dev,type="b",col="3")

prune.tree=prune.misclass(tree.spam,best=8)
tree.pred=predict(prune.tree,spam.test,type="class")
table(tree.pred,Valores_Reales=spam.test$type)

#         Valores_Reales
#tree.pred nonspam spam
#  nonspam 644 58
#  spam     42 406
#Tasa de clasificación 91.3%
#################################################
#Modelo de Random Forest

set.seed (1)
rf.spam =randomForest(type~.,data=spam.train,mtry=7, importance =TRUE)
rf.pred_spam=predict(rf.spam,newdata=spam.test,type="class")

table(rf.pred_spam,Valores_Reales=spam.test$type)
#            Valores_Reales
#rf.pred_spam nonspam spam
#     nonspam 663 29
#     spam     23 435
#Tasa de clasificación 95.4%

Revisando la tasa de clasificaciones correcta por medio de las técnicas de árboles de decisión , resulta ser la mejor técnica para clasificar los datos de los correos. Se obtienen que la técnica de Random Forest resulta clasificar correctamente el 95.4%, comparado con la red neuronal y SVM es mejor casi en un 2%.

La única intensión de este ejemplo es hacer una comparación entre diversas técnicas de clasificación, de cierto modo hacer un ejemplo sencillo y que se puede replicar. Ha esto le faltaría agregar algunos gráficos que muestran los resultados o hacer algunas variaciones de los parámetros requeridos en cada algoritmos para determinar con mejor eficiencia el mejor modelo.

Espero ilustre de manera breve la variedad de técnicas y permita visualizar que al final se requiere probar con muchos modelos para elegir uno entre todos los realizados.

Algoritmos de Machine Learning en R project

“The best thing about R is  that it was developed by statisticians. The worst thing about R is that….it was developed by statisticians.”  Bo Cowgill, Google, Inc.

Todas las entradas de esta categoría muestran algoritmos y técnicas clasificadas como algoritmos de Machine Learning o Aprendizaje Estadístico. En cada entrada comparto el código  y algunos repositorios donde pueden bajar datos y notas sobre los temas.

Las ventajas de usar R project para dar estos ejemplos son las siguientes:

1.-R project es software libre u open source, por lo cual cualquier persona pude descargarlo.

2.-El código que comparto solo debe de ser copiado y pegado en un Script o en la consola  de R project para reproducir los resultados.

Otra ventaja de aprender estas técnicas con ejemplos en R, es que muchos de los algoritmos son acompañados de alguna técnica gráfica para visualizar el resultado. R project por default cuenta con una gran cantidad de herramientas gráficas o se puede hacer uso de librerías como ggplot2, lattice, ggvis para hacer gráficas aún más elaboradas y visualmente más agradables.

El entendimiento de la técnica después de realizar un ejemplo desde mi perspectiva genera interés por saber como aplicarla a otros datos y nos invita a conocer más sobre el algoritmo desde un punto de vista no solo práctico, sino también teórico.

Evité en la medida de lo posible hacer uso de ecuaciones y en cada ocasión que se menciona algún concepto de matemáticas trato de explicarlo de un modo sencillo. Si este concepto requiere a mi parecer una mejor lectura, agregue algunas ligas para consultar en la red.

La única meta que me propuse fue explicar las cosas de modo tal que cualquier persona con un poco de curiosidad pueda entender algo de cada entrada.

Teniendo en mente lo anterior, espero que  el objetivo de trasmitir el conocimiento desde un ejemplo concreto haya sido logrado. En caso de que no sea así, sería grato saber qué parte no es clara y como mejorar este material.

Resumen de las entradas.

El orden siguiente es el que considero apropiado para revisar cada entrada.

1.-¿Qué se necesita conocer de R project para aprender algunas técnicas de Machine Learning?

Es una breve explicación sobre R project y sobre algunas de las funciones con las que cuenta por default. También menciono las librería que se requieren para replicar los ejemplos, aunque en cada entrada menciono algo breve sobre la librerías requeridas.

2.-Análisis Confirmatorio vs Exploratorio

Explico la diferencia entre los dos tipos de análisis y cómo están relacionados. Clasifico el tipo de medidas que uno puede analizar en los datos y pongo algunos ejemplos del tipo de gráficas que pueden ayudarnos a visualizar las medidas al momento de explorar la información.

3.-Regresión Lineal, un ejemplo sencillo.

Esta técnica es muy sencilla de implementar y los datos que nos regresa el comando en R debe ser entendidos para poder evaluar la calidad del resultado obtenido. Omito detalles formales del tema y comparto algunos ejemplos de regresiones simples y múltiples. Es un tema con muchos detalles importantes, por ejemplo la revisión de las posibles fallas al construir un modelo lineal o multilineal. No toco mucho  esos temas, pero en las referencias pueden encontrar observaciones y técnicas para conocer más al respecto.

4.-Regresión no lineal, Cross-Validation y Regularization. 

Los tres temas pueden haber requerido una entrada para cada uno, pero funciona bien mostrar como se relacionan. El objetivo es mostrar la implementación de la regresión no lineal y validar que el modelo elegido es el adecuado, para evitar la sobre estimación de los datos. En esto último las cross-validation y la regularización ayudan a tener un método para hacer una elección del modelo. Se dan algunos ejemplos del uso de los tres conceptos y técnicas.

5.-Clasificación binaria….Naive Bayes. 

Es uno de los algoritmos más usados por sencillo y por que puede ser modificado para tener una clasificación rápida en varias categorías. Doy el ejemplo clásico sobre detección de Spam y trato de complementarlo con el uso de una librería en la cual se cuenta con una función para estimar el modelo. Agregué una pequeña explicación sobre la probabilidad condicional y sobre el uso de la librería tm para analizar textos en R project. Espero ser claro y que permita comprenderse el ejemplo.

6.-Análisis de Cluster, un ejemplo sencillo. 

Se explica de modo breve como funciona la detección de Clusters. Como el tema requiere hacer uso de la noción de distancia o métrica, trato de explicar el concepto. Omití mucho material, sobre todo en el uso de distintas métricas para distintos tipos de variables.

7.-Un ejemplo sencillo sobre Análisis de Componentes Principales (PCA, Principal Component Analysis).

La técnica es muy usada y conocida para hacer reducción de dimensiones, explico qué es reducir dimensiones y como interpretar los resultado de la técnica. Como ejemplo principal hago una reducción de 25 indicadores para formar uno que resuma la información del resto. Replico un ejemplo de análisis de la digitalización de los números escritos a mano, este es un ejemplo clásico y la base de datos fue objeto de estudio para comparar técnicas de clasificación.

8.-Sobre sistemas de recomendación, ejemplo sencillo. 

Hago un breve ejemplos de un sistema de recomendación usando la técnica de k-vecinos cercanos (K-nn), esta técnica es no-paramétrica. Para ejemplificar como funciona pongo un ejemplo inicial y trato de explicar qué realiza el algoritmo y aplicarlo a un caso concreto. Los sistemas de recomendación prácticamente dan la libertad de elegir la técnica de clasificación que uno considere adecuada para el tipo de datos o servicio, por lo cual existen libertad de replicar este ejemplo haciendo uso de otro técnicas de clasificación.

9.-Optimización.

Esta entrada creo que es extensa y puede ser un poco amplia,ya que traté de explicar desde aspectos básicos de mínimo y máximos hasta algoritmo estocásticos y genéticos. Puse un ejemplo de como usar el código y en los casos más sofisticados, la parte estocástica, comparto un ejemplo que permitiera comparar los resultado obtenidos con diversos tipos de algoritmos, no puse los tiempos que tardan en dar la solución pero en caso de replicarlos será notorio el costo del procesamiento.

10.-Máquina de soporte Vectorial (SVM-Sopport Vector Machine).

La técnica sumamente usada y funciona bien para datos no-lineales, se dan varios ejemplos de como usar dos librerías que permiten calcular SVM con distintos kernels. En uno de los ejemplos de hace la comparación de varios modelos para determinar por medio de MSE cual es el mejor. Son ejemplos muy sencillos y trato de agregar explicaciones a cada ejemplo.

Lo que no está aún en estas entradas, pero que estará en inicio de Marzo 2016.

Dejé fuera por el momento varios temas fuera de las entradas, ejemplo Redes neuronales , Arboles de decisión, Random Forests, AdaBoost. Espero posteriormente agregar entradas sobre esos algoritmos.

En general todos las entradas tratan de simplificar y resumir lo que se puede encontrar en el texto  “Machine Learning for Hackers“, libro escrito por Jhon M. White y Drew Conway. Si bien, el libro en si es sencillo y requiere un bajo nivel de matemáticas para estudiarse, traté de hacer más sencillas las explicaciones y de complementarlo con otros ejemplos.

La recomendación es complementar las explicaciones de las entradas con la lectura del texto.  Jhon M White compartió su código  y datos usados en los ejemplos en el repositorio Github y pueden descargar el código presionando estas letras en rojo.

Algunos de los códigos deben de revisarse ya que las librerías que usaron en el año de la edición del texto ya fueron actualizadas, por lo cual es generan algunos errores.

Dos temas que vienen en el texto y decidí omitir son generación de un rango y análisis de redes sociales o de grafos. En otro momento comparto ejemplos respecto al tema.

El segundo es sumamente interesante; análisis de redes sociales, pero el código con el que cuenta el texto ya no es funcional. Así que se requiere rehacer buena parte del código y diseñar nuevos ejemplos, para eso se necesita cierto tiempo. Más aún debido al boom de las redes sociales existen otro tipo de herramientas sobre las cuales se puede escribir.

Para tener una idea de lo nuevo e interesante se pueden consultar las siguientes ligas para echar un vistazo:

Deseo que el material que se encuentra en esta categoría les sea útil y sobre todo les deje con ganas de aprender más al respecto y no solo desde el lado aplicado, sino también desde el lado teórico.

En la siguiente cita aplique “instrumento= algoritmo”.

“Tienes que aprender a tocar tu instrumento. Después debes practicar, practicar y practicar. Y después, cuando finalmente estás en el escenario, olvídalo todo y ulula.” Charlie Parker

 Nota: Todas las críticas y comentarios respecto a las entradas son bienvenidos.

Regresión no lineal, Cross-Validation y Regularization.

En esta entrada sigo la postura del texto Machine Learning for Hackers[1], la cual es explicar los tres temas juntos para mostrar como se conectan. Se pueden revisar por separado de manera amplia y desde una perspectiva estadística en la referencia [2].

En breve, se puede mencionar que Cross-Validation y Regularization funcionan bien usándolos para determinar un buen modelo o determinar cuando se está “sobre estimando” o “sobre ajustado” (overfitting).

La regresión no-lineal, como su nombre lo indica; es además de una generalización de la regresión lineal, también otra opción para construir un modelo. Al ser más general, no es extraño que se pueda caer en la idea de pensar que cuanto más complejo el modelo es mejor, lo cual no es necesariamente cierto.

Algo que suele ocurrir es que uno busca por medio de un modelo lineal estudiar un fenómenos no lineales, o en otro caso implementar alguna técnica que funciona bien con fenómenos no lineales en fenómenos que pueden ser “bien” estudiados con modelos lineales. Por lo cual es importante explorar la información y tratar de construir más de un modelo, lineal o no-lineal y hacer uso de herramientas para determinar cual es un mejor modelo.

Sobre la idea de complejidad de un modelo, se pude hacer un análisis bastante serio al respecto, pero uno se acercaría al concepto de complejidad  y este puede tener varios puntos de vista los cuales dejo sin detalle en esta entrada, basta mencionar que la complejidad tienen varias aristas y puntos de vista, que van desde temas de matemática puras hasta temas de sistemas complejos y teoría de computación.

Hago un  primer  un ejemplo de ajuste lineal y no-lineal.

#Ejemplo no lineal
x<-seq(-10,10,by=0.01)
y<-1-x^2+rnorm(length(x),0,7)
ggplot(data.frame(X=x,Y=y),aes(x=X,y=Y))+geom_point(col=2)+geom_smooth(size=3,method='lm',se=FALSE)
ggplot(data.frame(X=x,Y=y),aes(x=X,y=Y))+geom_point(col=2)+geom_smooth(size=3,se=FALSE)

Ajuste_LinealAjuste_No-Lineal

La gráfica muestra que al calcular de manera lineal la regresión, la recta estimada corta los datos y al calcular la regresión no-lineal se estima una curva, la cual parece un mejor ajuste. Pero si pensamos en transformar los datos de entrada, elevándolos al cuadrado, se obtiene otro tipo de comportamiento.

#Ejemplo de ajusto con datos transformados
x.cuadrados<-x^2
ggplot(data.frame(X.Cuadrados=x.cuadrados,Y=y),aes(x=X.Cuadrados,y=Y))+geom_point(col=2)+geom_smooth(size=3,se=FALSE)+ ggtitle("Ajuste de datos transformados")+theme(plot.title = element_text(lineheight=.8, face="bold"))

 

Ajuste_No_lineal_con_datos_transformados

La gráfica anterior muestra casi una relación lineal con el ajuste no-lineal, se puede revisar los residuos o la r cuadrada para estimar cuanto de la variabilidad de Y es explicada con los ajustes. Lo hago en R  por medio del comando summary y el resultado es el siguiente:

#Revisamos las estimaciones
> summary(lm(y~x))$r.squared
[1] 0.0001486085
> summary(lm(y~x.cuadrada))$r.squared
[1] 0.9444159

En el ejemplo se observa como una transformación en los datos hace que se pase de un ajuste que explica prácticamente el 0%, a un ajuste que explica casi el 95% de la variabilidad de los datos de salida.

Del ejemplo se puede concluir, que una transformación  hace una gran diferencia y en este caso beneficia al modelo, pero lo que no se visualiza es el costo de transformar los datos, nada limita a pensar que se  puede considerar cualquier potencia de la información y revisar el ajuste. Con potencia me refiero a elevar a la tercera, cuarta o quinta potencia nuestros datos de entrada.

Antes de abordar el problema de determinar cuando un ajuste no-lineal es mejor que otro, hago otro ejemplo para mostrar los ajustes no-paramétricos. Para este ejemplo uso datos que pueden descargarse desde la página de Robert H.Shumway.

#Serie de tiempo de la mortalidad cardiovascular
mortalidad<-scan("cmort.dat")
t=1:length(mortalidad)
lm(mortalidad~t)
t2=t^2
t3=t^3
c=cos(2*pi*t/52)
s=sin(2*pi*t/52)
fit=lm(mortalidad~t+t2+t3+c+s)
#Graficamos el ajuste
plot(t,mortalidad,type="p",main="Datos de Mortalidad Cardiovascular",xlab="Tiempo",ylab="Cantidad de muertes",lwd="2")
lines(fit$fit,col="2")
abline(a=96.65,b=-0.0312,col="3")
lines(lowess(t,mortalidad),col="4")
lines(ksmooth(t,mortalidad,"normal",bandwidth=104),col="5")
lines(ksmooth(t,mortalidad,"normal",bandwidth=5),col="6")

Regresiones_lineales_y_nolineales

La gráfica del ejemplo anterior muestra varios ajustes, el primero es el lineal, el segundo el polinomial y el tercero y cuarto son métodos no paramétricos que pueden ser considerados como extensiones de la regresión polinomial (regresión no-lineal). Cada uno muestra cierto comportamiento, y puede servir para explorar la información y posteriormente pensar en el tipo de modelo que se puede construir. Con la gráfica anterior solo trato mostrar que las regresiones no se limitan solo a lo lineal y no-lineal, uno puede hacer uso de técnicas no-paramétrica para estimar otro tipo de regresiones. Para mayor detalles se puede revisar la presentación de Andrew W. Moore [3].

Lo que hago ahora es enfocarme a la regresión polinomial, construyo un ejemplo por medio del cual comparo el ajuste lineal y el polinomial.

#Ejemplo no lineal
x<-seq(0,1,by=0.01)
y<-sin(2*pi*x)+rnorm(length(x),0,0.1)
df<-data.frame(X=x,Y=y)
ggplot(df,aes(x=X,y=Y))+geom_point()+ggtitle("Relación no lineal")+theme(plot.title = element_text(lineheight=.8, face="bold"))

Relación_No_Lineal

Se observa en la gráfica que los datos parecen como si estuvieran en una montaña rusa, tienen partes altas y bajas. Pareciera que siguen una trayectoria curva y queda pensar en aplicar dos regresiones, una lineal y otra polinomial.

#Ajuste lineal y polinomial
summary(lm(Y~X,data=df))
Call:
lm(formula = Y ~ X, data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.91351 -0.39942  0.02522  0.39833  0.98606 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.94573    0.09068   10.43   |t|)    
(Intercept)  -0.13568    0.04621  -2.936  0.00415 ** 
X            11.50556    0.40215  28.610  < 2e-16 ***
X2          -33.75407    0.93713 -36.018  < 2e-16 ***
X3           22.55399    0.61585  36.622  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1204 on 97 degrees of freedom
Multiple R-squared:  0.9726,    Adjusted R-squared:  0.9717 
F-statistic:  1147 on 3 and 97 DF,  p-value: < 2.2e-16

De los ajuste se  puede observar que el lineal explica aproximadamente el 59% y el polinomial con un polinomio de grado 3, explica aproximadamente el 97%. Pero nada limita a considerar polinomios de grado mayor, hago la estimación con un polinomio de grado 14 y  comparo como se comporta el ajuste, para esto usamos la función poly de R.

#Ajuste lineal y polinomial
summary(lm(Y~poly(X,degree=14),data=df))
Call:
lm(formula = Y ~ poly(X, degree = 14), data = df)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.243497 -0.066481 -0.001563  0.066558  0.240361 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)             0.004371   0.009707   0.450    0.654    
poly(X, degree = 14)1  -5.516374   0.097551 -56.549  < 2e-16 ***
poly(X, degree = 14)2   0.058760   0.097551   0.602    0.549    
poly(X, degree = 14)3   4.410330   0.097551  45.211  < 2e-16 ***
poly(X, degree = 14)4  -0.034386   0.097551  -0.352    0.725    
poly(X, degree = 14)5  -0.708767   0.097551  -7.266 1.58e-10 ***
poly(X, degree = 14)6  -0.005587   0.097551  -0.057    0.954    
poly(X, degree = 14)7   0.155736   0.097551   1.596    0.114    
poly(X, degree = 14)8   0.147905   0.097551   1.516    0.133    
poly(X, degree = 14)9   0.022788   0.097551   0.234    0.816    
poly(X, degree = 14)10  0.055761   0.097551   0.572    0.569    
poly(X, degree = 14)11 -0.087618   0.097551  -0.898    0.372    
poly(X, degree = 14)12  0.003417   0.097551   0.035    0.972    
poly(X, degree = 14)13  0.147284   0.097551   1.510    0.135    
poly(X, degree = 14)14 -0.075299   0.097551  -0.772    0.442    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.09755 on 86 degrees of freedom
Multiple R-squared:  0.984,     Adjusted R-squared:  0.9814 
F-statistic: 378.9 on 14 and 86 DF,  p-value: < 2.2e-16

Se observa que el ajuste explicado por el polinomio de grado 14 es del 98% de variabilidad en los datos, por cual puede hacer pensar que es mejor modelos, comparando los 3 que realicé.

Pero nada hace especial el polinomio de grado 14 con respecto a cualquier otro, bien podrías preferir uno de grado 20, 30 o 50.

Si reviso la R cuadrada de varios modelos polinomiales de grado mayor que 14 obtendré que explican del 98% en adelante y claro sin llegar  explicar el 100%. Pero el problema que surge tienen que ver con la siguiente pregunta,¿cómo elegir el mejor modelo de entre un conjunto de modelos?

En Machine Learning la idea no es encontrar un solo modelo, es construir varios, ya que más de una técnica puede funcionar para el mismo tipo de situación. Pero resulta crucial tener un modo o método para  elegir entre todos los modelos posibles.

Cross-Validation y Regularization

“All models are wrong, but  some models are userful”.

George Box

Este tema puedo ser consultado para más detalles y breve en las famosas nota de Andrew Ng, pero también de modo breve puede ser revisado en las notas de Andrew W. Moore. Recomiendo las notas del último, son más amigables ya que las de Andrew Ng requieren formación en matemáticas (probabilidad, álgebra lineal y cálculo de varias variables). Para ver estos dos temas de manera amplia en la referencia[2]

La idea de Cross-Validation es la siguiente:

  1. Elegir dos conjuntos, el de entrenamiento (training set) y el de prueba (test set).
  2.  Estimar el modelo en los datos de entrenamiento.
  3. Calcular MSE o RMSE de los datos de prueba.
  4. Comparar entre los Modelos con datos del paso 3.

En general se elige de todos los datos un 80-20 o 70-30,  es decir; 80% de los datos para entrenamiento y 20% para prueba. Pero se pueden tener algunos problemas con esto, el principal es que si el modelo requiere muchos datos por ser no-paramétrico es posible que la estrategia falle si no se cuenta con suficientes datos. Entonces se hace uso de una técnica conocida como LOOCV (Leave-one-out Cross-Validation), que en lugar de fijar el 20% para prueba solo no se considera uno de los datos, se calcula el modelo y se mide el error del dato no considerado y se hace ese proceso para toda la información, por último se calcula MSE o RMSE con la información de los errores.

Puede parecer que LOOCV cumple bien ante las situaciones donde la cantidad es importante, pero se puede usar otra alternativa, en lugar de hacer solo para una muestra de 20% fija, se divide la muestra en una cantidad finita de subconjuntos. Suponemos en K subconjuntos disjuntos, entonces se hace la estimación del modelo con cada uno de los subconjuntos tomados como el conjunto de prueba y se procede a calcular MSE o RMSE. Esta técnicas se llama K-Fold Cross Validation

La regularización está íntimamente relacionada con el concepto de complejidad en un modelo, se puede pensar que tener un modelo de un polinomio de grado 3 es más complejo que un polinomio de grado 2. Los fundamentos teóricos están relacionados con la noción de un “espacio normado“. No explico a que se refiere el último concepto, lo que interesa en esta entrada es entender cómo validar que un modelo es más complejo que otro.

Como la idea no es desarrollar la teoría, entonces lo que hago es usar una librería en R que realiza la estimación de los modelos lineales generalizados (GLM). Parte de sus algoritmos de estimación se realiza por regularización, así se puede usar uno de sus parámetros de estimación como medida de regularización.

Antes de hacer el ejemplo en R, lo que hago es mostrar como estimamos un modelo de regresión polinomial con respecto a unos datos y analizar el parámetro de regularización por medio de cross-validation para determinar cual es el mejor modelo. Considero que desea usar como modelo la regresión de un polinomio de grado 10, así se elige un conjunto de entrenamiento (training set) y uno de prueba (test set).

#Ejemplo del uso de regularización y cross-validation
x<-seq(0,1,by=0.01)
y<-sin(2*pi*x)+rnorm(length(x),0,0.1)
n<-lenght(x)
indices<-sort(sample(1:n,round(0.5*n))
training.x<-x[indices]
training.y<-y[indices]
test.x<-x[-indices]
test.y<-y[-indices]
df<-data.frame(X=X,Y=y)
training.df<-data.frame(X=training.x,Y=training.y)
test.df<-data.frame(X=test.x,Y=test.y)
#Usamos el conjunto de entrenamiento
glmnet.fit<-with(training.df,glmnet(poly(X,degree=10),Y)
lambdas<-glmnet.fit$lambda
modelo<-dta.frame()
for( lambda in lambdas){
modelo<-rbind(modelo,data.frame(Lambda=lambda,RMSE=rsme(test.y,with(test.df,predict(glmnet.fit,poly(X,degree=10),s=lambda)))))
}
#Visualizamos la relación entre Lambdas vs RMSE
ggplot(modelo,aes(X=Lambda,Y=RMSE))+geom_point()+geom_line()
#Elegimos Lambda que minimiza RMSE
best.lambda<-with(modelo, Lambda[which(RMSE==min(RMSE))])
glmnet.fit<-with(df,glmnet(poly(X,degree=10),Y))
#Visualizamos los coeficientes estimados del "mejor" modelos
coef(glmnet.fit,s=best.lambda

Del código anterior y del proceso que se realiza, se puede concluir que entre las dos herramientas Regularización y Cross-Validation se puede elegir el modelo que tienen menos “desviación estándar” en la distribución de los errores.

Se aprecia en la gráfica de abajo que el mínimo de la curva  ayuda a determinar el mejor modelo.

Lambda_vs_RMSE

 Caso de estudio

El siguiente ejemplo forma parte de los ejemplos presentados en el texto de Machine Learning for Hackers[1]. Lo que se hace en el texto es tomar datos de los 100 libros más populares de la editorial O’Reilly y tratar de definir partiendo de los textos de las contra portadas el posible éxito o alta venta.

Para desarrollar el ejemplo se usan las librerías tm y glmnet. Por medio de la primera se construye una matriz mediante los textos de la contra portada y ya teniendo la matriz se usa la regresión lineal general contra una variable para tratar de definir un rango de ventas partiendo de la lista de palabras que  contiene.

Mediante de la regularización (lambda) y la cross-validation, se trata de elegir el modelo que minimice RMSE con respecto al parámetro lambda del modelo.

#Análisis de contra-portadas
rango<-read.csv(data.file,stringsAsFactor=FALSE)
documentos<-data.frame(Texto=rango$Long.Desc.)
row.names(documentos)<-1:nrow(documentos)
library(tm)
corpus<-Corpus(DataframeSource(documentos))
corpus<-tm_map(corpus, content_transformer(tolower))
corpus<-tm_map(corpus,stripWhitespaces)
corpus<-tm_map(corpus,removeWords,stopwords('english'))
dtm<-DocumentTermMatrix(corpus)

rendimiento<-data.frame()

for(lambda in c(0.1,0.25,0.5,1,2,2.5))
{ 
  for ( i in 1:50){

    indices<-sample(1:100,80)
    training.x<-x[indices,]
    training.y<-y[indices]
    test.x<-x[-indices,]
    test.y<-y[-indices]
    glmnet.fit<-glmnet(training.x,training.y)
    prediccion.y<-predict(glm.fit,test.x,s=lambda)
    rmse<-sqrt(mean((prediccion.y-test.y)^2))
    rendimiento<-rbind(rendimiento,data.frame(Lambda=lambda,Interaccion=i,RMSE=rmse))
    }
}

El código anterior hace los siguiente:

  1. Se define el rango del parámetro de regularización (lambda).
  2. Se eligen subconjunto, 80% para entrenamiento y 20% para probar.
  3. Se estima la regresión y se compara contra el conjunto de prueba, con esta comparación se calcula RMSE para cierto lambda.

Análisis_Text_RMSE vs Lambda

Análisis_Text_RMSE vs Lambda2

 

La primera gráfica muestra que no se logra definir un buen modelo. En general RMSE vs Lambda nos indican que no se puede obtener mucho de los datos analizados, es decir; no resulta evidente como poder distinguir entre los 50 libros más vendidos con ese modelo.

Por lo cual se hace uso de una variable dummy para pasar de una regresión a una clasificación, por medio de la cual se puede responder cuando un libro es considerado uno de los 50 más vendidos solo partiendo de su contra portada. En este ejemplo no se trata solo de hacer el modelo, sino de verificar mediante regularización y cross-validation como es posible elegir un modelo con menor complejidad o uno mejor entre los posibles

Las observaciones y pasos a seguir son los siguientes; al usar la variable dummy y aplicar una regresión logística, se eligen subconjuntos de entrenamiento y prueba. Después de varias interacciones se puede analizar el comportamiento del parámetro lambda y  en lugar de RMSE  se usa la tasa de errores entre las predicciones y el subconjunto de prueba.

#Análisis de contra-portadas
y <- rep(c(1, 0), each = 50)
regularizacion.fit <- glmnet(x, y, family = 'binomial')
predict(regularizacion.fit, newx = x, s = 0.001)
ifelse(predict(regularizacion.fit, newx = x, s = 0.001) > 0, 1, 0)

performance <- data.frame()

for (i in 1:250)
{
 indices <- sample(1:100, 80)
 
 training.x <- x[indices, ]
 training.y <- y[indices]
 
 test.x <- x[-indices, ]
 test.y <- y[-indices]
 
 for (lambda in c(0.0001, 0.001, 0.0025, 0.005, 0.01, 0.025, 0.5, 0.1))
 {
 glm.fit <- glmnet(training.x, training.y, family = 'binomial')
 
 predicted.y <- ifelse(predict(glm.fit, test.x, s = lambda) > 0, 1, 0)
 
 tasa.error <- mean(predicted.y != test.y)

 performance <- rbind(performance,data.frame(Lambda = lambda,Iteration = i,TasaError = tasa.error))
 }
}

ggplot(performance, aes(x = Lambda, y = ErrorRate)) +
 stat_summary(fun.data = 'mean_cl_boot', geom = 'errorbar') +
 stat_summary(fun.data = 'mean_cl_boot', geom = 'point') +
 scale_x_log10()

 Análisis_Text_Tasa_Error vs log_ Lambda

En conclusión, se observa que al realizar el proceso con una regresión logística, se puede analizar el comportamiento de lambda y la tasa de error. Por lo tanto se puede clasificar los textos y elegir un modelo con la tasa de error correspondiente a lambda menor (como en la gráfica anterior).

¿Por qué el último modelo permite hacer una elección entre ellos y el anterior no?

El último modelo muestra constancia en la tasa de error, entonces se puede considerar que la menor Lambda hace considerar al modelo como el mejor.

En el modelo previo no se veía un patrón definido, elegir el que tiene menor RMSE o la menor Lambda no asegura que se este haciendo una buena elección.

Lo anterior puede parecer superficial, pero pensándolo un poco no es  una mala estrategia proceder con una variable dummy para modificar el modelo y tomar las tasas de error en lugar de RMSE.

Espero la entrada de una idea general de como se usa la regularización y la cross-validation, también como el modelo no-lineal puede beneficiarnos en algunos casos. En otra ocasión espero extender los ejemplo y hacer otro que puedan ayudar a clarificar los conceptos.

Algunas cosas que desearía fortalecer de esta entrada más adelante es resaltar con otro ejemplo como la regresión logística toma un rol de método de clasificación lineal, el rol de la regularización y la validación-cruzada o cross-validation para elegir modelos. Un par de buenos artículos sobre el tema se pueden ver en las referencias [2,5,6,7].

 Referencias:

1.-http://shop.oreilly.com/product/0636920018483.do

2.-http://statweb.stanford.edu/~tibs/ElemStatLearn/

3.-http://openclassroom.stanford.edu/MainFolder/DocumentPage.php?course=MachineLearning&doc=exercises/ex5/ex5.html

4.-http://www.amazon.com/Machine-Learning-Probabilistic-Perspective-Computation/dp/0262018020

5.-http://robjhyndman.com/hyndsight/crossvalidation/

6.-http://stats.stackexchange.com/

7.-http://projecteuclid.org/download/pdfview_1/euclid.ssu/1268143839