El objetivo de este notebook es representar oraciones mediante el modelo GloVe. Este modelo normalmente se utiliza para representar palabras con muy buenos resultados, en este caso se hace una ajuste de los vectores de cada palabra para lograr un vector de cada frase tratada.
Una vez establecido el modelo vectorial GloVe, se determina un modelo XGBTree para predecir la veracidad de desastres informados en varios textos.
Para ello se utilizan dos datasets, el primero es un dataset con mensajes informando desastres en twitter, con esta base de datos se implementa el XGBTree.
El segundo dataset es grande y se utiliza para generar el modelo GloVe, esto es para lograr generalizar mejor con GloVe.
GloVe , que viene de Global Vectors, es un modelo para representar palabras distribuidas. El modelo es un algoritmo de aprendizaje no supervisado para obtener representaciones vectoriales de palabras. Esto se logra mapeando palabras en un espacio significativo donde la distancia entre palabras esta relacionada con la similitud semantica. El entrenamiento se realiza en estadisticas globales de co-ocurrencia palabra-palabra agregadas de un corpus, y las representaciones resultantes muestran interesantes subestructuras lineales del espacio vectorial de palabras (Wikipedia).
El algoritmo GloVe consta de los siguientes pasos:
1- Recopilacion de estadisticas de co-ocurrencia de palabras en una forma de matriz de co-ocurrencia \(X\). Cada elemento \(X_{ij}\) de dicha matriz representa la frecuencia con la que aparece la palabra \(i\) en el contexto de la palabra \(j\). Por lo general, se escanea el corpus de la siguiente manera: para cada termino se buscan terminos de contexto dentro de un area definida por un window-size antes del termino y un window.size despues del termino. Tambien se da menos peso a las palabras mas distantes, usualmente usando esta formula:
\[decay = \frac{1}{offset}\]
2- Definir restricciones suaves para cada par de palabras:
\[w_{i}^{T}w_j+b_i+b_j = log(X_{ij})\]
Donde:
3- Definir una funcion de costos:
\[J=\sum_{i=1}^{V}\sum_{j=1}^{V}f(X_{ij})(w_{i}^{T}w_j+b_i+b_j-logX_{ij})^2\]
Donde \(f\) es una funcion de ponderacion que ayuda a evitar el aprendizaje solo de pares de palabras extremadamente comunes. Los autores de GloVe eligen la siguiente funcion:
\[f(X_{ij})=\begin{cases} (\frac{X_{ij}}{x_{max}})^\alpha & \text{si X_{ij} > XMAX} \\1 & \text{en otro caso}\end{cases}\]
Para mayor informacion revisar “GloVe: Global Vectors for Word Representation”, “GloVe Word Embeddings”.
Twitter es un importante canal de comunicacion en tiempos de emergencia. La ubicuidad de los telefonos inteligentes permite a las personas anunciar una emergencia que estan observando en tiempo real. Debido a esto, mas agencias estan interesadas en monitorear Twitter (es decir, organizaciones de ayuda ante desastres y agencias de noticias). Sin embargo, no siempre esta claro si las palabras de una persona realmente anuncian un desastre. Este dataset representa una muestra de mensajes de emergencia en Twitter identificando si los desastres informados son reales o no.
A continuacion se muestran las primeras 6 observaciones del dataset, que muestra que consta de 5 columnas:
dataDisaster <- fread("train.csv")
htmlTable(dataDisaster %>% head(),
caption = "Tabla 1. Muestra del dataset.",
tfoot = "† primeras 6 observaciones",
col.rgroup = c("none","#FC7C7C"),
css.cell = "padding-left: .5em; padding-right: .2em;")| Tabla 1. Muestra del dataset. | |||||
| id | keyword | location | text | target | |
|---|---|---|---|---|---|
| 1 | 1 | Our Deeds are the Reason of this #earthquake May ALLAH Forgive us all | 1 | ||
| 2 | 4 | Forest fire near La Ronge Sask. Canada | 1 | ||
| 3 | 5 | All residents asked to ‘shelter in place’ are being notified by officers. No other evacuation or shelter in place orders are expected | 1 | ||
| 4 | 6 | 13,000 people receive #wildfires evacuation orders in California | 1 | ||
| 5 | 7 | Just got sent this photo from Ruby #Alaska as smoke from #wildfires pours into a school | 1 | ||
| 6 | 8 | #RockyFire Update => California Hwy. 20 closed in both directions due to Lake County fire - #CAfire #wildfires | 1 | ||
| † primeras 6 observaciones | |||||
De estas variables se utilizan solo text como caracteristica para predecir target. Se observa que el dataset tiene 7613 observaciones, donde 42.97% de las observaciones son desastres reales.
dataDisaster <- dataDisaster %>% select(text, target)
htmlTable(dataDisaster %>% summary(),
caption = "Tabla 2. Distribucion de variables.",
tfoot = "",
col.rgroup = c("none","#FC7C7C"),
css.cell = "padding-left: .5em; padding-right: .2em;")| Tabla 2. Distribucion de variables. | ||
| text | target | |
|---|---|---|
| Length:7613 | Min. :0.0000 | |
| Class :character | 1st Qu.:0.0000 | |
| Mode :character | Median :0.0000 | |
| Mean :0.4297 | ||
| 3rd Qu.:1.0000 | ||
| Max. :1.0000 | ||
El dataset HC Corpora esta conformado por doce corpus divididos en cuatro idiomas (ingles, ruso, finlandes y aleman). Cada idioma tiene textos de twitter, blogs y sitios de noticias (en este caso se utiliza el corpus en ingles).
news <- data.frame(text = readLines("en_US.news.txt", encoding = "UTF-8"),
stringsAsFactors = FALSE)
blogs <- data.frame(text = readLines("en_US.blogs.txt", encoding = "UTF-8"),
stringsAsFactors = FALSE)
twitter <- data.frame(text = readLines("en_US.twitter.txt", encoding = "UTF-8"),
stringsAsFactors = FALSE)
htmlTable(data.frame(obs = c(dim(blogs)[1], dim(news)[1], dim(twitter)[1]),
size = c(format(object.size(blogs), units = "Mb"),
format(object.size(news), units = "Mb"),
format(object.size(twitter), units = "Mb")),
row.names = c("blogs", "news", "twitter")),
caption = "Tabla 3. Largo y peso de cada dataset.",
col.rgroup = c("none","#FC7C7C"),
css.cell = "padding-left: .5em; padding-right: .2em;")| Tabla 3. Largo y peso de cada dataset. | ||
| obs | size | |
|---|---|---|
| blogs | 899288 | 255.4 Mb |
| news | 77259 | 19.8 Mb |
| 2360148 | 319 Mb | |
htmlTable(data.frame(dataset = c("blogs", "news", "twitter"),
text = c(blogs$text[1], news$text[1], twitter$text[1])
),
caption = "Tabla 4. Largo y peso de cada dataset.",
col.rgroup = c("none","#FC7C7C"),
css.cell = "padding-left: .5em; padding-right: .2em;")| Tabla 4. Largo y peso de cada dataset. | ||
| dataset | text | |
|---|---|---|
| 1 | blogs | In the years thereafter, most of the Oil fields and platforms were named after pagan “gods”. |
| 2 | news | He wasn’t home alone, apparently. |
| 3 | How are you? Btw thanks for the RT. You gonna be in DC anytime soon? Love to see you. Been way, way too long. | |
Se observa de la tabla 3 que el conjunto del dataset HC Corpora es bastante grande. La tabla 4 muestra una observacion de cada subgrupo del dataset.
Visto los datasets se procede a unirlos y limpiarlos, para ello consideraremos lo siguiente:
train <- rbind(news, blogs, twitter, dataDisaster$text) # hay alrededor de 3M de observaciones
rm(news, blogs, twitter, dataDisaster)
cleanText <- function(text, stopwords = TRUE, language = "english", remText = NULL){
text = gsub("http "," ",text) # limpia paginas http
text = gsub("https "," ",text) # limpia paginas https
text = gsub("com "," ",text) # limpia direcciones
text = gsub("co "," ",text) # limpia direcciones
text = gsub("org "," ",text) # limpia direcciones
text = gsub("[[:punct:]]"," ",text) # elimina puntuacion
text = gsub("\\w*[0-9]+\\w*\\s*", " ",text) #elimina numeros
text = stringr::str_replace_all(text, "\\p{quotation mark}", "") # elimina comillas
text = gsub("\\n", " ",text) # elimina saltos de linea
text = stringr::str_replace_all(text,"[\\s]+", " ")
text = stringr::str_replace_all(text," $", "") # elimina espacios finales
# elimina emojis
text = gsub("<\\w+>","",iconv(text, from = "UTF-8", to = "latin1", sub = "byte"))
text = gsub("<\\w+>","",iconv(text, from = "UTF-8", to = "latin1", sub = "byte"))
text = gsub("-", "",text) # elimina giones
text = tolower(text) # transforma a minuscula
text = tm::removeWords(text, letters) # elimina letras sueltas
text = stringr::str_replace_all(text," $", "") # elimina espacios finales
if(stopwords){text = tm::removeWords(text, tm::stopwords(language))} # elimina stopwords
if(is.null(remText)){text = tm::removeWords(text, remText)} # elimina palabras especificas
text = tm::stripWhitespace(text) # quita espacios en blanco repetidos
text = stringr::str_replace_all(text,"^ ", "") # elimina espacios iniciales
text = tm::stemDocument(text) # Stem words
return(text)
}
it_train = itoken(train$text,
preprocessor = cleanText,
tokenizer = word_tokenizer,
n_chunks = 5,
progressbar = TRUE)
vocab = create_vocabulary(it_train, ngram = c(1L, 1L))Con lo anterior se genera un vocabulario con 391796 terminos, de los cuales a continuacion se presentan los 40 mas y menos frecuentes.
vocab_prune = vocab %>%
prune_vocabulary(term_count_min = 10, doc_count_min = 10)
vocab[order(vocab$term_count, decreasing = TRUE),] %>% head(40) %>%
ggplot(aes(x=reorder(term, term_count), y=term_count)) +
geom_bar(stat = "identity", fill="red", alpha = 0.7) + coord_flip() +
theme(legend.title=element_blank()) +
xlab("Palabras") + ylab("Frecuencia") +
labs(title = paste0("Palabras mas frecuentes (",dim(vocab)[1], " palabras)"))+
theme_linedraw()vocab[order(vocab$term_count, decreasing = TRUE),] %>% tail(40) %>%
ggplot(aes(x=reorder(term, term_count), y=term_count)) +
geom_bar(stat = "identity", fill="red", alpha = 0.7) + coord_flip() +
theme(legend.title=element_blank()) +
xlab("Palabras") + ylab("Frecuencia") +
labs(title = paste0("Palabras menos frecuentes (",dim(vocab)[1], " palabras)"))+
theme_linedraw()Como se observa en el histograma, existen muchos terminos que aparecen solo una vez. Estos terminos no son utiles para el modelo y utilizan memoria, por lo que se eliminaran, como criterio se consideraron solo los terminos que aparezcan por lo menos 10 veces. Esto genera una reduccion significativa, quedando 50247 terminos en total.
La idea central al aplicar GloVe al problema es vectorizar una oracion, dado que este modelo esta orientado a palabras se procedera a determinar los vectores de las palabras para luego realizar una combinacion de estos vectores y generar los vectores de las oraciones. Esto se fundamenta en la idea de que palabras relacionadas semanticamente tendran un vector similar, esto hace que al ser agregados al vector de la oracion se mantendra un resultado similar.
Con el vocabulario reducido se genera un modelo GloVe considerando 200 variables y 50 iteraciones. Con esto se reduce la dimensionalidad de manera significativa. A continuacion se observa la evolucion de la perdida durante el entrenamiento.
vectorizer = vocab_vectorizer(vocab_prune)
tfidf = TfIdf$new()
dtm = create_dtm(it_train, vectorizer)
dtm_tfidf = fit_transform(dtm, tfidf)
tcm <- create_tcm(it_train, vectorizer)
glove = GlobalVectors$new(rank = 200, x_max = 10, shuffle = TRUE)
word_vectors = glove$fit_transform(tcm, n_iter = 50)INFO [23:36:54.689] epoch 1, loss 0.2012
INFO [23:37:45.595] epoch 2, loss 0.1161
INFO [23:38:35.033] epoch 3, loss 0.1015
INFO [23:39:22.986] epoch 4, loss 0.0916
INFO [23:40:12.777] epoch 5, loss 0.0867
INFO [23:41:07.390] epoch 6, loss 0.0832
INFO [23:41:58.991] epoch 7, loss 0.0805
INFO [23:42:51.779] epoch 8, loss 0.0784
INFO [23:43:54.591] epoch 9, loss 0.0766
INFO [23:44:51.357] epoch 10, loss 0.0751
INFO [23:45:40.118] epoch 11, loss 0.0738
INFO [23:46:40.222] epoch 12, loss 0.0728
INFO [23:47:41.497] epoch 13, loss 0.0718
INFO [23:48:33.750] epoch 14, loss 0.0710
INFO [23:49:21.883] epoch 15, loss 0.0702
INFO [23:50:09.643] epoch 16, loss 0.0695
INFO [23:50:53.735] epoch 17, loss 0.0689
INFO [23:51:36.832] epoch 18, loss 0.0684
INFO [23:52:26.522] epoch 19, loss 0.0679
INFO [23:53:12.389] epoch 20, loss 0.0674
INFO [23:53:57.198] epoch 21, loss 0.0670
INFO [23:54:39.526] epoch 22, loss 0.0666
INFO [23:55:21.479] epoch 23, loss 0.0662
INFO [23:56:03.953] epoch 24, loss 0.0659
INFO [23:56:46.284] epoch 25, loss 0.0656
INFO [23:57:28.937] epoch 26, loss 0.0653
INFO [23:58:11.395] epoch 27, loss 0.0650
INFO [23:58:53.856] epoch 28, loss 0.0647
INFO [23:59:36.026] epoch 29, loss 0.0645
INFO [00:00:18.166] epoch 30, loss 0.0643
INFO [00:01:00.573] epoch 31, loss 0.0640
INFO [00:01:42.703] epoch 32, loss 0.0638
INFO [00:02:24.921] epoch 33, loss 0.0636
INFO [00:03:07.048] epoch 34, loss 0.0635
INFO [00:03:49.157] epoch 35, loss 0.0633
INFO [00:04:32.686] epoch 36, loss 0.0631
INFO [00:05:12.066] epoch 37, loss 0.0630
INFO [00:05:51.384] epoch 38, loss 0.0628
INFO [00:06:31.125] epoch 39, loss 0.0627
INFO [00:07:10.923] epoch 40, loss 0.0625
INFO [00:07:50.425] epoch 41, loss 0.0624
INFO [00:08:29.887] epoch 42, loss 0.0623
INFO [00:09:09.878] epoch 43, loss 0.0621
INFO [00:09:49.398] epoch 44, loss 0.0620
INFO [00:10:28.747] epoch 45, loss 0.0619
INFO [00:11:08.035] epoch 46, loss 0.0618
INFO [00:11:56.487] epoch 47, loss 0.0617
INFO [00:12:45.166] epoch 48, loss 0.0616
INFO [00:13:35.361] epoch 49, loss 0.0615
INFO [00:14:31.884] epoch 50, loss 0.0614
data.frame(loss = glove$get_history()[[1]], epoch = c(1:length(glove$get_history()[[1]]))) %>%
ggplot(aes(y = loss, x = epoch)) +
ggtitle("Entrenamiento modelo GloVe")+
geom_line(colour = "red", size = 1) +
geom_point(colour = "red", size = 3) +
theme_linedraw()Para visualizar las relaciones generadas por el modelo se muestra a continuacion una representacion utilizando t-SNE en (3D). Para complementar la visualizacion se colorean las palabras en base a su sentimiento en negro para neutro, azul para positivo y rojo para negativo.
# selecciona vocabulario mas frecuente
wvOrder <- vocab[order(vocab$term_count, decreasing = TRUE),][c(1:500),]
# calcula sentimientos
sentCalc <- function(name, row.names = TRUE){
text <- name %>% t() %>% apply(1,function(x) get_sentiment(char_v = x, method = "syuzhet"))
if(row.names){text <- text %>% as.data.frame(row.names = name)}
if(!row.names){text <- text %>% as.data.frame(row.names = c(1:length(name)))}
return(text)
}
em <- wvOrder$term %>% sentCalc()
em <- ifelse(em==0,'#000000',ifelse(em>0,'#0000FF','#FF0000'))
#
tsne <- Rtsne(word_vectors[wvOrder$term, ],
perplexity = 100, pca = FALSE, dims = 3,
max_iter = 3000, verbose = FALSE)
tsne_plot <- tsne$Y %>%
as.data.frame() %>%
mutate(word = wvOrder$term)
p <- plot_ly(tsne_plot, x = ~V1, y = ~V2, z = ~V3,
mode = 'text',
type = 'scatter3d',
text = ~word, textposition = 'middle right',
textfont = list(color = em[,1], size = 12),
width = 1000*0.75, height = 700*0.75) %>%
layout(title = "Representacion de palabras con GloVe",
scene = list(xaxis = list(title = 'x'),
yaxis = list(title = 'y'),
zaxis = list(title = 'z')
))
pLa representacion selecciona las 500 palabras mas comunes. Se observan varias relaciones de palabras con un contexto similar, como por ejemplo:
Estas relaciones semanticas son utiles para poder codificar oraciones completas. Ademas, se tiene que las palabras negativas y positivas no son cercanas, a excepcion de algunos casos aislados como white/black y money/pay.
Para intentar representar oraciones que incluyan relaciones semanticas se considera la suma ponderada utilizando los vectores del modelo GloVe generados en el punto anterior. Esto se lleva a cabo de la siguiente manera:
\[V_s=\frac{\sum_{i=1}^{n}{\overline{dtm_i}V_{w_i}}}{n}\]
Donde:
Se utiliza la normalizacion Tf-Idf para que las palabras mas comunes sean menos representativas y no influyan de sobremanera en el promedio.
Aplicando nuevamente t-SNE(2D) al dtm (Document-term matrix), dtm tfidf (Document-term matrix normalizado Tf-Idf) y al modelo GloVe se observa que en ningun caso hay una clara relacion entre el target (desastre/no desastre) y los datos. Por otro, lado tambien se observa que ambos dtm presentan algunos patrones, que en el caso de Glove se tienden a perder.
trainSample <- fread("train.csv") %>% select(text, target)
cleanText <- function(text, stopwords = TRUE, language = "english", remText = NULL){
text = gsub("http "," ",text) # limpia paginas http
text = gsub("https "," ",text) # limpia paginas https
text = gsub("com "," ",text) # limpia direcciones
text = gsub("co "," ",text) # limpia direcciones
text = gsub("org "," ",text) # limpia direcciones
text = gsub("[[:punct:]]"," ",text) # elimina puntuacion
text = gsub("\\w*[0-9]+\\w*\\s*", " ",text) #elimina numeros
text = stringr::str_replace_all(text, "\\p{quotation mark}", "") # elimina comillas
text = gsub("\\n", " ",text) # elimina saltos de linea
text = stringr::str_replace_all(text,"[\\s]+", " ")
text = stringr::str_replace_all(text," $", "") # elimina espacios finales
# elimina emojis
text = gsub("<\\w+>","",iconv(text, from = "UTF-8", to = "latin1", sub = "byte"))
text = gsub("<\\w+>","",iconv(text, from = "UTF-8", to = "latin1", sub = "byte"))
text = gsub("-", "",text) # elimina giones
text = tolower(text) # transforma a minuscula
text = tm::removeWords(text, letters) # elimina letras sueltas
text = stringr::str_replace_all(text," $", "") # elimina espacios finales
if(stopwords){text = tm::removeWords(text, tm::stopwords(language))} # elimina stopwords
if(is.null(remText)){text = tm::removeWords(text, remText)} # elimina palabras especificas
text = tm::stripWhitespace(text) # quita espacios en blanco repetidos
text = stringr::str_replace_all(text,"^ ", "") # elimina espacios iniciales
text = tm::stemDocument(text) # Stem words
return(text)
}
vocab_prune = vocab %>% prune_vocabulary(term_count_min = 10, doc_count_min = 10)
# limpiar y crear dtm con el nuevo texto
it_train = itoken(trainSample$text,
preprocessor = cleanText,
tokenizer = word_tokenizer,
n_chunks = 5,
progressbar = FALSE)
vectorizer = vocab_vectorizer(vocab_prune)
dtm = create_dtm(it_train, vectorizer)
# ajustar dtm con tfidf calculado anteriormente
dtm_tfidf = transform(dtm, tfidf)
# Codificar en base a Glove calculdo anteriormente (normalizado)
nword <- slam::row_sums(dtm, na.rm = T)
nword[nword==0] <- 1
docCod <- slam::matprod_simple_triplet_matrix(
slam::as.simple_triplet_matrix(dtm_tfidf),
slam::as.simple_triplet_matrix(word_vectors)
)/nword
docCod <- list(docCod = docCod, nword = nword)
docCodS <- docCod$docCod
set.seed(1)
samp <- sample.int(dim(trainSample)[1], 500, replace = F)
# t-SNE GloVe
tsne2 <- Rtsne(docCodS[samp,],
perplexity = 0.3*length(samp), pca = TRUE, dims = 2,
check_duplicates = F, max_iter = 1000, theta = 0.1, eta = 500,
verbose = F, exaggeration_factor = 30)
tsne_plot2 <- tsne2$Y %>%
as.data.frame() %>%
mutate(Sentence = ifelse(trainSample$target[samp]==0,'no disaster','disaster') %>% as.factor())
tsne_plot2 %>%
GGally::ggpairs(columns = c(1,2),
aes(colour=Sentence),
upper = list(continuous = GGally::wrap("cor", alpha = 1, size = 8)),
lower = list(continuous = GGally::wrap("points", alpha = 0.5, size = 6)),
diag = list(continuous = GGally::wrap("densityDiag", alpha = 0.7)),
title = "Representacion t-SNE de vectorización GloVe"
)+
scale_fill_manual(values = c("#FF0000", "#000000"))+
scale_color_manual(values = c("#FF0000", "#000000"))+
theme_linedraw()# t-SNE dtm
tsne2 <- Rtsne(dtm[samp,] %>% as.matrix(),
perplexity = 0.3*length(samp), pca = TRUE, dims = 2,
check_duplicates = F, max_iter = 1000, theta = 0.1, eta = 500,
verbose = F, exaggeration_factor = 30)
tsne_plot2 <- tsne2$Y %>%
as.data.frame() %>%
mutate(Sentence = ifelse(trainSample$target[samp]==0,'no disaster','disaster') %>% as.factor())
tsne_plot2 %>%
GGally::ggpairs(columns = c(1,2),
aes(colour=Sentence),
upper = list(continuous = GGally::wrap("cor", alpha = 1, size = 8)),
lower = list(continuous = GGally::wrap("points", alpha = 0.5, size = 6)),
diag = list(continuous = GGally::wrap("densityDiag", alpha = 0.7)),
title = "Representacion t-SNE de Document-term matrix"
)+
scale_fill_manual(values = c("#FF0000", "#000000"))+
scale_color_manual(values = c("#FF0000", "#000000"))+
theme_linedraw()# t-SNE dtm_tfidf
tsne2 <- Rtsne(dtm_tfidf[samp,] %>% as.matrix(),
perplexity = 0.3*length(samp), pca = TRUE, dims = 2,
check_duplicates = F, max_iter = 1000, theta = 0.1, eta = 500,
verbose = F, exaggeration_factor = 30)
tsne_plot2 <- tsne2$Y %>%
as.data.frame() %>%
mutate(Sentence = ifelse(trainSample$target[samp]==0,'no disaster','disaster') %>% as.factor())
tsne_plot2 %>%
GGally::ggpairs(columns = c(1,2),
aes(colour=Sentence),
upper = list(continuous = GGally::wrap("cor", alpha = 1, size = 8)),
lower = list(continuous = GGally::wrap("points", alpha = 0.5, size = 6)),
diag = list(continuous = GGally::wrap("densityDiag", alpha = 0.7)),
title = "Representacion t-SNE de Document-term matrix normalizado Tf-Idf"
)+
scale_fill_manual(values = c("#FF0000", "#000000"))+
scale_color_manual(values = c("#FF0000", "#000000"))+
theme_linedraw()Para predecir consideraremos un modelo XGB Tree y los siguientes parametros:
fitControl <- trainControl(method = "cv",
number = 10,
search = "random",
summaryFunction = twoClassSummary,
classProbs = TRUE,
sampling = "up",
verboseIter = FALSE
)
dataGloVe <- data.frame(target = factor(trainSample$target, labels = c("X0", "X1")), docCod$docCod)
set.seed(1)
xgbTreeGloVe <- caret::train(target ~.,
data = dataGloVe,
preProcess = c("center", "scale"),
method = "xgbTree",
trControl = fitControl,
metric = "ROC",
tuneLength = 50,
verbose = FALSE
)
ggplot(xgbTreeGloVe) + ggtitle("Resultado del Modelo XGBTree con GloVe")+
geom_point(colour = "red", size = 3) +
theme_linedraw()Este modelo entrega buenos resultados, con un ROC mayor a 0.86. Si lo comparamos con un modelo anterior que como maximo llego a 0.83 es una buena mejora.
Es necesario considerar que este modelo se desarrollo con una vectorizacion GloVe de 200 variables en oposicion al modelo con el que se compara que utiliza 1122 variables.
Es posible generar una vectorizacion a partir de GloVe para oraciones, aunque es necesario considerar una base de datos los suficientemente grande para la vectorizacion de palabras y que el modelo sea representativo y se puedan generalizar las relaciones entre palabras. De lo anterior y como este modelo fue desarrollado en un computador personal, es perfectamente mejorable el modelo de vectorizacion de palabras.
La ponderacion utilizando Tf-Idf resulto ser una buena opcion. Es posible mejorar estos pesos utilizando otro modelo que determine pesos optimos para cada problema, pero como primer paso es una buena opcion.
R version 3.6.2 (2019-12-12)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18363)
Matrix products: default
locale:
[1] LC_COLLATE=Spanish_Chile.1252 LC_CTYPE=Spanish_Chile.1252
[3] LC_MONETARY=Spanish_Chile.1252 LC_NUMERIC=C
[5] LC_TIME=Spanish_Chile.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] Rtsne_0.15 glmnet_4.0-2 Matrix_1.2-18 slam_0.1-47
[5] text2vec_0.6 plotly_4.9.2.1 RColorBrewer_1.1-2 ggcorrplot_0.1.3
[9] tidytext_0.2.5 syuzhet_1.0.4 tm_0.7-7 NLP_0.2-0
[13] lubridate_1.7.9 Metrics_0.1.4 ranger_0.12.1 caret_6.0-86
[17] lattice_0.20-41 ggpubr_0.4.0 data.table_1.13.0 htmlTable_2.0.1
[21] forcats_0.5.0 stringr_1.4.0 dplyr_1.0.2 purrr_0.3.4
[25] readr_1.3.1 tidyr_1.1.2 tibble_3.0.3 ggplot2_3.3.2
[29] tidyverse_1.3.0
loaded via a namespace (and not attached):
[1] colorspace_1.4-1 ggsignif_0.6.0 ellipsis_0.3.1
[4] class_7.3-17 rio_0.5.16 fs_1.5.0
[7] rstudioapi_0.11 SnowballC_0.7.0 prodlim_2019.11.13
[10] fansi_0.4.1 xml2_1.3.2 codetools_0.2-16
[13] splines_3.6.2 rsparse_0.4.0 knitr_1.29
[16] mlapi_0.1.0 jsonlite_1.7.1 pROC_1.16.2
[19] RhpcBLASctl_0.20-137 broom_0.7.0 dbplyr_1.4.4
[22] compiler_3.6.2 httr_1.4.2 backports_1.1.9
[25] lazyeval_0.2.2 assertthat_0.2.1 cli_2.0.2
[28] htmltools_0.5.0 tools_3.6.2 gtable_0.3.0
[31] glue_1.4.2 reshape2_1.4.4 float_0.2-4
[34] Rcpp_1.0.5 carData_3.0-4 cellranger_1.1.0
[37] vctrs_0.3.4 nlme_3.1-149 iterators_1.0.12
[40] timeDate_3043.102 gower_0.2.2 xfun_0.16
[43] openxlsx_4.1.5 rvest_0.3.6 lifecycle_0.2.0
[46] rstatix_0.6.0 MASS_7.3-52 scales_1.1.1
[49] ipred_0.9-9 lgr_0.3.4 hms_0.5.3
[52] parallel_3.6.2 yaml_2.2.1 curl_4.3
[55] rpart_4.1-15 stringi_1.4.6 tokenizers_0.2.1
[58] foreach_1.5.0 checkmate_2.0.0 zip_2.1.1
[61] shape_1.4.4 lava_1.6.7 rlang_0.4.7
[64] pkgconfig_2.0.3 evaluate_0.14 recipes_0.1.13
[67] htmlwidgets_1.5.1 tidyselect_1.1.0 plyr_1.8.6
[70] magrittr_1.5 R6_2.4.1 generics_0.0.2
[73] DBI_1.1.0 pillar_1.4.6 haven_2.3.1
[76] foreign_0.8-76 withr_2.2.0 survival_3.2-3
[79] abind_1.4-5 nnet_7.3-14 janeaustenr_0.1.5
[82] modelr_0.1.8 crayon_1.3.4 car_3.0-9
[85] rmarkdown_2.3 grid_3.6.2 readxl_1.3.1
[88] blob_1.2.1 ModelMetrics_1.2.2.2 reprex_0.3.0
[91] digest_0.6.25 stats4_3.6.2 munsell_0.5.0
[94] viridisLite_0.3.0