Dibujar la nube de tags de un usuario de twitter con R

octubre 12, 2013 in Investigación, innovación y desarrollo de nuevas ideas

R es una herramienta excelente de “Social Network Analysis” para twitter, permite trabajar con búsquedas, perfiles, construir grafos, etc.. Una herramienta que descubrí el año pasado en el curso de SNA, y que estoy profundizando ahora.

Las posibiliades de R son muy amplias y hay numerosos tutoriales por la red. En este caso he querido vaciar la nube de tags de mis últimos 2000 twitts. El resultado, después de cierto trabajo de limpieza de algunos términos (por ejemplo adverbios, etc…) es el siguiente.

trinitro-twitts

Las nubes de tags son una manera gráfica de ver que palabras se han utilizado más en la elaboración de un texto o en un discurso, o en este caso en twitter. Muestra más el metalenguaje y las minúsculas que hay detrás de quien elabora el texto, que el contenido del mismo.

Vaciando mi nube de tags

En mi caso yo pensaba, por ejemplo, por mi perfil más independentista que estos temas serían los más relevantes, y en cambio están a un tercer nivel. Quien lidera es el concepto de “izquierda” seguido por “argumento” y “hacer”. Casi parezco un activista del postureo progre con estas palabras clave, “pensar y actuar desde la izquierda”, podría ser el lema de mis metatags.

En un tercer nivel aparece el término “soberanía” (ahí está mi aspecto “indepe”) y “creo”, no me suponía tan “humilde”. Lo curioso es que mi aspecto de crítica al PSC y al PSOE está en el enésimo lugar, en el conjunto de 50 palabras más utilizadas pero ahí, al fondo. Lo cuál indica que mis críticas no son tan frecuentes como algunos creen (yo mismo).

Curiosamente lo que esperaba en un principio, que mis tags estarían dominados en un primer nivel por el debate soberanista, no es así, sigo, incluso en un momento como este, hablando de temas asociados al eje social y mi crítica a la dirección del PSC y del PSOE es un tema muy secundario entre los temas de los que hablo en twitter.

La parte técnica, ¿cómo conseguirlo?

El Script que he utilizado es una versión mejorada de este. Se ha de utilizar en R, o R-Studio (con el R instalado, claro). El Script está lo suficientemente comentado para aclarar que hace casi cada línea de código y los problemas a los que te puedes enfrentar. Para utilizarlo hay que modificar 4 variables:

  • El nombre del usuario del que queremos extraer los datos (variable, user)
  • El número de twitts en los que queremos profundizar (variable, TweetNumber), cuantos más, más tardará el script y más posibilidades hay que alcancemos el límite que nos permite twitter a nuestra API funcionar, hay un límite máximo de 3.200.
  • Nombre del archivo donde queremos guardar la imagen final (variable, nombrearchivo)
  • Nombre del archivo .RData donde tendremos nuestra validación en la API de twitter. Esta es la parte más complicada, la solución está en los comentarios. Agradezco a Carlos Guadian, su orientación en esta parte.

Se puede grabar el archivo como un script de R, o bien copiar y pegar directamente (con la selección de nuestras variables) en la consola de R.

Recomendación a usuarios de R-Studio en Windows: Cuando grabéis el Script seleccionar hacerlo con codificación y esta sea Windows-1252, sino los elementos que transforman los carácteres especiales del castellano (acentos, ñ, etc..) en su forma final, no funcionarán.

 

Script nubetagsusuario.R

############# Objetivo del programa ###############################
## Nombre: Nube de palabras de los twitts de un usuario.
## Objetivo: Función que intenta hacer nube de lo que dice un usuario en twitter
## Descripción: Introduzco el nombre de un usuario de twitter 
## y consigo una imagen con la nube de tags
## de los últimos N twitts realizados.
## Output: Una imagen con la nube de tags
##
## Sistema en el que está testeado:
## R-Studio con R 3.0.2 funcionando bajo Windows-XP SP3
## Válido para la API de Twitter 1.1
###################################################################
 
############## Definición de variables ###########################
 
## user es una "String"
## Es el nombre del usuario del que quiero buscar su nube de tags
 
user =  readline("¿Cuál es el nombre del usuario? ") 
 
## TweetNumber es un "Number"
## Es el número de twitts en los que quiero ahondar
 
TweetNumber =  readline("Cuantos tweets quieres analizar? ")
TweetNumber <- as.numeric(unlist(strsplit(TweetNumber, ",")))
 
 
palabrasstop = readline("Define las palabras que no quieres que aparezcan (separadas por espacios y en minúsculas) ")
palabrasstop = unlist(strsplit(palabrasstop, split=" "))
 
############ Preámbulos necesarios para que funcione ##############
##
## Librerías que son necesarias para funcionar en R
## ¡Recuerda instalarlas antes!
#########################################################
 
library(twitteR)
library(tm)
library(wordcloud)
library(RColorBrewer)
 
## ATENCIÓN USUARIOS DE WINDOWS:
## Esta parte es necesaria para los usuarios de Windows para 
## superar problemas de permisos
 
library(RCurl)
options(RCurlOptions = list(cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl")))
u = "https://raw.github.com/tonybreyal/Blog-Reference-Functions/master/R/bingSearchXScraper/bingSearchXScraper."
x = getURL(u, cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl"))
 
## Autentificación con twitter, tienes que tener tu propio fichero .RData acreditado
 
load("rcredenciales.RData") ## El tener tu propio .RData autentificado es una parte compleja
registerTwitterOAuth(tw)
 
##################### Aclaración para conseguir tu .RData ######################
## Una explicación de cómo obtenerlo:
##
## 1.- Necesitas darte de alta como desarrollador 
## en dev.twitter.com
## 2.- Da de alta una app y consigue tu consumer key 
## y tu secret ke y.
## 3.- Sigue los primeros pasos hasta conseguir el .RData:
## http://aaronccrowley.wordpress.com/2013/05/27/extracting-data-from-twitter-with-r/
##
## Alerta: si eres usuario de windows en el script citado 
## tendrás que incluir las líneas 42 a 50 del actual Script al inicio del Script
## indicado en la web
####################################################
 
##################### Inicio el propio programa en sí mismo #######
 
##### Comenzamos descargándonos en nuestro Workspace los twitts del usuario
 
mach_tweets = userTimeline(user, n=TweetNumber)
 
###### Extraigo el texto de los tweets y hago una Lista
mach_text = sapply(mach_tweets, function(x) x$getText())
 
#####################################################
## Limpieza del texto de carácteres incompatibles o contenidos
## sin valor semántico (preposiciones, etc..)
##
## R gestiona mal los carácteres especiales del castellano y catalá
## Estos scripts sustituyen carácteres en castellano / catalán. 
## Si el script.R no está grabado con el Encoding adecuado 
## se ha de ejecutar el código en la consola a trozos a partir de
## aquí 
## Por ejemplo: La codificación del script ha de ser Windows para usuarios Windows
## y no UTF-8 o algún ISO
########################################################3
 
########## Establezco el sistema local del idioma (solo para usuarios Windows)
Sys.setlocale("LC_CTYPE", "spanish")
 
## Función no definida (para evitar problemas de ejecución
## he preferido ejecutar una por una las substituciones)
##
## Transforma una Lista() en otra Lista()
## Objetivo: Sustituye los carácteres mal descargados por
## carácteres latinos que los scripts puedan leer sin problemas
 
mach_text = tolower(mach_text)
mach_text = gsub("ã¡", "a", mach_text)
mach_text = gsub("ã©", "e", mach_text)
mach_text = gsub("ã³", "o", mach_text)
mach_text = gsub("ãº", "u", mach_text)
mach_text = gsub("ã±", "ñ", mach_text)
mach_text = gsub("ã¨", "e", mach_text)
mach_text = gsub("ã²", "o", mach_text)
mach_text = gsub("ã", "i", mach_text)
 
## Se define la función clean.text
## Transforma una Lista() en otra Lista()
## Objetivo: Filtra palabras (evita URL, @usuarios, etc...)
##
 
clean.text = function(x)
{
  # tolower
  x = tolower(x)
  # remove rt
  x = gsub("rt", "", x)
  # remove at
  x = gsub("@\\w+", "", x)
  # remove punctuation
  x = gsub("[[:punct:]]", "", x)
  # remove numbers
  x = gsub("[[:digit:]]", "", x)
  # remove links http
  x = gsub("http\\w+", "", x)
  # remove tabs
  x = gsub("[ |\t]{2,}", "", x)
  # remove blank spaces at the beginning
  x = gsub("^ ", "", x)
  # remove blank spaces at the end
  x = gsub(" $", "", x)
  return(x)
}
 
mach_text = clean.text(mach_text)
mach_text = gsub("mas", "", mach_text)   ## elimino la palabra "mas"
 
############################################
## Transformamos la lista de textos en vectores y 
## luego en una matriz
##############################################3
 
## Creamos un Corpus vectorial con los twitts
## Transformamos una Lista ()  en un Corpus de vectores
 
mach_corpus = Corpus(VectorSource(mach_text)
)
 
## Creamos una matriz, limpiamos los elementos que nos sobran (los artículos, etc..)
## Transformamos un Corpus en una matriz
 
# create document term matrix applying some transformations
 
tdm = TermDocumentMatrix(mach_corpus,
                         control = list(removePunctuation = TRUE,
                                        stopwords = c(stopwords("spanish"), stopwords("catalan"), "@", palabrasstop),
                                        removeNumbers = TRUE, tolower = TRUE))
# define tdm as matrix
m = as.matrix(tdm)
 
##################################################################
######### Contamos la frecuencia de las palabras utilizadas #######
##############################################################3
 
# get word counts in decreasing order
word_freqs = sort(rowSums(m), decreasing=TRUE)
# create a data frame with words and their frequencies
dm = data.frame(word=names(word_freqs), freq=word_freqs)
# plot wordcloud
wordcloud(dm$word, dm$freq, random.order=FALSE, max.words=25, colors=brewer.pal(8, "Dark2"))
 
##########   Guardo un archivo de texto con las palabras más usadas
## y su frecuencia 
## Puede ser utilizado después en otras herramientas de análisis, y
## abierto con Open Office, Excel, etc..
#############################################################3
 
## Construyo un nombre para el fichero txt basado en el usuario
 
fichero.txt = paste(user,".txt")
fichero.txt = gsub(" ", "", fichero.txt)
 
## Ejecuto el write que crea el fichero texto, este fichero
## tendrá tantas filas como palabras detectadas en los twitts
## y separado por un espacio el número de repeticiones
## La importación desde Excel o Open Office o Drive es trivial
## recordando que la separación es de un espacio
## Podemos forzar otro tipo de separaciones, por ejemplo ";"
## write.table(dm, fichero.txt,  row.names = FALSE, sep = ";") 
 
write.table(dm, fichero.txt,  row.names = FALSE)
 
######### Creo una nube de tags y lo transformo en el PNG #####################
 
 
## Construyo una paleta de colores 
degradado = function (color1, color2, degradados)
{
  library(grDevices)
  palete = colorRampPalette(c(color1, color2))
  palete (degradados)
}
mipaleta = degradado ("#DD0000", "#FFFF00", 25)
 
## Dibujo la nube de palabras 
 
par(bg = "black") ## Establezco un fondo negro 
wordcloud(dm$word, dm$freq, random.order=FALSE, colors=mipaleta) ## construye la nube de tags
mtext(paste("Nube de tags de @",user, " ", TweetNumber, " tweets analizados", sep=""),col="#FFFFFF") ## crea un texto que encabeza la nube
mtext(Sys.time(), side = 1, col="#FFFFFF")

Más código

 
¿Qué aporta este script?

Hay diversos tutoriales de Twitter Data Mining con R, pero muchos de los scripts que presentan carecen de la capacidad de construir programas y funciones reproducibles (o sabes bastante de R o personalizarlo se vuelve algo difícil), no suelen describir lo que hace cada parte (¿esta función me transforma una “string” en un número? ¿construye una matriz, pero a partir de qué… un vector, una lista?) y algunos tienen problemas de estructuración además no suelen contener comentarios para usuarios novatos (como un servidor).

Además muchos de estos tutoriales no contienen las soluciones a posibles problemas. Por ejemplo, los usuarios de windows siempre han de incluir el siguiente código para realizar autentificaciones a la API de twitter:

library(RCurl)
options(RCurlOptions = list(cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl")))
u = "https://raw.github.com/tonybreyal/Blog-Reference-Functions/master/R/bingSearchXScraper/bingSearchXScraper."
x = getURL(u, cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl"))

Por otro lado, los carácteres especiales del castellano (o el catalán), como los acentos, las “ñ” o las “ç” son mal gestionadas en los scripts que intentan hacer nubes de palabras. He mejorado esos problemas de forma parcial (seguramente haya mejores soluciones), y he indicado donde para que otro desarrollador pueda encontrar soluciones más avanzadas.

Estos problemas y otros menores los he ido descubriendo y los he incluido en un script completo, más comprensivo, que por ejemplo, el script original en el que está basado.