Análisis de sentimiento con datos de Twitter

En este ejercicio vamos a intentar de analizar los comentarios en la red social Twitter de una empresa u organización en particular para conocer como son las opiniones que recibe que esten vinculadas al nombre de la empresa.

Para poder realizar este ** “Análisis de sentimiento” ** lo que vamos a hacer es utilizar la API de Twitter dándonos de alta como desarrollador y crear una aplicación para a través de la cual acceder a los datos de Twitter de una cuenta determinada. A partir de ahí haremos una limpieza de los datos para obtener los elementos con los que trabajar y realizar un analisis de datos.

Debemos tener en cuenta que en algunos casos el análisis de sentimiento en redes sociales se puede complicar según el tema, puesto para una situación concreta un comentario puede ser clasificado como negativo al no tener en cuenta el contexto. Así, por ejemplo, en una situación de guerra que haya comentarios negativos es entendible, y si esos comentarios se mezclan con otros en la cual no debería haber comentarios negativos se produce una mezcla inconcluyente. Más aún, es común que en muchos idiomas, entre ellos el español, palabras que en un principio son negativas, pueden ser usadas en tono amistoso.

Por lo tanto, para obtener resultados realistas y con un algoritmo que funcione bien se debe tener el contexto y elegir bien la muestra.

Veamos los pasos que hemos seguido para realizar este análisis.

Abrir una cuenta de desarrollador Antes de empezar hay que darse de alta en Twitter como desarrollador utilizando la cuenta personal de la red social y registrar un App en el API: *https://apps.twitter.com/.*

En este caso hemos denominado la app de twitter como “Twitter Sentiment Analysis. UNED”. Una vez creada la app generamos una serie de tokens de acceso (Access token y * Access token secret ) y claves de la API (api_key* y API secret key). Estos son las claves y tokens generados:

api_key <- " rn6qOI9nUcnuA11r7sdQEcRGu "

api_secret <- " alAtSqZK1uWOs7O89YnwkqMRVBdIYPyaOl3gry2rXFkU1LnkpI "

access_token <- " 920582805981188097-q5R0cMpWxFK3cQoDN7vGyYj7sRvxLO8 "

access_token_secret <- " fu3q0vy8NiZlF2pwn6y5CD8SCwcEZmiRIPBRTjprQFGeM"

twitter_app <- " Twitter Sentiment Analysis. UNED"

Estas claves las podemos regenerar siempre que queramos.

Una vez creada la cuenta de desarrollador y generadas las claves y tokens podemos instalar algunos paquetes necesarios para realizar el análisis de sentimiento.

Instalamos algunos paquetes

if(!is.element("Rstem", installed.packages()[, 1]))
      install.packages("Rstem", repos = 'http://cran.us.r-project.org')
install.packages("sentiment", repos = "http://www.omegahat.org/R", type = "source")
if(!is.element("sentiment", installed.packages()[, 1]))
      install.packages("sentiment", repos = 'http://cran.us.r-project.org')
if(!is.element("devtools", installed.packages()[, 1]))
      install.packages("devtools", repos = 'http://cran.us.r-project.org')
require(devtools)
if(!is.element("twitteR", installed.packages()[, 1]))
      install.packages("twitteR", repos = 'http://cran.us.r-project.org')
install.packages("Rstem", repos = "http://www.omegahat.org/R", type = "source")
install_url("http://cran.r-project.org/src/contrib/Archive/sentiment/sentiment_0.2.tar.gz")
require(sentiment)
ls("package:sentiment")
if(!is.element("tm", installed.packages()[, 1]))
      install.packages("tm", repos = 'http://cran.us.r-project.org')
if(!is.element("httr", installed.packages()[, 1]))
      install.packages("httr", repos = 'http://cran.us.r-project.org')
if(!is.element("rjson", installed.packages()[, 1]))
      install.packages("rjson", repos = 'http://cran.us.r-project.org')
if(!is.element("bit64", installed.packages()[, 1]))
      install.packages("bit64", repos = 'http://cran.us.r-project.org')
if(!is.element("RCurl", installed.packages()[, 1]))
      install.packages("RCurl", repos = 'http://cran.us.r-project.org')
install.packages("wordcloud")

Cargamos las librerías

# library(twitteR)
if(!is.element("rtweet", installed.packages()[,1]))
  install.packages("rtweet", repos = 'http://cran.us.r-project.org')
library(rtweet)
library(wordcloud)
## Loading required package: RColorBrewer
library(RColorBrewer)
library(plyr)
library(ggplot2)
library(sentiment)
## Loading required package: tm
## Loading required package: NLP
## 
## Attaching package: 'NLP'
## The following object is masked from 'package:ggplot2':
## 
##     annotate
## Loading required package: Rstem

Una vez cargadas las librerias, accedemos a Twitter a través de los datos del token.

api_key             <- "lhoFGi7WwTCNweSwjLAf0pcsO"
api_secret          <- "HX5YP7MaRb0pri3G73tbIIqvv8qbUGiptsY4fsL9bCN6YjN9zv"
access_token        <- "920582805981188097-kydfkJ915usop34k1VQd9uMBVKTxnaL"
access_token_secret <- "73LOfzcjfIPlUUNoDVOVXYt5uEpBPaiM16EnSk9HD7pUO"
twitter_app         <- " Twitter Sentiment Analysis. UNED"


# Accedemos a Twitter a través de los datos del token
create_token(
  app             = twitter_app,
  consumer_key    = api_key,
  consumer_secret = api_secret,
  access_token    = access_token,
  access_secret   = access_token_secret)
## <Token>
## <oauth_endpoint>
##  request:   https://api.twitter.com/oauth/request_token
##  authorize: https://api.twitter.com/oauth/authenticate
##  access:    https://api.twitter.com/oauth/access_token
## <oauth_app>  Twitter Sentiment Analysis. UNED
##   key:    lhoFGi7WwTCNweSwjLAf0pcsO
##   secret: <hidden>
## <credentials> oauth_token, oauth_token_secret
## ---

Antes de cargar los datos con los que queremos hacer el análisis de sentimiento podríamos ejecutar algunas funciones que nos ofrece la librería rtweet como langs para ver el lenguaje aceptado por Twittter o emojis

A partir de ahora, una vez conectados con el API de Twitter, podemos cargar los datos con los que queremos trabajar.

Analisis de datos de Twitter

Cargamos los datos de Uber

Una vez que se completa la autorización, podemos ejecutar una búsqueda. Para este ejemplo, vamos a realizar una búsqueda de los tweets que mencionan una marca conocida: Uber España @Uber.

Vamos a restringir el resultado a una muestra total de 10.000 tweets escritos en inglés (lang = “en”). Si queremos que no se incluyan los Rtweets debemos incluir la siguiente función include_rts = FALSE. También es posible dar un rango de fechas y restricciones geográficas.

# Busqueda de la palabra Uber en español con geocode situado en Madrid y un radio de 600km. 

uber_tweets <- search_tweets("Uber", n = 10000, include_rts = FALSE, lang="es", geocode =  "40.42028,-3.70577,600km")
## Searching for tweets...
## Finished collecting tweets!

Sacamos el texto de los tweets.

# Sacamos el texto y lo definimos con la siguiente variable
uber_txt <- uber_tweets$text
# Otra forma de coger el texto
# some_txt = sapply(some_tweets, function(x) x$getText())
# Mostramos los 10 primeros
head(uber_txt, 10)
##  [1] "Y luego algunos sin materia gris andan defendiendo a #Uber y #Cabify. Pues aquí tenéis un claro ejemplo de lo que pasaría si el #Taxi dejara de prestar servicio. Ceporros, que os merecéis toda la mierda que tenéis, que no es poca. Españistán <f0><U+009F><U+0087><U+00AA><f0><U+009F><U+0087><U+00B8> https://t.co/s896P8ksDI"
##  [2] "@boye_g @loputosatir Esto no ha hecho más que empezar <f0><U+009F><U+0091><U+008C>https://t.co/ILohDHTN1P"                                                                                                                                                                                                   
##  [3] "Yo si fuese un #violador, sin lugar a dudas me metía a trabajar en un #Uber #Cabify. Allí no me exigen nada y tengo muchas victimas donde elegir #cabifymola #deleteUber #QuienAvisaNoEsTraidor"                                                                                                             
##  [4] "@PesetoLoco @firstdates_tv @Uber @cabify_espana Hoy en fisrt dates, precariedad en estado puro! Quien pagará la cena? <f0><U+009F><U+00A7><U+0090>"                                                                                                                                                          
##  [5] "Nosotros cumpliendo las leyes día si y día también, y los piratas de #Uber y #cabify haciendo lo que les da la gana. Hace tiempo que ya estamos cansados de esta situación. Aeropuerto del Prat @aena, zona de salidas. Los @mossos ni están ni se les espera... Can picha. https://t.co/KYB263eTrh"         
##  [6] "Hola @cabify_espana tengo entendido que si soy un violador y un pedófilo ex presidiario, puedo trabajar con vosotros, que no hay ningún problema. Como lo hago? Tengo que hacer solo un curso de 1h verdad? #Cabify #Uber"                                                                                   
##  [7] "@nunurob @Uber_ES A ver si tienes suerte y te lo devuelven Nuria, lo que hacen es una práctica habitual de estas empresas. Hay miles de denuncias en @LeaksUberCabify. Confía en el #taxi de siempre, legal y honrado y también tienen apps muy buenas. Saludos!"                                            
##  [8] "@oscar_herranz @airbnb_es @Uber @cabify_espana La economía global o el esclavismo del siglo XXI? <f0><U+009F><U+00A4><U+00A3> por cierto, ya veremos si se bloquean o no, este otoño o se bloquean esas apps o se bloquean las ciudades. A ver quien la tiene más grande <f0><U+009F><U+0098><U+0089>"       
##  [9] "@TAXIDRI87187936 @manowl @Uber_ES Si es amigo de nuestro enemigo, entonces no le ayudes. Que encima no da ni las gracias <f0><U+009F><U+0098><U+00AC> que se apañen las mierdas entre ellos <f0><U+009F><U+0098><U+008A>"                                                                                    
## [10] "Otra vez vuelve a pasar, un conductor de aplicación viola y mata a una chica joven #Uber #Cabify #Didi #VTC #Machismo https://t.co/A0SE53PGX8"

Limpieza de datos

ETL en RRSS

Ahora que tenemos los mensajes de Twitter, debemos limpiarlos antes de hacer cualquier análisis. Esto implica eliminar cierto contenido, como la puntuación, que no tiene contenido emocional y eliminar cualquier contenido que cause errores.

En general al trabajar con Redes Sociales se suelen hacer una serie de pasos para limpiar los datos, los cuales generalmente son: • Minúsculas. • Quitar nombres (@) • Quitar puntuación • Stopwords (palabras repetitivas). • Eliminación de números si fuese necesario.*

Quitamos los retweets

uber_txt <- gsub("(RT|via)((?:\\b\\W*@\\w+)+)", "", uber_txt)

# Veamos los 10 primeros tweets
head(uber_txt, 10)
##  [1] "Y luego algunos sin materia gris andan defendiendo a #Uber y #Cabify. Pues aquí tenéis un claro ejemplo de lo que pasaría si el #Taxi dejara de prestar servicio. Ceporros, que os merecéis toda la mierda que tenéis, que no es poca. Españistán <f0><U+009F><U+0087><U+00AA><f0><U+009F><U+0087><U+00B8> https://t.co/s896P8ksDI"
##  [2] "@boye_g @loputosatir Esto no ha hecho más que empezar <f0><U+009F><U+0091><U+008C>https://t.co/ILohDHTN1P"                                                                                                                                                                                                   
##  [3] "Yo si fuese un #violador, sin lugar a dudas me metía a trabajar en un #Uber #Cabify. Allí no me exigen nada y tengo muchas victimas donde elegir #cabifymola #deleteUber #QuienAvisaNoEsTraidor"                                                                                                             
##  [4] "@PesetoLoco @firstdates_tv @Uber @cabify_espana Hoy en fisrt dates, precariedad en estado puro! Quien pagará la cena? <f0><U+009F><U+00A7><U+0090>"                                                                                                                                                          
##  [5] "Nosotros cumpliendo las leyes día si y día también, y los piratas de #Uber y #cabify haciendo lo que les da la gana. Hace tiempo que ya estamos cansados de esta situación. Aeropuerto del Prat @aena, zona de salidas. Los @mossos ni están ni se les espera... Can picha. https://t.co/KYB263eTrh"         
##  [6] "Hola @cabify_espana tengo entendido que si soy un violador y un pedófilo ex presidiario, puedo trabajar con vosotros, que no hay ningún problema. Como lo hago? Tengo que hacer solo un curso de 1h verdad? #Cabify #Uber"                                                                                   
##  [7] "@nunurob @Uber_ES A ver si tienes suerte y te lo devuelven Nuria, lo que hacen es una práctica habitual de estas empresas. Hay miles de denuncias en @LeaksUberCabify. Confía en el #taxi de siempre, legal y honrado y también tienen apps muy buenas. Saludos!"                                            
##  [8] "@oscar_herranz @airbnb_es @Uber @cabify_espana La economía global o el esclavismo del siglo XXI? <f0><U+009F><U+00A4><U+00A3> por cierto, ya veremos si se bloquean o no, este otoño o se bloquean esas apps o se bloquean las ciudades. A ver quien la tiene más grande <f0><U+009F><U+0098><U+0089>"       
##  [9] "@TAXIDRI87187936 @manowl @Uber_ES Si es amigo de nuestro enemigo, entonces no le ayudes. Que encima no da ni las gracias <f0><U+009F><U+0098><U+00AC> que se apañen las mierdas entre ellos <f0><U+009F><U+0098><U+008A>"                                                                                    
## [10] "Otra vez vuelve a pasar, un conductor de aplicación viola y mata a una chica joven #Uber #Cabify #Didi #VTC #Machismo https://t.co/A0SE53PGX8"

Quitamos las personas (@)

uber_txt <- gsub("@\\w+", "", uber_txt)

# Ahora veremos 5 tweets
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a #Uber y #Cabify. Pues aquí tenéis un claro ejemplo de lo que pasaría si el #Taxi dejara de prestar servicio. Ceporros, que os merecéis toda la mierda que tenéis, que no es poca. Españistán <f0><U+009F><U+0087><U+00AA><f0><U+009F><U+0087><U+00B8> https://t.co/s896P8ksDI"
## [2] "  Esto no ha hecho más que empezar <ed><U+00A0><U+00BD><ed><U+00B1><U+008C>https://t.co/ILohDHTN1P"                                                                                                                                                                                                          
## [3] "Yo si fuese un #violador, sin lugar a dudas me metía a trabajar en un #Uber #Cabify. Allí no me exigen nada y tengo muchas victimas donde elegir #cabifymola #deleteUber #QuienAvisaNoEsTraidor"                                                                                                             
## [4] "    Hoy en fisrt dates, precariedad en estado puro! Quien pagará la cena? <ed><U+00A0><U+00BE><ed><U+00B7><U+0090>"                                                                                                                                                                                          
## [5] "Nosotros cumpliendo las leyes día si y día también, y los piratas de #Uber y #cabify haciendo lo que les da la gana. Hace tiempo que ya estamos cansados de esta situación. Aeropuerto del Prat , zona de salidas. Los  ni están ni se les espera... Can picha. https://t.co/KYB263eTrh"

Quitamos los links html

uber_txt <-  gsub("\\bhttp[a-zA-Z0-9]*\\b", "", uber_txt)
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a #Uber y #Cabify. Pues aquí tenéis un claro ejemplo de lo que pasaría si el #Taxi dejara de prestar servicio. Ceporros, que os merecéis toda la mierda que tenéis, que no es poca. Españistán <ed><U+00A0><U+00BC><ed><U+00B7><U+00AA><ed><U+00A0><U+00BC><ed><U+00B7><U+00B8> ://t.co/s896P8ksDI"
## [2] "  Esto no ha hecho más que empezar <ed><U+00A0><U+00BD><ed><U+00B1><U+008C>https://t.co/ILohDHTN1P"                                                                                                                                                                                           
## [3] "Yo si fuese un #violador, sin lugar a dudas me metía a trabajar en un #Uber #Cabify. Allí no me exigen nada y tengo muchas victimas donde elegir #cabifymola #deleteUber #QuienAvisaNoEsTraidor"                                                                                              
## [4] "    Hoy en fisrt dates, precariedad en estado puro! Quien pagará la cena? <ed><U+00A0><U+00BE><ed><U+00B7><U+0090>"                                                                                                                                                                           
## [5] "Nosotros cumpliendo las leyes día si y día también, y los piratas de #Uber y #cabify haciendo lo que les da la gana. Hace tiempo que ya estamos cansados de esta situación. Aeropuerto del Prat , zona de salidas. Los  ni están ni se les espera... Can picha. ://t.co/KYB263eTrh"

Quitamos los caracteres no alfanuméricos

uber_txt <- gsub("[^a-zA-Z0-9 ]", "", uber_txt)
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a Uber y Cabify Pues aqu tenis un claro ejemplo de lo que pasara si el Taxi dejara de prestar servicio Ceporros que os merecis toda la mierda que tenis que no es poca Espaistn  tcos896P8ksDI"            
## [2] "  Esto no ha hecho ms que empezar httpstcoILohDHTN1P"                                                                                                                                                                                                         
## [3] "Yo si fuese un violador sin lugar a dudas me meta a trabajar en un Uber Cabify All no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteUber QuienAvisaNoEsTraidor"                                                                        
## [4] "    Hoy en fisrt dates precariedad en estado puro Quien pagar la cena "                                                                                                                                                                                       
## [5] "Nosotros cumpliendo las leyes da si y da tambin y los piratas de Uber y cabify haciendo lo que les da la gana Hace tiempo que ya estamos cansados de esta situacin Aeropuerto del Prat  zona de salidas Los  ni estn ni se les espera Can picha tcoKYB263eTrh"

Quitamos la puntuación

uber_txt <- gsub("[[:punct:]]", "", uber_txt)
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a Uber y Cabify Pues aqu tenis un claro ejemplo de lo que pasara si el Taxi dejara de prestar servicio Ceporros que os merecis toda la mierda que tenis que no es poca Espaistn  tcos896P8ksDI"            
## [2] "  Esto no ha hecho ms que empezar httpstcoILohDHTN1P"                                                                                                                                                                                                         
## [3] "Yo si fuese un violador sin lugar a dudas me meta a trabajar en un Uber Cabify All no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteUber QuienAvisaNoEsTraidor"                                                                        
## [4] "    Hoy en fisrt dates precariedad en estado puro Quien pagar la cena "                                                                                                                                                                                       
## [5] "Nosotros cumpliendo las leyes da si y da tambin y los piratas de Uber y cabify haciendo lo que les da la gana Hace tiempo que ya estamos cansados de esta situacin Aeropuerto del Prat  zona de salidas Los  ni estn ni se les espera Can picha tcoKYB263eTrh"

Quitamos la palabra amp. La palabra amp (esta palabra deberíamos intentar quitarla siempre en las correcciones / limpieza ).

uber_txt <- gsub("amp ", "", uber_txt)
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a Uber y Cabify Pues aqu tenis un claro ejemplo de lo que pasara si el Taxi dejara de prestar servicio Ceporros que os merecis toda la mierda que tenis que no es poca Espaistn  tcos896P8ksDI"            
## [2] "  Esto no ha hecho ms que empezar httpstcoILohDHTN1P"                                                                                                                                                                                                         
## [3] "Yo si fuese un violador sin lugar a dudas me meta a trabajar en un Uber Cabify All no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteUber QuienAvisaNoEsTraidor"                                                                        
## [4] "    Hoy en fisrt dates precariedad en estado puro Quien pagar la cena "                                                                                                                                                                                       
## [5] "Nosotros cumpliendo las leyes da si y da tambin y los piratas de Uber y cabify haciendo lo que les da la gana Hace tiempo que ya estamos cansados de esta situacin Aeropuerto del Prat  zona de salidas Los  ni estn ni se les espera Can picha tcoKYB263eTrh"

Quitamos los tco. Los tco son un servicio que se usan para cortar los links

uber_txt <-  gsub("\\btco[a-zA-Z0-9]*\\b", "", uber_txt)
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a Uber y Cabify Pues aqu tenis un claro ejemplo de lo que pasara si el Taxi dejara de prestar servicio Ceporros que os merecis toda la mierda que tenis que no es poca Espaistn  "            
## [2] "  Esto no ha hecho ms que empezar httpstcoILohDHTN1P"                                                                                                                                                                                            
## [3] "Yo si fuese un violador sin lugar a dudas me meta a trabajar en un Uber Cabify All no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteUber QuienAvisaNoEsTraidor"                                                           
## [4] "    Hoy en fisrt dates precariedad en estado puro Quien pagar la cena "                                                                                                                                                                          
## [5] "Nosotros cumpliendo las leyes da si y da tambin y los piratas de Uber y cabify haciendo lo que les da la gana Hace tiempo que ya estamos cansados de esta situacin Aeropuerto del Prat  zona de salidas Los  ni estn ni se les espera Can picha "

Quitamos NAs

uber_txt <- uber_txt[!is.na(uber_txt)]
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a Uber y Cabify Pues aqu tenis un claro ejemplo de lo que pasara si el Taxi dejara de prestar servicio Ceporros que os merecis toda la mierda que tenis que no es poca Espaistn  "            
## [2] "  Esto no ha hecho ms que empezar httpstcoILohDHTN1P"                                                                                                                                                                                            
## [3] "Yo si fuese un violador sin lugar a dudas me meta a trabajar en un Uber Cabify All no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteUber QuienAvisaNoEsTraidor"                                                           
## [4] "    Hoy en fisrt dates precariedad en estado puro Quien pagar la cena "                                                                                                                                                                          
## [5] "Nosotros cumpliendo las leyes da si y da tambin y los piratas de Uber y cabify haciendo lo que les da la gana Hace tiempo que ya estamos cansados de esta situacin Aeropuerto del Prat  zona de salidas Los  ni estn ni se les espera Can picha "

Quitamos emoticonos

uber_txt <- iconv(uber_txt, 'UTF-8', 'ASCII')
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a Uber y Cabify Pues aqu tenis un claro ejemplo de lo que pasara si el Taxi dejara de prestar servicio Ceporros que os merecis toda la mierda que tenis que no es poca Espaistn  "            
## [2] "  Esto no ha hecho ms que empezar httpstcoILohDHTN1P"                                                                                                                                                                                            
## [3] "Yo si fuese un violador sin lugar a dudas me meta a trabajar en un Uber Cabify All no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteUber QuienAvisaNoEsTraidor"                                                           
## [4] "    Hoy en fisrt dates precariedad en estado puro Quien pagar la cena "                                                                                                                                                                          
## [5] "Nosotros cumpliendo las leyes da si y da tambin y los piratas de Uber y cabify haciendo lo que les da la gana Hace tiempo que ya estamos cansados de esta situacin Aeropuerto del Prat  zona de salidas Los  ni estn ni se les espera Can picha "

Limpieza de espacios, tabuladores, etc.

uber_txt <- gsub("[ \t]{2,}", "", uber_txt)
uber_txt <- gsub("^\\s+|\\s+$", "", uber_txt)
head(uber_txt, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a Uber y Cabify Pues aqu tenis un claro ejemplo de lo que pasara si el Taxi dejara de prestar servicio Ceporros que os merecis toda la mierda que tenis que no es poca Espaistn"         
## [2] "Esto no ha hecho ms que empezar httpstcoILohDHTN1P"                                                                                                                                                                                         
## [3] "Yo si fuese un violador sin lugar a dudas me meta a trabajar en un Uber Cabify All no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteUber QuienAvisaNoEsTraidor"                                                      
## [4] "Hoy en fisrt dates precariedad en estado puro Quien pagar la cena"                                                                                                                                                                          
## [5] "Nosotros cumpliendo las leyes da si y da tambin y los piratas de Uber y cabify haciendo lo que les da la gana Hace tiempo que ya estamos cansados de esta situacin Aeropuerto del Pratzona de salidas Losni estn ni se les espera Can picha"

Pasamos a minúsculas todo el texto

uber_txt <- tolower(uber_txt)
head(uber_txt, 5)
## [1] "y luego algunos sin materia gris andan defendiendo a uber y cabify pues aqu tenis un claro ejemplo de lo que pasara si el taxi dejara de prestar servicio ceporros que os merecis toda la mierda que tenis que no es poca espaistn"         
## [2] "esto no ha hecho ms que empezar httpstcoilohdhtn1p"                                                                                                                                                                                         
## [3] "yo si fuese un violador sin lugar a dudas me meta a trabajar en un uber cabify all no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteuber quienavisanoestraidor"                                                      
## [4] "hoy en fisrt dates precariedad en estado puro quien pagar la cena"                                                                                                                                                                          
## [5] "nosotros cumpliendo las leyes da si y da tambin y los piratas de uber y cabify haciendo lo que les da la gana hace tiempo que ya estamos cansados de esta situacin aeropuerto del pratzona de salidas losni estn ni se les espera can picha"
Comparación texto sin limpiar y con limpieza…

Vemos como nos ha quedado el texto y lo comparamos con el original antes de realizar toda la limpieza. Primero el original.

# head(sapply(uber_tweets, function(x) x$getText()), 10)
head(uber_tweets$text, 5)
## [1] "Y luego algunos sin materia gris andan defendiendo a #Uber y #Cabify. Pues aquí tenéis un claro ejemplo de lo que pasaría si el #Taxi dejara de prestar servicio. Ceporros, que os merecéis toda la mierda que tenéis, que no es poca. Españistán <f0><U+009F><U+0087><U+00AA><f0><U+009F><U+0087><U+00B8> https://t.co/s896P8ksDI"
## [2] "@boye_g @loputosatir Esto no ha hecho más que empezar <f0><U+009F><U+0091><U+008C>https://t.co/ILohDHTN1P"                                                                                                                                                                                                   
## [3] "Yo si fuese un #violador, sin lugar a dudas me metía a trabajar en un #Uber #Cabify. Allí no me exigen nada y tengo muchas victimas donde elegir #cabifymola #deleteUber #QuienAvisaNoEsTraidor"                                                                                                             
## [4] "@PesetoLoco @firstdates_tv @Uber @cabify_espana Hoy en fisrt dates, precariedad en estado puro! Quien pagará la cena? <f0><U+009F><U+00A7><U+0090>"                                                                                                                                                          
## [5] "Nosotros cumpliendo las leyes día si y día también, y los piratas de #Uber y #cabify haciendo lo que les da la gana. Hace tiempo que ya estamos cansados de esta situación. Aeropuerto del Prat @aena, zona de salidas. Los @mossos ni están ni se les espera... Can picha. https://t.co/KYB263eTrh"

Y el limpio

head(uber_txt, 5)
## [1] "y luego algunos sin materia gris andan defendiendo a uber y cabify pues aqu tenis un claro ejemplo de lo que pasara si el taxi dejara de prestar servicio ceporros que os merecis toda la mierda que tenis que no es poca espaistn"         
## [2] "esto no ha hecho ms que empezar httpstcoilohdhtn1p"                                                                                                                                                                                         
## [3] "yo si fuese un violador sin lugar a dudas me meta a trabajar en un uber cabify all no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteuber quienavisanoestraidor"                                                      
## [4] "hoy en fisrt dates precariedad en estado puro quien pagar la cena"                                                                                                                                                                          
## [5] "nosotros cumpliendo las leyes da si y da tambin y los piratas de uber y cabify haciendo lo que les da la gana hace tiempo que ya estamos cansados de esta situacin aeropuerto del pratzona de salidas losni estn ni se les espera can picha"

Vemos como hemos quitado la puntuación, links o emoticonos, entre otros. Una vez limpiado el texto podemos empezar a trabajar.

Análisis de texto

Creamos un corpus

Es necesario hacer un Corpus de tm para realizar otras operaciones de minería de texto.

uber_corpus <- Corpus(VectorSource(uber_txt))
inspect(uber_corpus[1:10])
## <<SimpleCorpus>>
## Metadata:  corpus specific: 1, document level (indexed): 0
## Content:  documents: 10
## 
##  [1] y luego algunos sin materia gris andan defendiendo a uber y cabify pues aqu tenis un claro ejemplo de lo que pasara si el taxi dejara de prestar servicio ceporros que os merecis toda la mierda que tenis que no es poca espaistn         
##  [2] esto no ha hecho ms que empezar httpstcoilohdhtn1p                                                                                                                                                                                         
##  [3] yo si fuese un violador sin lugar a dudas me meta a trabajar en un uber cabify all no me exigen nada y tengo muchas victimas donde elegir cabifymola deleteuber quienavisanoestraidor                                                      
##  [4] hoy en fisrt dates precariedad en estado puro quien pagar la cena                                                                                                                                                                          
##  [5] nosotros cumpliendo las leyes da si y da tambin y los piratas de uber y cabify haciendo lo que les da la gana hace tiempo que ya estamos cansados de esta situacin aeropuerto del pratzona de salidas losni estn ni se les espera can picha
##  [6] holatengo entendido que si soy un violador y un pedfilo ex presidiario puedo trabajar con vosotros que no hay ningn problema como lo hago tengo que hacer solo un curso de 1h verdad cabify uber                                           
##  [7] a ver si tienes suerte y te lo devuelven nuria lo que hacen es una prctica habitual de estas empresas hay miles de denuncias enconfa en el taxi de siempre legal y honrado y tambin tienen apps muy buenas saludos                         
##  [8] la economa global o el esclavismo del siglo xxipor cierto ya veremos si se bloquean o no este otoo o se bloquean esas apps o se bloquean las ciudades a ver quien la tiene ms grande                                                       
##  [9] si es amigo de nuestro enemigo entonces no le ayudes que encima no da ni las graciasque se apaen las mierdas entre ellos                                                                                                                   
## [10] otra vez vuelve a pasar un conductor de aplicacin viola y mata a una chica joven uber cabify didi vtc machismo

Al igual que se puede limpiar el texto con gsub, podemos limpiar el corpus con tm_map. En este chunk aplicamos la transformación a minúsculas, eliminación de números, puntuación, palabras comunes (stopwords) y espacios en blanco.

Ahora vamos a usar la función tm_map para mejorar el corpus y guardarlo en un nuevo objeto, uber_corpus_clean. Esta función tiene distintas posibilidades. Empezamos por pasar el texto a minúsculas y quitar los números

# Pasamos a minusculas
uber_corpus_clean <- tm_map(uber_corpus, tolower)
## Warning in tm_map.SimpleCorpus(uber_corpus, tolower): transformation drops
## documents
# Eliminamos los numeros
uber_corpus_clean <- tm_map(uber_corpus_clean, removeNumbers)
## Warning in tm_map.SimpleCorpus(uber_corpus_clean, removeNumbers):
## transformation drops documents
# Eliminamos la puntuacion
uber_corpus_clean <- tm_map(uber_corpus_clean, removePunctuation)
## Warning in tm_map.SimpleCorpus(uber_corpus_clean, removePunctuation):
## transformation drops documents
# Eliminamos los espacios en blanco
uber_corpus_clean <- tm_map(uber_corpus_clean, stripWhitespace)
## Warning in tm_map.SimpleCorpus(uber_corpus_clean, stripWhitespace):
## transformation drops documents
Eliminar palabras comunes: Stopwords

Como hemos visto el paquete tm nos proporciona la posibilidad de eliminar un grupo de palabras del corpus, limpiando el texto. Entre esas funciones, una de las más importante es stopwords(). Esta funcion nos permite eliminar palabras que se utilizan comunmente en el lenguaja, como articulos o preposiciones.

En español también podemos ver las palabras comunes y eliminarlas. Vemos las palabras incluidas en la función

stopwords(kind='es')
##   [1] "de"           "la"           "que"          "el"          
##   [5] "en"           "y"            "a"            "los"         
##   [9] "del"          "se"           "las"          "por"         
##  [13] "un"           "para"         "con"          "no"          
##  [17] "una"          "su"           "al"           "lo"          
##  [21] "como"         "más"          "pero"         "sus"         
##  [25] "le"           "ya"           "o"            "este"        
##  [29] "sí"           "porque"       "esta"         "entre"       
##  [33] "cuando"       "muy"          "sin"          "sobre"       
##  [37] "también"      "me"           "hasta"        "hay"         
##  [41] "donde"        "quien"        "desde"        "todo"        
##  [45] "nos"          "durante"      "todos"        "uno"         
##  [49] "les"          "ni"           "contra"       "otros"       
##  [53] "ese"          "eso"          "ante"         "ellos"       
##  [57] "e"            "esto"         "mí"           "antes"       
##  [61] "algunos"      "qué"          "unos"         "yo"          
##  [65] "otro"         "otras"        "otra"         "él"          
##  [69] "tanto"        "esa"          "estos"        "mucho"       
##  [73] "quienes"      "nada"         "muchos"       "cual"        
##  [77] "poco"         "ella"         "estar"        "estas"       
##  [81] "algunas"      "algo"         "nosotros"     "mi"          
##  [85] "mis"          "tú"           "te"           "ti"          
##  [89] "tu"           "tus"          "ellas"        "nosotras"    
##  [93] "vosotros"     "vosotras"     "os"           "mío"         
##  [97] "mía"          "míos"         "mías"         "tuyo"        
## [101] "tuya"         "tuyos"        "tuyas"        "suyo"        
## [105] "suya"         "suyos"        "suyas"        "nuestro"     
## [109] "nuestra"      "nuestros"     "nuestras"     "vuestro"     
## [113] "vuestra"      "vuestros"     "vuestras"     "esos"        
## [117] "esas"         "estoy"        "estás"        "está"        
## [121] "estamos"      "estáis"       "están"        "esté"        
## [125] "estés"        "estemos"      "estéis"       "estén"       
## [129] "estaré"       "estarás"      "estará"       "estaremos"   
## [133] "estaréis"     "estarán"      "estaría"      "estarías"    
## [137] "estaríamos"   "estaríais"    "estarían"     "estaba"      
## [141] "estabas"      "estábamos"    "estabais"     "estaban"     
## [145] "estuve"       "estuviste"    "estuvo"       "estuvimos"   
## [149] "estuvisteis"  "estuvieron"   "estuviera"    "estuvieras"  
## [153] "estuviéramos" "estuvierais"  "estuvieran"   "estuviese"   
## [157] "estuvieses"   "estuviésemos" "estuvieseis"  "estuviesen"  
## [161] "estando"      "estado"       "estada"       "estados"     
## [165] "estadas"      "estad"        "he"           "has"         
## [169] "ha"           "hemos"        "habéis"       "han"         
## [173] "haya"         "hayas"        "hayamos"      "hayáis"      
## [177] "hayan"        "habré"        "habrás"       "habrá"       
## [181] "habremos"     "habréis"      "habrán"       "habría"      
## [185] "habrías"      "habríamos"    "habríais"     "habrían"     
## [189] "había"        "habías"       "habíamos"     "habíais"     
## [193] "habían"       "hube"         "hubiste"      "hubo"        
## [197] "hubimos"      "hubisteis"    "hubieron"     "hubiera"     
## [201] "hubieras"     "hubiéramos"   "hubierais"    "hubieran"    
## [205] "hubiese"      "hubieses"     "hubiésemos"   "hubieseis"   
## [209] "hubiesen"     "habiendo"     "habido"       "habida"      
## [213] "habidos"      "habidas"      "soy"          "eres"        
## [217] "es"           "somos"        "sois"         "son"         
## [221] "sea"          "seas"         "seamos"       "seáis"       
## [225] "sean"         "seré"         "serás"        "será"        
## [229] "seremos"      "seréis"       "serán"        "sería"       
## [233] "serías"       "seríamos"     "seríais"      "serían"      
## [237] "era"          "eras"         "éramos"       "erais"       
## [241] "eran"         "fui"          "fuiste"       "fue"         
## [245] "fuimos"       "fuisteis"     "fueron"       "fuera"       
## [249] "fueras"       "fuéramos"     "fuerais"      "fueran"      
## [253] "fuese"        "fueses"       "fuésemos"     "fueseis"     
## [257] "fuesen"       "siendo"       "sido"         "tengo"       
## [261] "tienes"       "tiene"        "tenemos"      "tenéis"      
## [265] "tienen"       "tenga"        "tengas"       "tengamos"    
## [269] "tengáis"      "tengan"       "tendré"       "tendrás"     
## [273] "tendrá"       "tendremos"    "tendréis"     "tendrán"     
## [277] "tendría"      "tendrías"     "tendríamos"   "tendríais"   
## [281] "tendrían"     "tenía"        "tenías"       "teníamos"    
## [285] "teníais"      "tenían"       "tuve"         "tuviste"     
## [289] "tuvo"         "tuvimos"      "tuvisteis"    "tuvieron"    
## [293] "tuviera"      "tuvieras"     "tuviéramos"   "tuvierais"   
## [297] "tuvieran"     "tuviese"      "tuvieses"     "tuviésemos"  
## [301] "tuvieseis"    "tuviesen"     "teniendo"     "tenido"      
## [305] "tenida"       "tenidos"      "tenidas"      "tened"

La siguiente línea le dice a la función tm_map que elimine las palabras (removeWords) de corpus_clean que están en stopwords() del listado de palabras españolas.

uber_corpus_clean <- tm_map(uber_corpus_clean, removeWords, stopwords(kind = "es"))
## Warning in tm_map.SimpleCorpus(uber_corpus_clean, removeWords,
## stopwords(kind = "es")): transformation drops documents

Ahora podemos hacer un Document-Term Matrix (dtm) y un Term Document Matrix (tdm)

Term Document Matrix (tdm)
uber_tdm           <- TermDocumentMatrix(uber_corpus_clean, control = list(stopwords = TRUE))
uber_tdm           <- as.matrix(uber_tdm)
Document-Term Matrix (dtm)

Hacemos un dtm para ver cuantas veces aparecen las palabras en el documento.

uber_dtm <- DocumentTermMatrix(uber_corpus_clean, control = list(minWordLength = 1, stopwords = TRUE))
inspect(uber_dtm)
## <<DocumentTermMatrix (documents: 1771, terms: 6185)>>
## Non-/sparse entries: 18164/10935471
## Sparsity           : 100%
## Maximal term length: 62
## Weighting          : term frequency (tf)
## Sample             :
##       Terms
## Docs   autnomos cabify coches efectivo invierte madrid millones taxi
##   1042        0      0      0        0        0      0        0    0
##   1048        0      1      0        0        0      0        0    1
##   1081        0      1      0        0        0      0        0    0
##   1222        0      1      0        0        0      0        0    0
##   1456        0      0      0        0        0      0        0    1
##   1559        0      0      0        0        0      1        0    0
##   1747        0      1      0        0        0      0        0    0
##   512         0      0      1        0        1      0        1    0
##   805         0      0      0        0        0      0        0    2
##   861         0      0      0        0        0      0        0    0
##       Terms
## Docs   toyota uber
##   1042      0    2
##   1048      0    1
##   1081      0    1
##   1222      0    1
##   1456      0    1
##   1559      0    0
##   1747      0    1
##   512       3    3
##   805       0    1
##   861       0    0

En el caso del DTM vemos cuantas veces se repiten las palabras.

Hacemos el stem

El stem es util para sacar la raíz de las palabras.

uber_corpus_stem <- tm_map(uber_corpus_clean, stemDocument)
## Warning in tm_map.SimpleCorpus(uber_corpus_clean, stemDocument):
## transformation drops documents
uber_corpus_stem <- tm_map(uber_corpus_stem, stemCompletion, dictionary = uber_corpus_clean)
## Warning in tm_map.SimpleCorpus(uber_corpus_stem, stemCompletion, dictionary
## = uber_corpus_clean): transformation drops documents
inspect(uber_corpus_stem[1:5])
## <<SimpleCorpus>>
## Metadata:  corpus specific: 1, document level (indexed): 0
## Content:  documents: 5
## 
## luego materia gris andan defendiendo uber cabifi pue aqu teni claro ejemplo pasara si taxi dejara prestar servicio ceporro mereci toda mierda teni poca espaistn 
##                                                                                                                                                                  
##                                                                                                                               hecho ms empezar httpstcoilohdhtnp 
##                                                                                                                                                                  
##                                       si violador lugar duda meta trabajar uber cabifi all exigen mucha victima elegir cabifymola deleteub quienavisanoestraidor 
##                                                                                                                                                                  
##                                                                                                                       hoy fisrt date precariedad puro pagar cena 
##                                                                                                                                                                  
##           cumpliendo ley da si da tambin pirata uber cabifi haciendo da gana hace tiempo cansado situacin aeropuerto pratzona salida losni estn espera can picha 
## 
Términos frecuentes

Términos más frecuentes frecuentes. Ponemos la frecuencia mínima 10 y ponemos en un “head” que nos devuelva los 40 primeros.

head(findFreqTerms(uber_dtm, lowfreq=10), 40)
##  [1] "aqu"        "cabify"     "claro"      "luego"      "mierda"    
##  [6] "pues"       "servicio"   "taxi"       "uber"       "lugar"     
## [11] "muchas"     "trabajar"   "hoy"        "pagar"      "aeropuerto"
## [16] "espera"     "estn"       "gana"       "hace"       "haciendo"  
## [21] "tambin"     "tiempo"     "hacer"      "ningn"      "problema"  
## [26] "puedo"      "solo"       "verdad"     "apps"       "denuncias" 
## [31] "empresas"   "hacen"      "siempre"    "ver"        "cierto"    
## [36] "ciudades"   "economa"    "encima"     "enemigo"    "aplicacin"

Vemos como tiene sentido que aparezcan muchas de estas palabras dentro de los tweets relacionados con la empresa estadounidense que ofrece servicios de transporte, siendo los tweets capturados aquellos que han sido escritos en español y en la geografia española. Entre estas palabras se encuentran: taxistas, ley, madrid, demandaran, cabify o tribunal.

Vamos a ver qué palabras están mas asociadas a la palabra cabify.

findAssocs(uber_dtm, 'cabify', 0.40)
## $cabify
## numeric(0)

Vemos que las palabras asociadas con cabify que son mas repetidas son vtc, economiacolaborativa, legislacion, facturacion o taxi.

Diccionario

Ahora vamos a crear un diccionario con las palabras con un número mínimo de apariciones de 5. Aunque antes existia una funcion concreta (Dictionary), esta funcion ya no existe.

Creamos una función

Dictionary <- function(x) {
    if( is.character(x) ) {
        return (x)
    }
    stop('x is not a character vector')
}

La aplicamos en el dtm

uber_dict  <- Dictionary(findFreqTerms(uber_dtm, 5))
head(uber_dict)
## [1] "aqu"     "cabify"  "claro"   "ejemplo" "luego"   "mierda"

Nube de palabras

library(wordcloud)
wordcloud(uber_corpus_clean, min.freq = 10, random.order = FALSE)

Análisis de los datos

Clasificar emociones

Ahora que tenemos el texto limpio para el análisis, podemos hacer análisis de opinión y sentimiento. La función classify_emotion “clasifica la emoción (por ejemplo, enfado, disgusto, miedo, alegría, tristeza o sorpresa) de un conjunto de textos usando un clasificador de Bayes entrenado en el”vocabulario de emociones“”.

Empezamos clasificando emociones con classify_emotion usando un algoritmo de bayes. Para saber mas podemos ejecutar directamente la ayuda para saber lo que hace.

?classify_emotion
## starting httpd help server ... done

Como se describe en la ayuda, esta función clasifica emociones (e.g. anger, disgust, fear, joy, sadness, surprise) de una serie de textos.

uber_class_emo <- classify_emotion(uber_txt, algorithm="bayes", prior=1.0)

La función nos retorna 7 columnas: anger, disgust, fear, joy, sadness, surprise y best_fit para cada fila del documento

head(uber_class_emo)
##      ANGER              DISGUST            FEAR              
## [1,] "1.46871776464786" "3.09234031207392" "2.06783599555953"
## [2,] "1.46871776464786" "3.09234031207392" "2.06783599555953"
## [3,] "1.46871776464786" "3.09234031207392" "2.06783599555953"
## [4,] "1.46871776464786" "3.09234031207392" "2.06783599555953"
## [5,] "1.46871776464786" "3.09234031207392" "2.06783599555953"
## [6,] "7.34083555412328" "3.09234031207392" "2.06783599555953"
##      JOY                SADNESS           SURPRISE           BEST_FIT
## [1,] "1.02547755260094" "1.7277074477352" "2.78695866252273" NA      
## [2,] "1.02547755260094" "1.7277074477352" "2.78695866252273" NA      
## [3,] "1.02547755260094" "1.7277074477352" "2.78695866252273" NA      
## [4,] "1.02547755260094" "1.7277074477352" "2.78695866252273" NA      
## [5,] "1.02547755260094" "1.7277074477352" "2.78695866252273" NA      
## [6,] "1.02547755260094" "1.7277074477352" "2.78695866252273" "anger"

Ahora lo que vamos a hacer es crear una variable denominada “emotion” en la que guardemos los resultados que ha obtenido el algoritmo de forma ordenada. La que según el algoritmo encaja mejor (BEST_FIT) la guardamos.

Para facilitar la clasificación, vamos a substituir los NAs por unknown.

emotion <- uber_class_emo[, 7]
emotion[is.na(emotion)] <- "unknown"
table(emotion, useNA = "ifany")
## emotion
##    anger     fear      joy  sadness surprise  unknown 
##      298       38       92       21        4     1318

Veamos los sentimientos en un gráfico. Para ello tenemos que convertirlo en un data.frame.

library(ggplot2)
library(gridExtra)
uber_pie <- ggplot(as.data.frame(uber_class_emo), aes(x = factor(1), fill = factor(BEST_FIT))) + geom_bar(width = 1)

uber_pie + coord_polar(theta = "y") + ggtitle("Sentimiento Uber en España", subtitle = "Datos España") + ylab("Y") + xlab("X") + theme(plot.title = element_text(size=12, face='bold'))

Ahora veamos quitando los NA

library(ggplot2)
library(gridExtra)
uber_pie <- ggplot(as.data.frame(uber_class_emo), aes(x = factor(1), fill = factor(BEST_FIT)))  + geom_bar(width = 1)

uber_pie + coord_polar(theta = "y") + ggtitle("Sentimiento Uber en España", subtitle = "Datos España") + ylab("Y") + xlab("X") + scale_fill_brewer(palette = "RdYlGn") + theme(plot.title = element_text(size=12, face='bold'))

Polaridad

Ahora pasamos a ver otra clasificación, que es la de polaridad. Ahora obtenemos la polaridad. Clasificamos el texto en cuatro categorías:

  • POS: Sentimiento positivo
  • NEG: Sentimiento negativo
  • POS/NEG: Indefinido
  • BEST_FIT: La más probable

Podemos volver a ejecutar la ayuda para conocer como trabaja esta función. ?classify_polarity

Ejecutamos la función de clasificación de polaridad.

uber_class_pol <- classify_polarity(uber_txt, algorithm="bayes")
head(uber_class_pol, 5)
##      POS                NEG                 POS/NEG             
## [1,] "1.03127774142571" "26.8423564950873"  "0.0384197915564697"
## [2,] "1.03127774142571" "0.445453222112551" "2.31512017476245"  
## [3,] "1.03127774142571" "9.47547003995745"  "0.108836578774127" 
## [4,] "1.03127774142571" "0.445453222112551" "2.31512017476245"  
## [5,] "8.78232285939751" "0.445453222112551" "19.7154772340574"  
##      BEST_FIT  
## [1,] "negative"
## [2,] "positive"
## [3,] "negative"
## [4,] "positive"
## [5,] "positive"

Ahora guardamos con la variable polarity los resultados obtenidos de la columna “BEST_FIT”. Esto nos permitirá conocer hacia donde se inclina la balanza, bien hacia comentarios positivos o negativos.

polarity <- uber_class_pol[, 4]
head(polarity)
## [1] "negative" "positive" "negative" "positive" "positive" "negative"

En una tabla

table(polarity, useNA = 'ifany')
## polarity
## negative  neutral positive 
##      382       84     1305

La mayoria de los comentarios parecen ser positivos.

Podemos recopilar la información en un dataframe por si más adelante queremos utilizarlo. Lo clasificamos en texto, emoción y polaridad.

uber_sentiment_dataframe <- data.frame(text=uber_txt, emotion=emotion, 
                                  polarity=polarity, stringsAsFactors=FALSE)
head(uber_sentiment_dataframe, 5)

Echemos un vistazo a algunas caracteristicas de este dataframe

Nombres de las variables

names(uber_sentiment_dataframe)
## [1] "text"     "emotion"  "polarity"

Estructura del dataframe

str(uber_sentiment_dataframe)
## 'data.frame':    1771 obs. of  3 variables:
##  $ text    : chr  "y luego algunos sin materia gris andan defendiendo a uber y cabify pues aqu tenis un claro ejemplo de lo que pa"| __truncated__ "esto no ha hecho ms que empezar httpstcoilohdhtn1p" "yo si fuese un violador sin lugar a dudas me meta a trabajar en un uber cabify all no me exigen nada y tengo mu"| __truncated__ "hoy en fisrt dates precariedad en estado puro quien pagar la cena" ...
##  $ emotion : chr  "unknown" "unknown" "unknown" "unknown" ...
##  $ polarity: chr  "negative" "positive" "negative" "positive" ...

Resumen del dataframe

summary(uber_sentiment_dataframe)
##      text             emotion            polarity        
##  Length:1771        Length:1771        Length:1771       
##  Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character

Reordenamos por emociones y polaridad.

uber_sentiment_dataframe <- within(uber_sentiment_dataframe, emotion <- factor(emotion, levels=names(sort(table(emotion), decreasing=TRUE))))
head(uber_sentiment_dataframe)
Graficos de emociones y polaridad

Número de Tweets clasificados por categorías de emociones

ggplot(uber_sentiment_dataframe, aes(x=emotion)) + geom_bar(aes(y=..count.., fill=emotion)) +
      scale_fill_brewer(palette="Dark2") +
      ggtitle("Análisis de sentimiento de Uber en Twitter", subtitle = "Datos Uber España") +
      theme(legend.position="right", plot.title = element_text(size=12, face='bold')) + ylab("Número de Tweets") + xlab("Tipos de emoción")

Gráfico de Polaridad por tweets

ggplot(uber_sentiment_dataframe, aes(x=polarity)) +
      geom_bar(aes(y=..count.., fill=polarity)) +
      scale_fill_brewer(palette="RdYlBu") +
      ggtitle("Análisis de sentimiento Uber en Twitter", subtitle = "Datos España") +
      theme(legend.position="bottom", plot.title = element_text(size=12, face='bold')) + ylab("Número de Tweets") + xlab("Tipos de polaridad")

Finalmente, veamos las palabras en los tweets y creamos una nube de palabras que usa las emociones de las palabras para determinar su ubicación dentro de la nube.

uber_sentiment_df = data.frame(text=uber_txt, emotion=emotion,
polarity=polarity, stringsAsFactors=FALSE)

# Separamos el texto segun las emociones
emotion_uber = levels(factor(uber_sentiment_df$emotion))
emotion_length = length(emotion_uber)
emotion_uber.docs = rep('', emotion_length)
for (i in 1: emotion_length) 
{
tmp = uber_txt[emotion == emotion_uber[i]]
emotion_uber.docs[i] = paste(tmp, collapse=' ')
}
 
# Eliminamos las Stopwords
emotion_uber.docs = removeWords(emotion_uber.docs, stopwords('es'))

# Creamos el corpus
corpus = Corpus(VectorSource(emotion_uber.docs))
tdm = TermDocumentMatrix(corpus)
tdm = as.matrix(tdm)
colnames(tdm) = emotion_uber
 
# Dibujamos una Comparison Wordcloud
comparison.cloud(tdm, colors = brewer.pal(emotion_length, 'Dark2'),
scale = c(1,.2), max.words = 400,random.order = FALSE, title.size = 1.5)

### Cerramos sesión

La función sessionInfo() nos sirve para ver los datos que hemos utilizado, para ver que datos están cargados, cuales eran los paquetes instalados. Esto nos sirve muchas veces para poder trazar lo que hemos hecho y ver errores posibles en el código.

# Terminamos la sesión con
sessionInfo()
## R version 3.4.4 (2018-03-15)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 17134)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=Spanish_Spain.1252  LC_CTYPE=Spanish_Spain.1252   
## [3] LC_MONETARY=Spanish_Spain.1252 LC_NUMERIC=C                  
## [5] LC_TIME=Spanish_Spain.1252    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] gridExtra_2.3      sentiment_0.2      Rstem_0.4-1       
##  [4] tm_0.7-5           NLP_0.1-11         ggplot2_3.0.0     
##  [7] plyr_1.8.4         wordcloud_2.6      RColorBrewer_1.1-2
## [10] rtweet_0.6.7.9000 
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_0.12.18     compiler_3.4.4   pillar_1.3.0     bindr_0.1.1     
##  [5] tools_3.4.4      digest_0.6.16    jsonlite_1.5     evaluate_0.11   
##  [9] tibble_1.4.2     gtable_0.2.0     pkgconfig_2.0.2  rlang_0.2.1     
## [13] curl_3.2         parallel_3.4.4   yaml_2.2.0       bindrcpp_0.2.2  
## [17] xml2_1.2.0       withr_2.1.2      httr_1.3.1       stringr_1.3.1   
## [21] dplyr_0.7.6      knitr_1.20       rprojroot_1.3-2  grid_3.4.4      
## [25] tidyselect_0.2.4 glue_1.3.0       R6_2.2.2         rmarkdown_1.10  
## [29] purrr_0.2.5      magrittr_1.5     SnowballC_0.5.1  backports_1.1.2 
## [33] scales_1.0.0     htmltools_0.3.6  assertthat_0.2.0 colorspace_1.3-2
## [37] labeling_0.3     stringi_1.1.7    openssl_1.0.2    lazyeval_0.2.1  
## [41] munsell_0.5.0    slam_0.1-43      crayon_1.3.4