Creación con R de dendogramas semánticos y clústers de conversaciones en twitter
Ciberpolítica, Ciència

Creación con R de dendogramas semánticos y clústers de conversaciones en twitter

Elaborar un dendograma para una búsqueda en twitter es un complemento a la nube de palabras. Mientras que en la nube de tags buscamos que palabras son más utilizadas y las jerarquizamos según el número de veces que se han citado, no buscamos relaciones semánticas entre ellas.

El análisis clúster a través de un dendograma de las conversaciones que se producen en una búsqueda en twitter nos permite ver las relaciones semánticas entre palabras, y cómo se relacionan entre ellas. Es decir, nos permite ver “que conversaciones” se están produciendo y no sólo que palabras son más utilizadas.

Perdemos la capacidad de la nube de tags de jerarquizar el peso de cada palabra, por lo tanto este análisis puede ser un buen complemento al de la nube de tags.

Si te interesa entender mejor cómo funciona un análisis clúster.

El resultado que tendremos de este script es el siguiente, una gráfica donde veremos un “dendograma” donde las palabras más utilizadas estarán presentes, las palabras cuanto más asociadas a una misma frase estén tendrán una relación jerárquica más cercana. Algunas, como en este caso, aparecen juntas en numerosas frases y están enlazadas al mismo nivel, pero otras tienen mucha mayor distancia (comparten menos frases comunes). Con esta estructura de relación semántica podemos agrupar las conversaciones y obtener “clústers” o grupos de conversaciones.

dendograma

Un script que requiere más interpretación humana

La ejecución de este script tiene dos partes, una en la que introducimos los parámetros de búsqueda para que el script haga su trabajo, pero una segunda que nosotros tendremos que hacer el análisis de forma más intuitiva (pero aprovechando la capacidad de las librerías de R para hacer el análisis clúster). En esta parte interpretativa veremos el dendograma y decidiremos cuántos clústers queremos (entre 2 y 8), según el número de palabras que veamos y cómo intuitivamente veamos que podrían agruparse. Una vez el script elabora el número de clústers que creemos mejores, podremos etiquetarlos e identificarlos para crear una etiqueta que ayude a terceros a poder interpretar el dendograma.

dendograma.R

  1. ################################################
  2. ### Cargamos las librerías necesarias
  3. ## twitter para descargar datos
  4. ## tm (Text Mining)
  5. ## RColorBrewer para tener librerías de colores
  6. ## wordcloud para nubes de palabras
  7. ###############################################
  8.  
  9. library(twitteR)
  10. require(tm)
  11. library(wordcloud)
  12. library(RColorBrewer)
  13.  
  14. ## ATENCIÓN USUARIOS DE WINDOWS:
  15. ## Esta parte es necesaria para los usuarios de Windows para
  16. ## superar problemas de permisos
  17.  
  18. library(RCurl)
  19. options(RCurlOptions = list(cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl")))
  20. u = "https://raw.github.com/tonybreyal/Blog-Reference-Functions/master/R/bingSearchXScraper/bingSearchXScraper."
  21. x = getURL(u, cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl"))
  22.  
  23. ## Autentificación con twitter, tienes que tener tu propio fichero .RData acreditado
  24.  
  25. load("rcredenciales.RData") ## El tener tu propio .RData autentificado es una parte compleja
  26. registerTwitterOAuth(tw)
  27.  
  28. ##################### Aclaración para conseguir tu .RData ######################
  29. ## Una explicación de cómo obtenerlo:
  30. ##
  31. ## 1.- Necesitas darte de alta como desarrollador
  32. ## en dev.twitter.com
  33. ## 2.- Da de alta una app y consigue tu consumer key
  34. ## y tu secret ke y.
  35. ## 3.- Sigue los primeros pasos hasta conseguir el .RData:
  36. ## http://aaronccrowley.wordpress.com/2013/05/27/extracting-data-from-twitter-with-r/
  37. ##
  38. ## Alerta: si eres usuario de windows en el script citado
  39. ## tendrás que incluir las líneas 42 a 50 del actual Script al inicio del Script
  40. ## indicado en la web
  41. ####################################################
  42.  
  43. ############## Definición de variables ###########################
  44.  
  45. ## k es un número
  46. ## k define el número de clústers
  47. ## k es preguntado una vez elaborado el dendograma
  48.  
  49. ## terminobusqueda = String
  50. ## Es el nombre del usuario del que quiero buscar su nube de tags
  51.  
  52. terminobusqueda = readline("¿Cuál es el término de la búsqueda? ")
  53. # pequeño código para evitar dejar vacío el término de búsqueda
  54. while (terminobusqueda =="") terminobusqueda = readline("Por favor, define un término de búsqueda ")
  55.  
  56. ## TweetNumber = Number
  57. ## Es el número de twitts en los que quiero ahondar
  58.  
  59. TweetNumber = readline("¿Cuantos tweets quieres analizar? ")
  60. TweetNumber = as.numeric(unlist(strsplit(TweetNumber, ",")))
  61.  
  62. ## geografico = string (number(latitud), number(longitud), number+km(radio geogr?fico)) o NULL
  63. ## Es una variable que permite acotar las búsquedas a twitts geolocalizados
  64.  
  65. print ("Ejemplos de datos geográficos, Barcelona, 150km a la redonda:41.378476,2.1701334,150km")
  66.  
  67. geografico = readline("Ámbito geográfico, dejar vacio si no se quiere geolocalizar ")
  68. if (geografico=="") geografico=NULL
  69.  
  70. ## palabrasstop -> string
  71. ## String de palabras que no queremos que aparezcan en el dendograma
  72.  
  73. palabrasstop = readline("Define las palabras que no quieres que aparezcan (separadas por espacios y en minúsculas) ")
  74. palabrasstop = unlist(strsplit(palabrasstop, split=" "))
  75.  
  76. ############################################
  77. ## Ejecutamos la descarga de datos de twitter
  78. ############################################
  79.  
  80. mach_tweets = searchTwitter(terminobusqueda, n=TweetNumber, geocode=geografico)
  81. mach_text = sapply(mach_tweets, function(x) x$getText())
  82.  
  83. ########## Establezco el sistema local del idioma (solo para usuarios Windows)
  84. Sys.setlocale("LC_CTYPE", "spanish")
  85.  
  86. ## Función implícita no definida
  87. ## Transforma una Lista() en otra Lista()
  88. ## Objetivo: Sustituye los carácteres mal descargados por
  89. ## carácteres latinos que los scripts puedan leer sin problemas
  90.  
  91. mach_text = tolower(mach_text)
  92. mach_text = gsub("ã¡", "a", mach_text)
  93. mach_text = gsub("ã©", "e", mach_text)
  94. mach_text = gsub("ã³", "o", mach_text)
  95. mach_text = gsub("ãº", "u", mach_text)
  96. mach_text = gsub("ã±", "ñ", mach_text)
  97. mach_text = gsub("ã¨", "e", mach_text)
  98. mach_text = gsub("ã²", "o", mach_text)
  99. mach_text = gsub("ã", "i", mach_text)
  100.  
  101. ## Eliminamos los términos de b?squeda
  102. ## Transformamos una lista en otra lista
  103.  
  104. mach_text = gsub(terminobusqueda, "", mach_text)
  105.  
  106. ## Se define la función clean.text
  107. ## Transforma una Lista() en otra Lista()
  108. ## Objetivo: Filtra palabras (evita URL, @usuarios, etc...)
  109. ##
  110.  
  111. clean.text = function(x)
  112. {
  113. # tolower
  114. x = tolower(x)
  115. # remove rt
  116. x = gsub("rt", "", x)
  117. # remove at
  118. x = gsub("@\\w+", "", x)
  119. # remove punctuation
  120. x = gsub("[[:punct:]]", "", x)
  121. # remove numbers
  122. x = gsub("[[:digit:]]", "", x)
  123. # remove links http
  124. x = gsub("http\\w+", "", x)
  125. # remove tabs
  126. x = gsub("[ |\t]{2,}", "", x)
  127. # remove blank spaces at the beginning
  128. x = gsub("^ ", "", x)
  129. # remove blank spaces at the end
  130. x = gsub(" $", "", x)
  131. return(x)
  132. }
  133.  
  134. ### Hacemos la limpieza de texto
  135.  
  136. mach_text = clean.text(mach_text)
  137.  
  138. # Construimos un corpus
  139. mydata.corpus = Corpus(VectorSource(mach_text))
  140.  
  141. # volvemos a asegurar que las palabras estarán en minúsculas
  142. mydata.corpus = tm_map(mydata.corpus, tolower)
  143.  
  144. # eliminamos la puntuación
  145. mydata.corpus = tm_map(mydata.corpus, removePunctuation)
  146.  
  147. # elimina palabras comunes (del castellano y del catalán)
  148. my_stopwords = c(stopwords('spanish'),stopwords('catalan'), palabrasstop)
  149. mydata.corpus = tm_map(mydata.corpus, removeWords, my_stopwords)
  150.  
  151. # Transformamos elcurpus en una matriz
  152. mydata.dtm = TermDocumentMatrix(mydata.corpus)
  153.  
  154. # inspeccionamos la matriz
  155. mydata.dtm
  156.  
  157. # inspeccionamos las palabras más relevantes
  158. findFreqTerms(mydata.dtm, lowfreq=30)
  159.  
  160. # Eliminamos los sparse terms para simplificar los clusters
  161. # Si aumentamos el valor de sparse saldrán más palabras.
  162. # Con la actual configuración tendremos entre 10 y 30 palabras
  163. # Que es ideal para poder trabajar.
  164. mydata.dtm2 = removeSparseTerms(mydata.dtm, sparse=0.95)
  165. # Transformamos la matriz en un data frame
  166. mydata.df = as.data.frame(inspect(mydata.dtm2))
  167.  
  168. # hacemos algunas comprobaciones sobre el dataframe
  169. nrow(mydata.df)
  170. ncol(mydata.df)
  171. mydata.df.scale = scale(mydata.df)
  172. d = dist(mydata.df.scale, method = "euclidean") # definimos la distancia
  173. fit = hclust(d, method="ward") # definimos el método para hacer clusters
  174.  
  175. ############################
  176. ## Dibujamos el dendograma
  177. ############################
  178.  
  179. ## Parte 1
  180. # Generamos el dendograma
  181.  
  182. plot(fit, main="")
  183.  
  184. # Ponemos un título al dendograma
  185. titulo = c("Dendograma en twitter de ", terminobusqueda)
  186. title(titulo)
  187.  
  188. ## Parte 2
  189. ## Dibujamos los clusters
  190. k = readline("¿Cuántos clústers quieres dibujar? ")
  191. k = as.numeric(unlist(strsplit(k, ",")))
  192. rect.hclust(fit, k, border=rainbow(k))
  193.  
  194. ### Parte 3, interpretación del dendograma
  195.  
  196. ## Pedimos al usuario que identifique
  197. ## cada cluster y le de una definición para
  198. ## poder escribir la leyenda
  199.  
  200. cluster1 = NULL
  201. cluster2 = NULL
  202. cluster3 = NULL
  203. cluster4 = NULL
  204. cluster5 = NULL
  205. cluster6 = NULL
  206. cluster7 = NULL
  207. cluster8 = NULL
  208.  
  209. cluster1 = readline("¿Cómo defines el primer clúster? ")
  210. cluster2 = readline("¿Cómo defines el 2o clúster? ")
  211. if (k>2) cluster3 = readline("¿Cómo defines el 3er clúster? ")
  212. if (k>3) cluster4 = readline("¿Cómo defines el 4o clúster? ")
  213. if (k>4) cluster5 = readline("¿Cómo defines el 5o clúster? ")
  214. if (k>5) cluster6 = readline("¿Cómo defines el 6o clúster? ")
  215. if (k>6) cluster7 = readline("¿Cómo defines el 7o clúster? ")
  216. if (k>7) cluster8 = readline("¿Cómo defines el 8o clúster? ")
  217.  
  218. ## Dibujamos la leyenda segun los criterios del
  219. ## usuario.
  220.  
  221. labels.clusters = c(cluster1, cluster2, cluster3, cluster4, cluster5, cluster6, cluster7, cluster8)
  222. legend("topright", legend = labels.clusters, fill = rainbow(k), title = "Clusters", box.col = "black", bg="transparent")
Web semántica ¿Qué es esto?
software image
no rating based on 0 votes
Nombre de la aplicación
Creación con R de dendogramas semánticos y clústers de conversaciones en twitter
Sistema operativo
R (Versión 3.0.2)
Página donde está ubicada

Soc coordinador de la revista electrònica i xarxa de bloggers www.socialdemocracia.org, webmaster de la UGT de Catalunya i militant del PSC.

2 thoughts on “Creación con R de dendogramas semánticos y clústers de conversaciones en twitter

  1. Hola, he intentado probarlo y me dice que el máximo de twits que puedo leer es 5. Voy a investigar las limitaciones de la API y de mi aplicación, porque me interesa bastante esta herramienta. ¡Saludos y gracias!

  2. Dime que #hashtag o búsqueda estás trabajando, es posible que la API por límite temporal sólo encuentre 5 twitts, me ha pasado que he puesto 5000 y me ha devuelto sólo unos cientos, pero nunca tan pocos. Mira la ayuda de R a twitsearch() y ver si hay algún factor que estás limitando.

Deja un comentario