Sobre los Tweets en el Paro Nacional
Los últimos meses del año pasado fueron escenario de varias movilizaciones alrededor del mundo, en respuesta a acciones gubernamentales de diversas índoles. En Ecuador, las protestas de octubre fueron detonadas por las medidas económicas anunciadas por la presidencia, en el contexto del cumplimiento de una agenda acordada con el Fondo Monetario Internacional.
Entre otras cosas, las medidas consistían en terminar inmediatamente el subsidio de combustibles. Como suele suceder con esta clase de medidas, ciertos sectores -estudiantil, indígena, agricultor, transportista- hubiesen sido los más afectados. Tras un paro nacional que se extendió del 3 al 13 de octubre, el gobierno retiró la propuesta. Para mayor información sobre la naturaleza de las medidas, la protesta de dichos sectores y la respuesta gubernamental, se recomienda consultar las siguientes fuentes: Wambra, Pichincha Comunicaciones1, Crisis y CONAIE.
El propósito de este artículo es demostrar cómo se ejecutó un análisis sobre tweets
generados entre el 1 y el 10 de octubre, considerando tres hashtags que fueron
populares durante el paro nacional en Ecuador. La premisa es que la elección de un
hashtag expone la intención del usuario, de reportar los hechos acontecidos o de
desaprobar la protesta. Originalmente se ejecutó el análisis con ayuda del paquete
twitteR
, que permite obtener tweets a través de la API gratuita de Twitter; para
esto, es necesario ejecutar previamente una proceso de autenticación2.
library(twitteR)
setup_twitter_oauth("...", "...", "...", "...") # claves personales de desarrollador
wambra = userTimeline("wambraEc", 100, excludeReplies = FALSE, includeRts = TRUE)
A manera de ejemplo se han obtenido cien publicaciones de la cuenta “wambraEc”, incluyendo replies y retweets. El resultado es una lista de tweets donde los respectivos metadatos están ocultos:
## [[1]]
## [1] "wambraEc: RT @CDHGYE: #ParoNacionalEc\n#MuertesEnElParo \n\n@CDHGYE agradece a @wambraEc por el trabajo periodístico sobre estas graves violaciones de D…"
##
## [[2]]
## [1] "wambraEc: RT @machadopepita: Esas son las vidas que menos importan al capitalismo, se vuelven descartables y nos corresponde honrarlas, no olvidar y…"
##
## [[3]]
## [1] "wambraEc: RT @kinoraxx: Un 8 de enero, dos adolescentes fueron asesinados a manos de la Policía ecuatoriana #HermanosRestrepo\n32 años después la impu…"
##
## [[4]]
## [1] "wambraEc: #MuertesEnElParo\nAnte el silencio y la falta de respuesta de las autoridades, sus familias decidieron contar sus hi… https://t.co/b5zXi9cuR6"
##
## [[5]]
## [1] "wambraEc: [ESPECIAL]\nSon 11 nombres, muy poco pronunciados en la historia del #ParoNacional #Ecuador\n\n¿Quiénes eran las perso… https://t.co/82jimxB9P0"
##
## [[6]]
## [1] "wambraEc: [INTERNACIONAL]\n#Chiapas: “Necesitamos y merecemos vivir”, ese fue el mensaje de clausura en el segundo Encuentro I… https://t.co/JKgRBVaQ0R"
Para tabular los metadatos se puede utilizar la función existente
twitteR::twListToDF()
o una función personalizada:
library(dplyr)
library(purrr)
user2na = function(user) ifelse(length(user) == 0, NA, paste0("@", user))
coor2na = function(coor) ifelse(length(coor) == 0, NA, as.double(coor))
twts2tbl = function(twts_list, time_zone = "GMT") tibble(
isrt = map_lgl(twts_list, ~.$isRetweet),
rts = map_dbl(twts_list, ~.$retweetCount),
favs = map_dbl(twts_list, ~.$favoriteCount),
time = map_dbl(twts_list, ~.$created) %>%
as.POSIXct(tz = time_zone, origin = "1970-01-01"),
lon = map_dbl(twts_list, ~coor2na(.$longitude)),
lat = map_dbl(twts_list, ~coor2na(.$latitude)),
user = map_chr(twts_list, ~user2na(.$screenName)),
rpto = map_chr(twts_list, ~user2na(.$replyToSN)),
text = map_chr(twts_list, ~.$text))
twts2tbl(tail(wambra), "America/Guayaquil")
## # A tibble: 6 x 9
## isrt rts favs time lon lat user rpto text
## <lgl> <dbl> <dbl> <dttm> <dbl> <dbl> <chr> <chr> <chr>
## 1 TRUE 19 0 2020-01-09 09:15:07 NA NA @wamb~ <NA> "RT @CDHGYE: ~
## 2 TRUE 25 0 2020-01-09 08:25:34 NA NA @wamb~ <NA> "RT @machadop~
## 3 TRUE 14 0 2020-01-09 08:25:03 NA NA @wamb~ <NA> "RT @kinoraxx~
## 4 FALSE 75 81 2020-01-08 22:17:37 NA NA @wamb~ @wamb~ "#MuertesEnEl~
## 5 FALSE 626 578 2020-01-08 22:17:36 NA NA @wamb~ <NA> "[ESPECIAL]\n~
## 6 FALSE 10 17 2020-01-06 12:54:11 NA NA @wamb~ <NA> "[INTERNACION~
Entre esas publicaciones se encuentra este artículo sobre las once personas que lamentablemente fallecieron participando en las manifestaciones, o de manera paralela a las mismas.
[ESPECIAL]
— Wambra Medio Comunitarioᅠ (@wambraEc) January 9, 2020
Son 11 nombres, muy poco pronunciados en la historia del #ParoNacional #Ecuador
¿Quiénes eran las personas que murieron,
cómo ocurrió su muerte,
tiene responsabilidad la Fuerza Pública?#MuertesEnElParo
8 historias
8 ilustraciones
Leer▶️ https://t.co/ln6WC7PzpI pic.twitter.com/V474IiktKA
Una vez tabulados los metadatos, existe una variedad de aspectos que pueden ser analizados. La siguiente tabla presenta el conteo de tweets que contienen cada hashtag, así como el porcentaje de los mismos que se han considerado únicos (esto es, no son replies ni su texto se encuentra repetido), el conteo de usuarios y la razón promedio de tweets por usuario.
hashtag | tweets (1) | únicos (2) | porcentaje (2÷1) | usuarios (3) | razón (1÷3) |
---|---|---|---|---|---|
#ParoNacionalEcuador | 13770 | 11471 | 0.8330 | 5297 | 2.600 |
#EcuadorPaisDePaz | 19754 | 13356 | 0.6761 | 5412 | 3.650 |
#ElParoSigue | 13083 | 10223 | 0.7814 | 3892 | 3.361 |
Un par de ideas se derivan de este conteo. La utilización de #EcuadorPaisDePaz (relacionado con una desaprobación de las protestas) presentó el porcentaje más bajo de tweets únicos y la razón más alta de tweets por usuario. Aunque los números no son particularmente atípicos, ponen en evidencia una forma de contribución cercana al spam. En contraposición, #ParoNacionalEcuador demuestra el porcentaje más alto de publicaciones diferentes, y la razón más baja de contribución por usuario; este hashtag fue utilizado comúnmente para reportar, con fotos y videos, eventos represivos y violentos ejecutados por las fuerzas gubernamentales.
Además, se halló que solo tres usuarios superaron en 85 tweets el uso de #ParoNacionalEcuador; entre ellos, la cuenta de Pichincha Comunicaciones. Por el contrario, fueron catorce las cuentas que publicaron #EcuadorPaisDePaz más de 85 veces, entre ellas: los ministerios de transporte y obras públicas, de desarrollo urbano y vivienda, y de salud pública; las secretarias técnica, del deporte, y de comunicación de la presidencia; el servicio de rentas internas y cuentas zonales del ministerio de inclusión económica y social. Esta observación confirma la sospecha de que se trató de propaganda, por parte de instituciones públicas, para desmerecer las demandas de los sectores movilizados.
Los datos resumidos en la tabla anterior fueron obtenidos a través de tres ejecuciones
de la función twitteR::searchTwitter()
, variando cada vez el hashtag de interés.
Notar el uso de un filtro que excluye retweets, pues de otra manera los tweets
devueltos habrían excedido el límite impuesto de veinte mil.
"#ParoNacionalEcuador -filter:retweets" %>%
searchTwitter(2e4, since = "2019-10-01", until = "2019-10-10")
Este análisis se efectuó originalmente en octubre; sin embargo, recuperar los datos aplicando este método resulta imposible. La razón es que la API gratuita permite obtener tweets con una semana3 de antigüedad como máximo, a diferencia del sitio web de Twitter que permite navegar por tweets de cualquier época. Afortunadamente, existe una alternativa diseñada por el programador Jefferson Henrique; básicamente es un programa java que simula la navegación en el sitio web de Twitter y recupera datos conforme son presentados. Los siguientes comandos representan la obtención de tweets que contengan #ParoNacionalEcuador a través de la command line (requiere git y java).
git clone https://github.com/Jefferson-Henrique/GetOldTweets-java
cd GetOldTweets-java
java -jar got.jar querysearch="#ParoNacionalEcuador" since=2019-10-01 until=2019-10-15
ren "output_got.csv" "output_ParoNacionalEcuador.csv"
Los resultados son escritos en un archivo de valores separados por comas, con dos particularidades: utiliza punto y coma como separador, e incurre en un uso inadecuado de las comillas. La siguiente función de lectura fue escrita teniendo en mente esas dos particularidades.
readHashTag = function(hashtag){
lines = readLines(paste0("output_", hashtag, ".csv")) %>%
gsub(";\"", ";'", .) %>% gsub("\";", "';", .)
class = c(date = "POSIXct", mentions = "NULL", hashtags = "NULL", id = "character")
read.csv2(text = lines, colClasses = class, quote = "'", na.strings = "") %>%
mutate(user = sub("^https://twitter.com/(\\w+)/status/\\d+$", "@\\1", permalink),
text = sub("https://twitter.com/.+$", "", text),
text = sub("pic.twitter.com/.+$", "", text),
ht = paste0("#", hashtag)) %>%
select(ht, id, time = date, text, user, retweets, favorites) %>%
as_tibble()
}
readHashTag("ParoNacionalEcuador")
## # A tibble: 244 x 7
## ht id time text user retweets favorites
## <chr> <chr> <dttm> <chr> <chr> <int> <int>
## 1 #ParoNa~ 118382~ 2019-10-14 14:15:00 "La #prensa f~ @FUND~ 183 109
## 2 #ParoNa~ 118357~ 2019-10-13 21:43:00 "#ATENCIÓN ES~ @kole~ 84 133
## 3 #ParoNa~ 118355~ 2019-10-13 20:11:00 "Aquellos que~ @Kati~ 47 111
## 4 #ParoNa~ 118351~ 2019-10-13 17:30:00 "#LoQueNoVera~ @Isma~ 66 66
## 5 #ParoNa~ 118350~ 2019-10-13 17:25:00 "#Urgente #AT~ @ecua~ 207 176
## 6 #ParoNa~ 118350~ 2019-10-13 17:19:00 "#ULTIMOMOMEN~ @Chal~ 73 49
## 7 #ParoNa~ 118350~ 2019-10-13 17:15:00 "#Ahora | Cac~ @xime~ 106 96
## 8 #ParoNa~ 118350~ 2019-10-13 17:14:00 "Pese al Esta~ @reli~ 228 238
## 9 #ParoNa~ 118350~ 2019-10-13 16:57:00 "Anunciamos a~ @radi~ 312 242
## 10 #ParoNa~ 118349~ 2019-10-13 16:17:00 "Asi luce la ~ @reli~ 65 62
## # ... with 234 more rows
En este caso se han recuperado solamente 244 de 11471 tweets con hashtag #ParoNacionalEcuador que se obtuvieron originalmente; se trata de una cantidad mínima pero, por lo que sabemos, es la única alternativa a contratar una API comercial de Twitter. En el siguiente artículo se explorará qué aspectos del análisis son posibles con esta cantidad reducida de datos.
A la fecha de publicación, el sitio web se encuentra suspendido debido a denuncias de la presidencia. De cualquier forma Pichincha Comunicaciones, al igual que las otras fuentes sugeridas, presenta en su Twitter la cobertura que realizó durante el paro.↩︎
La autenticación consiste en suministrar ciertas claves personales de consumidor y de acceso, y para obtener esas claves uno debe primero solicitar una cuenta de desarrollador en Twitter.↩︎
Existe otra API gratuita y oficial que recupera tweets de cualquier época, pero procedentes de una única cuenta; esta API es la utilizada en el ejemplo de “wambraEc”. La búsqueda por hashtag o texto sí está restringida a una semana.↩︎