# install.packages("rtweet")
library(rtweet)
library(tidyverse)
library(tm)
library(wordcloud2)
library(topicmodels)
library(LDAvis)
library(tsne)
rtweet
rt <- search_tweets(q = "Bolivia OR bolivia OR Evo",type = "mixed", n = 18000, include_rts = FALSE)
saveRDS(rt,'fuentes/rt.RDS')
rt <- read_rds('fuentes/rt.RDS')
rt %>%
sample_n(10)
range(rt$created_at)
[1] "2019-11-19 18:22:11 UTC" "2019-11-20 22:30:30 UTC"
Nos da los tweets de los últimos nueve días, o el máximo que indicamos más reciente
rt %>%
ts_plot(by = "minutes") +
ggplot2::theme_minimal() +
ggplot2::theme(plot.title = ggplot2::element_text(face = "bold")) +
ggplot2::labs(
x = NULL, y = NULL,
title = "Frecuencia de los tweets relacionados NLP",
subtitle = "Agregado a intervalos de tres horas")+
scale_x_datetime(limits = c((max(rt$created_at)- 12800),max(rt$created_at)))
texto <- rt$text
texto[1:10]
[1] "Más represión y muertes en Bolivia gracias al Golpe de Estado. Esta vez en El Alto. La Comunidad Internacional debe exigirle a los gobernantes de facto y a las fuerzas militares y policiales bolivianas el cese inmediato de la represión y la flagrante violación de Derechos Humanos"
[2] "“Nos están matando como un perro... dónde está la prensa de aquí? Relato de una masacre. Bolivia. 19 Nov de 2019 https://t.co/puZnyFT2L5"
[3] "https://t.co/mlPNjP2mR9"
[4] "Todo o socialista quer implantar este nefasto sistema em seus países.\nMas ir viver onde ele já foi implementado, como na Venezuela, ninguém quer, nem o Evo Morales @evoespueblo \n\nOu será que o Evo não foi para lá porque sabe que @NicolasMaduro está a ponto de cair? https://t.co/ahN38AfT3h"
[5] "@JulianMaciasT @suarezluis @suarezluis amigo !!! Este tipo te hizo famoso 😂😂😂 que manera de desinformar a la gente !!\n\n#BoliviaLibre #BoliviaUnida #EvoEsFraude #Bolivia #BoliviaNoHayGolpe #EvoDictador #NoFueGolpeFueFraude #EvoAsesino #EvoMentiroso"
[6] "@magne_caro @luismebx @MashiRafael @evoespueblo #BoliviaLibre #BoliviaUnida #EvoEsFraude #Bolivia #BoliviaNoHayGolpe #EvoDictador #NoFueGolpeFueFraude #EvoAsesino #EvoMentiroso https://t.co/KKAQ22ERqt"
[7] "Los afines al Dictador Evo Morales son #terroristas, aplaudo a las FFAA y la Policía por defender la seguridad de los Bolivianos 🇧🇴\n\n#BoliviaLibre #BoliviaUnida #EvoEsFraude #Bolivia #BoliviaNoHayGolpe #EvoDictador #NoFueGolpeFueFraude #EvoAsesino #EvoMentiroso https://t.co/fHJpaq5FKZ"
[8] "@F_ortegazabala Las verdades duelen 🤷🏻♀️\n\n#BoliviaLibre #BoliviaUnida #EvoEsFraude #Bolivia #BoliviaNoHayGolpe #EvoDictador #NoFueGolpeFueFraude #EvoAsesino #EvoMentiroso"
[9] "@ammg1912 @JeanineAnez Quién eres tu para opinar de MI país #Bolivia 🇧🇴??? Ni vives acá ni te da la gana de informarte bien, que vergüenza ajena das !!! #BoliviaLibre #BoliviaUnida #EvoEsFraude #Bolivia #BoliviaNoHayGolpe #EvoDictador #NoFueGolpeFueFraude #EvoAsesino #EvoMentiroso https://t.co/h6F00OvEZv"
[10] "@albertovargas30 @JeanineAnez Jajajajaja cual paz ?? Evo Morales ?? Ppffffff ese narcotraficante sigue instigando a sus seguidores a la violencia !\n#BoliviaLibre #BoliviaUnida #EvoEsFraude #Bolivia #BoliviaNoHayGolpe #EvoDictador #NoFueGolpeFueFraude #EvoAsesino #EvoMentiroso https://t.co/JtT6oXLuTO"
Este texto es necesario limpiarlo para que sea más fácil de utilizar.
tm
myCorpus = Corpus(VectorSource(texto))
tm_map
podemos iterar sobre el corpus aplicando una transformación sobre cada documentoEn este caso, para la limpieza utilizaremos las siguientes transformaciones.
tm
tenemos que usar también content_transformer
)myCorpus = tm_map(myCorpus, content_transformer(tolower))
myCorpus = tm_map(myCorpus, removePunctuation)
myCorpus = tm_map(myCorpus, removeNumbers)
myCorpus = tm_map(myCorpus, removeWords, stopwords(kind = "es"))
inspect(myCorpus[1:10])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 10
[1] represión muertes bolivia gracias golpe vez alto comunidad internacional debe exigirle gobernantes facto fuerzas militares policiales bolivianas cese inmediato represión flagrante violación derechos humanos
[2] “ matando perro dónde prensa aquí relato masacre bolivia nov httpstcopuznyftl
[3] httpstcomlpnjpmr
[4] socialista quer implantar nefasto sistema em seus países\nmas ir viver onde ele já foi implementado na venezuela ninguém quer nem evo morales evoespueblo \n\nou evo não foi lá sabe nicolasmaduro ponto cair httpstcoahnafth
[5] julianmaciast suarezluis suarezluis amigo tipo hizo famoso 😂😂😂 manera desinformar gente \n\nbolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
[6] magnecaro luismebx mashirafael evoespueblo bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso httpstcokkaqerqt
[7] afines dictador evo morales terroristas aplaudo ffaa policía defender seguridad bolivianos 🇧🇴\n\nbolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso httpstcofhjpaqfkz
[8] fortegazabala verdades duelen 🤷🏻♀️\n\nbolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
[9] ammg jeanineanez quién opinar país bolivia 🇧🇴 vives acá da gana informarte bien vergüenza ajena das bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso httpstcohfovezv
[10] albertovargas jeanineanez jajajajaja paz evo morales ppffffff narcotraficante sigue instigando seguidores violencia \nbolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso httpstcojttoxluto
podemos ver que nos quedaron unos que son la forma de representar el “enter”. Lo mejor sería eliminarlos.
También queremos sacar los links. Para eso vamos a usar expresiones regulares para definir el patron que tiene un link, y luego crearemos una función que los elimine.
Para que sea más sencilla la construcción de la expresión regular, usamos la librería RVerbalExpressions
# devtools::install_github("VerbalExpressions/RVerbalExpressions")
library(RVerbalExpressions)
expresion <- rx() %>%
rx_find('http') %>%
rx_maybe('s') %>%
# rx_maybe('://') %>% #como ya lo pasamos por los otros filtros, ya no hay puntuacion
rx_anything_but(value = ' ')
expresion
[1] "(http)(s)?([^ ]*)"
Probamos la expresion con un ejemplo
txt <- "us blacklists chinese artificial intelligence firms time\n\nread httpstcoajreyxfsxy\n\nartificialintelligence ai datascience machinelearning bigdata deeplearning nlp robots iot"
str_remove_all(txt, pattern = expresion)
[1] "us blacklists chinese artificial intelligence firms time\n\nread ai datascience machinelearning bigdata deeplearning nlp robots iot"
Lo pasamos por el corpus
myCorpus = tm_map(myCorpus, content_transformer(function(x) str_replace_all(x, pattern = expresion, replacement = ' ')))
transformation drops documents
myCorpus = tm_map(myCorpus, content_transformer(function(x) str_replace_all(x, pattern = '\n',replacement = ' ')))
transformation drops documents
inspect(myCorpus[1:10])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 10
[1] represión muertes bolivia gracias golpe vez alto comunidad internacional debe exigirle gobernantes facto fuerzas militares policiales bolivianas cese inmediato represión flagrante violación derechos humanos
[2] “ matando perro dónde prensa aquí relato masacre bolivia nov
[3]
[4] socialista quer implantar nefasto sistema em seus países mas ir viver onde ele já foi implementado na venezuela ninguém quer nem evo morales evoespueblo ou evo não foi lá sabe nicolasmaduro ponto cair
[5] julianmaciast suarezluis suarezluis amigo tipo hizo famoso 😂😂😂 manera desinformar gente bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
[6] magnecaro luismebx mashirafael evoespueblo bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
[7] afines dictador evo morales terroristas aplaudo ffaa policía defender seguridad bolivianos 🇧🇴 bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
[8] fortegazabala verdades duelen 🤷🏻♀️ bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
[9] ammg jeanineanez quién opinar país bolivia 🇧🇴 vives acá da gana informarte bien vergüenza ajena das bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
[10] albertovargas jeanineanez jajajajaja paz evo morales ppffffff narcotraficante sigue instigando seguidores violencia bolivialibre boliviaunida evoesfraude bolivia bolivianohaygolpe evodictador nofuegolpefuefraude evoasesino evomentiroso
Creamos una matriz de Término-documento. En el parámetro control
aclaro el tamaño mínimo de las palabras con minWordLength
myDTM = DocumentTermMatrix(myCorpus, control = list(minWordLength = 1))
inspect(myDTM)
<<DocumentTermMatrix (documents: 17997, terms: 46526)>>
Non-/sparse entries: 246992/837081430
Sparsity : 100%
Maximal term length: 80
Weighting : term frequency (tf)
Sample :
Terms
Docs and bolivia elecciones evo evoespueblo gobierno golpe morales pueblo the
11957 0 0 0 1 0 0 0 0 0 0
16535 0 1 0 0 0 0 0 0 0 0
17246 0 1 0 0 0 0 0 0 0 0
2482 1 1 0 1 0 0 0 0 0 2
2788 0 0 0 1 0 0 0 0 0 0
584 0 0 1 0 0 0 0 1 0 0
5939 0 0 0 1 0 0 0 0 0 0
7944 0 1 0 0 0 0 0 0 0 0
8646 0 0 0 1 0 0 0 1 0 0
8894 0 1 0 0 0 0 0 0 0 0
findMostFreqTerms sirve para encontrar las palabras más frecuentes por documento o grupo de documentos. Como sólo me interesa el corpus total, tengo que modificar el INDEX para que sea el mismo en todos los documentos.
palabras_frecuentes <- findMostFreqTerms(myDTM,n = 25, INDEX = rep(1,nDocs(myDTM)))[[1]]
palabras_frecuentes
bolivia evo morales the evoespueblo golpe elecciones
10282 7443 3200 1967 1666 1326 1135
gobierno pueblo and méxico presidente país venezuela
918 903 872 774 710 675 587
ahora mas gente jeanineanez paz ser audio
580 570 559 554 532 520 516
así chile oea bolívia
503 498 489 488
Armo un dataframe con esta información y elimino las palabras Bolivia y Evo, que fueron utilizadas para el scrapper y son por ello las más importantes
palabras_frecuentes <- tibble(word = names(palabras_frecuentes), freq =palabras_frecuentes)
palabras_frecuentes <- palabras_frecuentes %>%
filter(!(word %in% c('bolivia','evo')))
Con el comando wordcloud2
creo la nube de palabras
wordcloud2(palabras_frecuentes)
necesito eliminar los documentos vacíos (que luego de la limpieza quedaron sin ningúna palabra)
ui = unique(myDTM$i)
dtm = myDTM[ui,]
dim(myDTM)
[1] 17997 46526
dim(dtm)
[1] 17857 46526
Entreno el modelo de LDA. k
indica el número de tópicos (dimensiones latentes).
Como ejemplo de una manipulación más fina del algorítmo, modificamos el parámetro delta, que como sólo es modificable cuando se utiliza el método de optimización Gibbs, debemos especificar esto también en al parámetro method
. delta lo modificamos dentro del parámetro control
que reúne varias especificaciones.
Delta es el parametro de la distribución a priori de los términos sobre los tópicos. Esto ajusta cuanto comparten los términos los tópicos (por lo general buscamos que no compartan demasiados términos, dado que es más sencilla la interpretación).
lda_fit <- LDA(dtm, k = 10,method = "Gibbs", control = list(delta=0.6,seed = 1234))
saveRDS(lda_fit,'resultados/lda_fit.rds')
lda_fit <- read_rds('resultados/lda_fit.rds')
lda_fit
A LDA_Gibbs topic model with 10 topics.
Terms <- terms(lda_fit, 10)
Terms
Topic 1 Topic 2 Topic 3 Topic 4 Topic 5 Topic 6
[1,] "bolivia" "evo" "bolivia" "the" "país" "evo"
[2,] "golpe" "morales" "muertos" "and" "gente" "morales"
[3,] "pueblo" "gobierno" "represión" "for" "ser" "méxico"
[4,] "ahora" "audio" "vía" "you" "mas" "asilo"
[5,] "dice" "paz" "youtube" "that" "poder" "rita"
[6,] "golpistas" "boliviano" "senkata" "coup" "solo" "segato"
[7,] "pues" "video" "alto" "this" "puede" "amlo"
[8,] "democracia" "comida" "militares" "are" "bien" "hija"
[9,] "derecha" "ministro" "masacreenbolivia" "with" "quiere" "dijo"
[10,] "golpista" "ciudades" "masacre" "people" "hacer" "presidente"
Topic 7 Topic 8 Topic 9 Topic 10
[1,] "bolivia" "evoespueblo" "bolivia" "bolivia"
[2,] "así" "jeanineanez" "elecciones" "venezuela"
[3,] "bolivianos" "cnnee" "presidenta" "chile"
[4,] "menos" "larazonbolivia" "oea" "almagrooea"
[5,] "mismo" "soyfdelrincon" "presidente" "cuba"
[6,] "pitita" "terrorismo" "bolívia" "argentina"
[7,] "seguir" "lopezobrador" "áñez" "upacificopy"
[8,] "twitter" "dictador" "convocar" "maduro"
[9,] "seguidores" "oeaoficial" "jeanine" "violencia"
[10,] "vuelta" "mundo" "ley" "ecuador"
topicmodels_json_ldavis <- function(fitted, dtm){
svd_tsne <- function(x) tsne(svd(x)$u)
# Find required quantities
phi <- as.matrix(posterior(fitted)$terms)
theta <- as.matrix(posterior(fitted)$topics)
vocab <- colnames(phi)
term_freq <- slam::col_sums(dtm)
# Convert to json
json_lda <- LDAvis::createJSON(phi = phi, theta = theta,
vocab = vocab,
mds.method = svd_tsne,
plot.opts = list(xlab="tsne", ylab=""),
doc.length = as.vector(table(dtm$i)),
term.frequency = term_freq)
return(json_lda)
}
json_res <- topicmodels_json_ldavis(lda_fit, dtm)
sigma summary: Min. : 33554432 |1st Qu. : 33554432 |Median : 33554432 |Mean : 33554432 |3rd Qu. : 33554432 |Max. : 33554432 |
Epoch: Iteration #100 error is: 12.9021288675413
Epoch: Iteration #200 error is: 0.468249056852732
Epoch: Iteration #300 error is: 0.289778848429587
Epoch: Iteration #400 error is: 0.268120180579266
Epoch: Iteration #500 error is: 0.260966680795684
Epoch: Iteration #600 error is: 0.256274456341558
Epoch: Iteration #700 error is: 0.253567240179068
Epoch: Iteration #800 error is: 0.252797289427224
Epoch: Iteration #900 error is: 0.252669111770735
Epoch: Iteration #1000 error is: 0.25264570458198
serVis(json_res)
createTcpServer: address already in use
To stop the server, run servr::daemon_stop(2) or restart your R session
Serving the directory /tmp/RtmpVeQCHt/file5bf820302827 at http://127.0.0.1:3864