sábado, 22 de marzo de 2014

Analizando tuits usando R

Causas y objetivos de las protestas 2014 de acuerdo con @leopoldolopez

Causas y objetivos de las protestas 2014 de acuerdo con @leopoldolopez

Introducción

Tuiter es una herramienta estupenda para el análisis de entorno. Si bien existen algunos problemas en el presente para obtener tuits (la nueva API de Twitter genera problema exige auntentificación del usuario, pero, a pesar de que se obtiene la OAUTH, continua generando mensaje de error), es posible colectar algunos en forma manual y de esa manera obtener una visión aceptable sobre algunos tópicos, conversaciones o actores especíicos. Emplearemos esta herramienta para intentar establecer las causas/objetivos de las protestas en Venezuela, de acuerdo con la cuenta de tuiter de Leopoldo López, según se observa en los tuits del timeline de @leopoldolopez entre el 01 de febrero y el 01 de marzo de 2014, recogidos el 03 de marzo de 2014 a las 8 pm, hora de Venezuela.

Empezamos cargando los paquetes necesarios para el análisis a la cónsola de R:

## Loading required package: tm
## Loading required package: wordcloud
## Loading required package: Rcpp
## Loading required package: RColorBrewer

En esta oportunidad hemos “cosechado”“ los tuits en forma manual, puesto que sólo estamos interesados en los tuits del mes de febrero. Si se desea una cosecha más amplia, y no se dispone de dinero para adquirir alguna de las aplicaciones que trabajan sin ningún problema con Twitter, quizá valga la pena insistir hasta que la autentificación sea aceptada y se logre ejecutar este procedimiento empleando el paquete twwiteR, XML o Rcurl.

Los tuites cosechado se guardaron en un archivo de texto y luego lo procesamos empleando Refine. De esa forma creamos una tabla que nos permitió colocar la información relevante separada en columnas. Luego de ello, se procedió a procesar la información.

Data

head(leopoldo)
##                                                                                                                                        texto
## 1   Les invito a leer el comunicado completo http://goo.gl/oFA2Gv  la protesta en la calle es constitucional y pacifica! #ElQueSeCansaPierde
## 2  Gracias a @oariascr, Fernando H. Cardoso, @RicardoLagos y Alejandro Toledo x comunicado sobre crisis en Venezuela y mi encarcelamiento/LT
## 3  Queremos rendir homenaje a los 18 fallecidos q ha dejado la violenta represion d los organos d seguridad del regimen de Nicolas Maduro/LT
## 4  Invito a tod@s mañana 10am #3M a 1 caminata #MujeresPorLaVida y @VoluntadPopular desde la Av Andres Galarraga a la Plza. Alfredo Sadel/LT
## 5 Desde Ramo Verde,tan cerca e incomunicados, te mando 1 abrazo @simonovis ejemplo d resistencia. Estamos del lado correcto d la historia/LT
## 6                  Asi es! RT @carlosvecchio: Ratifico que el manifiesto que leí fue escrito del puño y letra de ... http://m.tmi.me/1dQbFE 
##         sender.1      fecha
## 1 @leopoldolopez  5 de mar.
## 2 @leopoldolopez  5 de mar.
## 3 @leopoldolopez  4 de mar.
## 4 @leopoldolopez  4 de mar.
## 5 @leopoldolopez  3 de mar.
## 6 @leopoldolopez  3 de mar.

Obtuvimos 526 tuits. Vamos a obtener, a partir de esta data, la cantidad de hashtags, entidades y links, en los tuits.

Extracción de hashtags, entidades y links

Vamos a trabajar con el paquete stringr que nos permite trabajar con texto y extraer elementos que nos interesan. Primero crearemos una función en la que juntamos las diferentes funciones de este paquete necesarias para obtener los hashs, y con esta data crear la distribución de frecuencias absolutas y relativas para observar la probabilidad de cada hashtag.


# cargamos el paquete stringr

require(stringr)

# extraemos los hash y los almacenamos en una variable
has <- str_extract_all(x, "#\\w+")

# convertimos los hash en vectores
hash <- unlist(has)

# ponemos los hashtags en minuscula
hash <- tolower(hash)

# creamos un data.frame
hashdf <- data.frame(sort(table(hash), decreasing = T))

names(hashdf) <- "frecuencia"

# creamos la distribucion de frecuencias relativas
hashdf$porc = round(hashdf$frecuencia/sum(hashdf$frecuencia) * 100, 2)

# Procedemos igual para obtener las @entidades, y los links, cambiando
# unicamente la expresion regular

A partir de estos códigos, variando sólamente la expresión regular para cada caso, podemos obtener la distribución de frecuencias absolutas y relativas de hashtags y entidades

##                  frecuencia  porc
## #12f                     62 23.22
## #lasalida                58 21.72
## #unidadenlacalle         30 11.24
##                  frecuencia  porc
## @voluntadpopular         19 11.31
## @leopoldolopez           14  8.33
## @nicolasmaduro           11  6.55

Los tres hashtags más frecuente, juntos suman el 56.18% de ellos, en en timeline de @leopoldolopez se relacionan con las protestas del día 12 de febrero. En tanto que las tres entidades que más se nombran son @voluntad popular, 11.31%, @leopoldolopez, 8.33% y @nicolasmaduro, 6.55%. Finalmente, los retuis más frecuentes son de @voluntadpopular,14.3%, y ** @luisflorido** -miembro de Voluntad Popular, 4.8%. Hay un sólo link

Visualización

Con esta información podemos crear dos visualizaciones, concretamente dos nubes de palabras:

par(mfrow = c(2, 1))
wordcloud(rownames(hashLeopoldo), hashLeopoldo$frecuencia, random.order = FALSE, 
    random.color = FALSE, colors = brewer.pal(8, "Dark2"))
wordcloud(rownames(entLeopoldo), entLeopoldo$frecuencia, random.order = FALSE, 
    random.color = FALSE, colors = rainbow(7))

Hashtags y entidades mencionadas en @leopoldolopez, el dia 01/03/2014

En la nube superior podemos observar los hashtags más frecuentes empleados en los tuits de Leopoldo Lopez en el lapso analizado, así como las entidades que más se mencionaron en su timeline

Procesamiento del texto de los tuits

Veamos quien le tuiteos, retuiteos sobre qué versaron esos retuits. Usaremos la función grep() para extraer la información que nos interesa de los textos de los tuits (para mayor información sobre el uso de expresiones regulares en la extracción de información de cadenas de texto ver grep). Para trabajar con mayor rapidez, crearemos nuestras propias funciones en las que incorporaremos la funcion grep()

Mensajes enviados


# ejemplo del uso de la funcion gsub() para obtener el texto de los retuits
retuiteado <- gsub("^rt @([a-z0-9_]{1,15})[^a-z0-9_]+.*$", "\\1", leopoldo$texto, 
    perl = T)

head(retuiteado, 3)
## [1] "Les invito a leer el comunicado completo http://goo.gl/oFA2Gv  la protesta en la calle es constitucional y pacifica! #ElQueSeCansaPierde" 
## [2] "Gracias a @oariascr, Fernando H. Cardoso, @RicardoLagos y Alejandro Toledo x comunicado sobre crisis en Venezuela y mi encarcelamiento/LT"
## [3] "Queremos rendir homenaje a los 18 fallecidos q ha dejado la violenta represion d los organos d seguridad del regimen de Nicolas Maduro/LT"

Extraigamos los mensajes que envia Leopoldo López de forma específica

## [1] ".@nicolasmaduro: no tienes las agallas para meterme preso? o esperas ordenes de la habana? te lo digo: la verdad esta de nuestro lado"
## [2] ".@nicolasmaduro tendras q construir carceles para millones d venezolanos porque seguiremos adelante luchando por #lamejorvzla"
## [1] "@leopoldolopez" "@leopoldolopez"
## [1] "nicolasmaduro" "nicolasmaduro"

Hay dos mensajes enviados concretamente por López. El destinatario es Nicolás Maduro

Mensajes retuiteados

## [1] "rt @voluntadpopular: venezuela, #elquesecansapierde mañana 1m  todos con #unidadenlacalle ... http://m.tmi.me/1dp5ak "
## [2] "rt @voluntadpopular: en caracas saldremos desde la sede de la cev montalbán hasta la ... http://m.tmi.me/1dnh5k "     
## [3] "rt @voluntadpopular: ud vió x @globovision como se cae la mentira del gobierno: así ... http://m.tmi.me/1dhmwo "

Extraemos las personas que retuitearon

##  [1] "@leopoldolopez" "@leopoldolopez" "@leopoldolopez" "@leopoldolopez"
##  [5] "@leopoldolopez" "@leopoldolopez" "@leopoldolopez" "@leopoldolopez"
##  [9] "@leopoldolopez" "@leopoldolopez"

En este caso dado que estamos en un timeline específico, es normal que los retuits provengan del dueño del timeline.

Veamos ahora a quien le retuiteo López:

##  [1] "voluntadpopular" "voluntadpopular" "voluntadpopular"
##  [4] "voluntadpopular" "voluntadpopular" "pedropatino"    
##  [7] "eluniversal"     "voluntadpopular" "voluntadpopular"
## [10] "juankrpe"

Y veamos quienes retuitearon mensajes en general del timeline de López

##                 frecuencia porc
## voluntadpopular          1  100

Podríamos elaborar también una nube de palabras, sin embargo ya sabemos que sólo se mostrarán Voluntad Popular y Luis Florido, puesto que el resto sólo han retuiteao dos o menos mensajes. Una visualización que pudiera ser de mayor interés corresponde a un grafo en el que vinculemos a las personas que han retuiteado según fecha. Para ello creamos una matriz con las entidades que han enviado o retuiado mensajes y la hora, para luego, transponiendo la matriz, quedarnos con las entidades que tendieron a enviar los mensajes en una fecha específica:

# Creamos un data.frame con los autores de los tuits/retuits
hora <- data.frame(tolower(leopoldo$sender.1), leopoldo$fecha)
head(hora, 2)
##   tolower.leopoldo.sender.1. leopoldo.fecha
## 1             @leopoldolopez      5 de mar.
## 2             @leopoldolopez      5 de mar.

# Extraemos tomando en cuenta las veces que cada autor creó o retuiteó un
# mensaje y creamos una matriz
horaMatriz = as.matrix(table(hora))
head(horaMatriz, 2)
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  1 de feb.  1 de mar.  10 de feb.  11 de feb.
##                 @_provea            0          0           0           0
##                 @_provea            0          0           0           0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  12 de feb.  13 de feb.  14 de feb.  16 de feb.
##                 @_provea             3           0           0           0
##                 @_provea             0           0           0           0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  17 de feb.  18 de feb.  19 de feb.  2 de feb.
##                 @_provea             0           0           0          0
##                 @_provea             0           0           0          0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  2 de mar.  20 de feb.  21 de feb.  22 de feb.
##                 @_provea            0           0           0           0
##                 @_provea            0           0           0           0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  25 de feb.  26 de feb.  28 de feb.  3 de feb.
##                 @_provea             0           0           0          0
##                 @_provea             0           0           0          0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  3 de mar.  31 de ene.  4 de feb.  4 de mar.
##                 @_provea            0           0          0          0
##                 @_provea            0           0          0          0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  5 de feb.  5 de mar.  6 de feb.  7 de feb.
##                 @_provea            0          0          0          0
##                 @_provea            0          0          0          0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1.  8 de feb.  9 de feb. 11 de feb. 12 de feb.
##                 @_provea            0          0          0          0
##                 @_provea            0          0          0          2
##                           leopoldo.fecha
## tolower.leopoldo.sender.1. 2 de feb. 3 de feb. 4 de feb. 5 de feb.
##                 @_provea           0         0         0         0
##                 @_provea           0         0         0         0
##                           leopoldo.fecha
## tolower.leopoldo.sender.1. 6 de feb. 7 de feb. 9 de feb.
##                 @_provea           0         0         0
##                 @_provea           0         0         0

# para ver la gente que tuiteó o retuiteó en una misma fecha
horaT <- horaMatriz %*% t(horaMatriz)
head(horaT, 2)
##                           tolower.leopoldo.sender.1.
## tolower.leopoldo.sender.1. @_provea @_provea   @daniel_ceballos  
##                 @_provea          9          0                  0
##                 @_provea          0          4                  0
##                           tolower.leopoldo.sender.1.
## tolower.leopoldo.sender.1. @eluniversal   @leopoldolopez @nakamartinez
##                 @_provea                0            117             0
##                 @_provea                0              0             0
##                           tolower.leopoldo.sender.1.
## tolower.leopoldo.sender.1. @voluntadpopular @voluntadpopular  
##                 @_provea                  0                  0
##                 @_provea                  0                  4
##                           tolower.leopoldo.sender.1.
## tolower.leopoldo.sender.1. rt@voluntadpopular  
##                 @_provea                      0
##                 @_provea                      0

Creamos el grafo

require(igraph)
leoGrapho = graph.adjacency(horaT, mode = "undirected")

# llevamos las líneas múltiples como atributo y luego simplificamos el
# grafo:
E(leoGrapho)$weight <- count.multiple(leoGrapho)
leoGrapho <- simplify(leoGrapho)


# reamos los atributos del grafo
V(leoGrapho)$label = V(leoGrapho)$name
V(leoGrapho)$label.color = rgb(0, 0, 0.2, 0.5)
V(leoGrapho)$degree = degree(leoGrapho)
V(leoGrapho)$label.cex = 0.8
V(leoGrapho)$size = 10
V(leoGrapho)$frame.color = NA
E(leoGrapho)$color = rgb(0, 0.5, 0, 0.2)

plot(leoGrapho, layout = layout.fruchterman.reingold)

plot of chunk grafoLeo

El grafo nos muestra las entidades que tendieron a (re)enviar mensajes en una misma fecha. Los nodos que están separados, no coincidieron con otras entidades cuando (re)tuitearon algún mensaje


hora2 <- data.frame(leopoldo$fecha, tolower(leopoldo$sender.1))
hora2 <- as.matrix(table(hora2))
mensajes <- graph.incidence(hora2, mode = c("all"))
V(mensajes)$label = V(mensajes)$name
V(mensajes)$label.cex = 0.8
V(mensajes)$size = 6
V(mensajes)$frame.color = NA

lay <- layout.bipartite(mensajes)

plot(mensajes, layout = lay[, 2:1])

plot of chunk gCompelto

Este último grafo se ha creado para enfatizar las fechas. Observamos que Voluntad Popular ha sido muy activo en los primeros 13 días del mes de febrero. Esto de hecho aplica a la mayoría de las entidades. A partir del 15 de enero, los tuits y retuits corresponden básicamente a Leopoldo López.

Texto

Antes de analizar los mensajes de los tuits, resumamos la cantidad y tipo de mensajes. En concreto hay:

## [1] "2 @-mensaje(s) de 1 tuitero(s) para 1 receptor (es)."

Por otra parte tenemos:

## [1] "10 mensajes retuiteados de 1 retuitero(s) y 4 receptor(es)."

Los retuits han venido y se han dirigido a:

g <- graph.data.frame(rts.df, directed = T)
plot(g, layout = layout.fruchterman.reingold, vertex.size = 1, asp = FALSE, 
    edge.arrow.size = 0.2, edge.arrow.width = 0.6)

plot of chunk grafoRetuits

Veamos ahora el contenido de los mensajes (los cinco primeros de 526:

## [1] "les invito a leer el comunicado completola protesta en la calle es constitucional y pacifica elquesecansapierde"                     
## [2] "gracias afernando h cardosoy alejandro toledo x comunicado sobre crisis en venezuela y mi encarcelamientolt"                         
## [3] "queremos rendir homenaje a losfallecidos q ha dejado la violenta represion d los organos d seguridad del regimen de nicolas madurolt"
## [4] "invito a tod mañana am m acaminata mujeresporlavida ydesde la av andres galarraga a la plza alfredo sadellt"                         
## [5] "desde ramo verdetan cerca e incomunicados te mandoabrazoejemplo d resistencia estamos del lado correcto d la historialt"             
## [6] "asi esratifico que el manifiesto que leí fue escrito del puño y letra de"

Elaboremos una distribución de frecuencia y veamos las 50 palabras más frecuentes:

##                            palabras freq
## calle                         calle  104
## venezuela                 venezuela   55
## fuerza                       fuerza   51
## lasalida                   lasalida   49
## lucha                         lucha   49
## hoy                             hoy   45
## estudiantes             estudiantes   33
## gobierno                   gobierno   32
## maduro                       maduro   32
## pueblo                       pueblo   30
## pais                           pais   29
## cambio                       cambio   27
## venezolanos             venezolanos   27
## mañana                       mañana   25
## plaza                         plaza   25
## mas                             mas   24
## unidad                       unidad   24
## unidadenlacalle     unidadenlacalle   23
## protesta                   protesta   22
## salir                         salir   21
## radical                     radical   20
## gente                         gente   19
## ser                             ser   19
## asamblea                   asamblea   17
## convocatoria           convocatoria   17
## juntos                       juntos   17
## pacifica                   pacifica   17
## vamos                         vamos   17
## activate                   activate   15
## entonces                   entonces   15
## soyradical               soyradical   15
## tachira                     tachira   15
## violencia                 violencia   15
## desastre                   desastre   13
## estadodelincuente estadodelincuente   13
## miedo                         miedo   13
## millones                   millones   13
## presos                       presos   13
## represion                 represion   13
## salgamos                   salgamos   13
## popular                     popular   12
## todas                         todas   12
## asi                             asi   11
## calles                       calles   11
## compromiso               compromiso   11
## frente                       frente   11
## gracias                     gracias   11
## solo                           solo   11
## asambleas                 asambleas   10
## cada                           cada   10

Elaboremos una nube de palabras con esta información

wordcloud(leopoldoTexto$palabras, leopoldoTexto$freq, random.order = FALSE, 
    random.color = FALSE, colors = brewer.pal(10, "Paired"))

plot of chunk nube3

Los mensajes de Leopoldo López en al lapso analizado estuvieron relacionado con la calle-Venezuela-lucha-la salida-hoy. Esos son los temas más frecuentes, por lo que podemos concluir que ellos explican las razones para las protestas.

Conclusiones

Podemos emplear R en el análisis del entorno empleando tuiter. Hemos usado como ejemplo la cosecha manual de 526 tuits del timeline de @leopoldolopez, recogidos el 3 de marzo del corriente. Con este ejercicio pudimos comprobar que:

  • Lopez envió dos tuits a @nicolasmaduro
  • López retuiteo básicamente de y hacia @volutadpopular en mayor medida
  • los mayores retuits de @voluntadpopular se producen en los primeros 13 días del mes de febrero
  • los hashtagas más frecuentes fueron #12f y #lasalidad
  • La calle ha sido la palabra más frecuente en los mensajes del timeline de @leopoldolopez

El análisis no es completo. Los códigos deben refinarse y probarse en otros tuits recogidos de la misma forma. No obstante, es posible obtener un visión global de los mensajes de un actor determinado.

No hay comentarios: