Como parte del curso “Seminario de Estadística: Herramientas Estadísticas para Ciencia de Datos”, esta semana nos enfrentaremos a un problema de aprendizaje supervisado donde vamos a crear un modelo para clasificar datos. Usaremos una base llamada “fraud_email.csv” que contiene dos variables, la primera es un string llamado “Text”, el cual es el cuerpo de un email, y la segunda es la variable binaria “Class” que nos indica 0 si no es spam o 1 si el correo es spam.
A continuación se presentan los requerimientos que se nos solicitan.
La respuesta es si, el algorítmo SVM es un clasificador lineal con las característica de que no asume ninguna distribución a los datos y directamente busca el hiperplano óptimo que separa los datos en clases.
Para esta parte creamos 3 variables, la primera es una variable que cuenta cuantas faltas de ortografía hay en el cuerpo del email, estás son del tipo “.A”, es decir que no hay espacio entre el punto y la letra siguiente. La segunda variable cuenta cuantos signos de igual “=” hay en email. Y la tercera cuenta cuantos caracteres del tipo “2e” o “e3” hay en el email, es decir un número seguido de una letra o una letra seguida de un número.
Al analizar el csv me di cuenta que los correos que resultaban ser spam, tenían la particularidad que había faltas de ortografía clave. Por ejemplo siempre que había muchos signos de igualdad resultaba ser spam, y pasaba lo mismo cuando no había espacios o una letra venia seguida de un número.
Se construyo un modelo SVM. Donde las variables resultaron ser significativas y al ajustarlo y hacer las predicciones tuvimos un AUC de al menos 78%, y esto puede cambiar debido a que escogimos el 70% de los datos sin hacer validación cruzada. Pero en el peor de los casos al menos nuestro modelo predice el 78% bien.
Así creamos las variables.
for (i in 1:length(data[,1])) {
data[i,4] = str_count(str_to_lower(data[i,1]),
"\\.(?=[:alpha:])|[:alpha](?=\\.)")
}
for (i in 1:length(data[,1])) {
data[i,5] = str_count(str_to_lower(data[i,1]),
"=")
}
for (i in 1:length(data[,1])) {
data[i,6] = str_count(str_to_lower(data[i,1]),
"[:digit:](?=[:alpha:])|[:alpha:](?=[:digit:])")
}
for (i in 1:length(data[,1])) {
data[i,7] = str_count(str_to_lower(data[i,1]),
"<|>|@")
}
Esta es nuestra matriz de confusión.
# Partimos los datos.
t.id <- createDataPartition(data$class, p = 0.7, list = F)
# Creamos el modelo SVM
mod <- svm(class ~ V4 + V5 + V6, data = data[t.id,], type = "C-classification",
kernel = "sigmoid")
# Hay mejor accurracy con linear y sigmoid
# Predecimos los datos
pred <- predict(mod, data[-t.id,])
# Creamos la matriz de confusión
table(data[-t.id,]$class, pred)
## pred
## 0 1
## 0 1902 120
## 1 548 1008
Esta es la curva ROC de nuestro modelo, podemos notar que esta pegada al 1, y que el AUC en esta prueba es bueno.
# Creamos una curva de ROC
rocobj <- roc(n.data$class, as.numeric(n.data$pred))
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
plot.roc(rocobj,print.auc=T,print.thres = "best",
col="blue",xlab="1-ESpecificidad",ylab="Sensibilidad")