knitr::opts_chunk$set(echo = TRUE) twitterAuthentication <- function(){ auth = yaml :: yaml.load_file("data/auth.yml") # Load authentication config file consumer_key <- auth$twitter_auth$consumer_key consumer_secret <- auth$twitter_auth$consumer_secret access_token <- auth$twitter_auth$access_token access_token_secret <- auth$twitter_auth$access_token_secret options(httr_oauth_cache=T) # Enables cache OAuth access credentials between R sessions setup_twitter_oauth(consumer_key, consumer_secret, access_token, access_token_secret) } getFollowersDataFrame <- function(tuser){ usersData <- list() CONST_FNUM <- 50 followers <- tuser$getFollowers(n = CONST_FNUM) for(i in 1: length(followers)){ usersData[[i]] <- data.frame(getUser(followers[[i]])$toDataFrame()) if(i%%10 == 0) { Sys.sleep(16*60) } } usersFrame <- ldply(usersData, rbind) return(cbind(usersFrame, friendships(usersFrame$screenName)[4:5])) } getFriendsDataFrame <- function(tuser){ usersData <- list() CONST_FRNUM <- 6 friends <- tuser$getFriends(CONST_FRNUM) for(i in 1:length(friends)){ usersData[[i]] <- data.frame(getUser(friends[[i]])$toDataFrame()) } usersFrame <- ldply(usersData, rbind) return(cbind(usersFrame, friendships(usersFrame$screenName)[4:5])) } getTopFollowers <- function(usersFrame){ ordredFrame <- usersFrame[with(usersFrame, order(-followersCount)),] return(data.frame(user = ordredFrame$screenName, followers = ordredFrame$followersCount)) } getTopFriends <- function(usersFrame){ ordredFrame <- usersFrame[with(usersFrame, order(-friendsCount)),] return(data.frame(user = ordredFrame$screenName, friends = ordredFrame$friendsCount)) } getTopTweets <- function(usersFrame){ ordredFrame <- usersFrame[with(usersFrame, order(-statusesCount)),] return(data.frame(user = ordredFrame$screenName, statuses = ordredFrame$statusesCount)) } fillMatrixOfTweets <- function(usersFrame, tweetsNumber) { mat <- matrix(nrow = dim(usersFrame)[1], ncol=tweetsNumber) for (i in 1:dim(usersFrame)[1]){ # for 'i' friends if(!usersFrame$protected[[i]]){ ttweets <- userTimeline(usersFrame$screenName[[i]], n=tweetsNumber, includeRts = TRUE) # load 20 tweets from friend 'i' if(length(ttweets) > 0){ for (j in 1:length(ttweets)) { mat[i,j] <- ttweets[[j]]$getText() } } # if(i%%10==0){ # Sys.sleep(15*60) # } } } return(mat) } getUserTweetsDataFrame <- function(user, number) { tweets<-userTimeline(user, n=number, includeRts = TRUE) tweetsData <- list() for(i in 1:length(tweets)){ tweetsData[[i]] <- data.frame(tweets[[i]]$toDataFrame()) if(i%%100 == 0) { Sys.sleep(16*60) } } return(ldply(tweetsData, rbind)) } getTweetsDataFrame <- function(textToSearch, geocode, number){ tweets<-searchTwitter(textToSearch, geocode = geocode, n=number, retryOnRateLimit=1) #links search on Tweeter tweetsData <- list() for(i in 1:length(tweets)){ tweetsData[[i]] <- data.frame(tweets[[i]]$toDataFrame()) if(i%%100 == 0){ Sys.sleep(16*60) } } return(ldply(tweetsData, rbind)) } getTweetsWithKeyword <- function(tweetsDataFrame, keyWordsList){ resTweets <- data.frame() for(tweet in tweetsDataFrame$text){ wordsFound <- list() for(keyWord in keyWordsList){ regExp <- paste("*",keyWord,"*") res <- grep(pattern = regExp, tweet, ignore.case = TRUE) if(length(res)>0){ #print(paste("Match with ", keyWord, " ", tweet, sep = "")) wordsFound <- c(wordsFound, keyWord) } } if(length(wordsFound)>0){ resTweets <- rbind(resTweets, data.frame(tweet = tweet, number = length(wordsFound))) } else { resTweets <- rbind(resTweets, data.frame(tweet = 0, number = 0)) } } return(resTweets) } plotReciprocalFollowsGraph <- function(me, userDataFrame){ v1 <- vector() v2 <- vector() for (i in 1:dim(userDataFrame)[1]) { row <- userDataFrame[i,] if(row$following == TRUE && row$followed_by == TRUE){ v1 <- c(me$name, row$screenName, v1) v2 <- c(row$screenName, me$name, v2) } } if(length(v1) > 0 && length(v2) > 0){ reciprocalGraph <- graph.data.frame(data.frame(v1 = v1, v2 = v2)) plot(reciprocalGraph) } else return("NA") } mapLocations <- function(..., colours) { dataFrames <- list(...) map <- get_map(location = 'Spain', zoom = 6) map <- ggmap(map) for(i in 1:length(dataFrames)){ coordinates <- geocode(dataFrames[[i]]$location) geom <- geom_point(data=coordinates, aes(x=lon, y=lat), colour=colours[i], size=3) map <- map + geom } map }
La intensa actividad en las redes sociales las ha convertido en fuentes de grandes volúmenes de información. En caso de Twitter, la extracción y el análisis de los datos propios de usuarios y mensajes, permitirá obtener múltiples resultados estadísticos. En este sentido y el marco de unas cercanas elecciones epañolas, se pretende realizar un análisis de los datos que se pueden obtener a partir de la cuenta de twitter oficial de los partidos políticos.
Se inicia el estudio ralizando una monitorización de los usuarios que siguen (los Followers) a un partido político, sea en este caso el PP (https://twitter.com/PPopular). El análisis se realiza sobre una muestra de 50 usuarios, a pesar de que la realidad es mucho mayor. El motivo es la restricción que impone Twitter para las consultas realizadas a través de API, limitadas a un máximo de 180 cada 15 minutos.
Primeramente, después de la autenticación a la API de Twitter se obtiene un conjunto data frame con los datos de 50 de los Followers del PP:
library(twitteR) library(plyr) twitterAuthentication() # Data frames with PP profile information tuserPp <- getUser("PPopular") # PP data frames with information of 50 friends followersDataFramePp <<- getFollowersDataFrame(tuserPp)
Inicialmente, tratamos de identificar los más relevantes Followers del partido.
library(twitteR) # PP friends analysis topFollowersPp <<- getTopFollowers(followersDataFramePp) topFriendsPp <<- getTopFriends(followersDataFramePp) topTweetsPp <<- getTopTweets(followersDataFramePp)
De este modo, en la siguiente tabla se visualizan: los usuarios que siguen a un mayor número de Friends, los más seguidos por Followers y los más activos en el envío de mensajes (Tweets).
library("knitr") library("xtable") # Table print options(xtable.floating = FALSE) options(xtable.timestamp = "") table <- cbind(head(topFollowersPp, n=3), head(topFriendsPp, n=3), head(topTweetsPp, n=3)) names(table) <- c("Usuario", "# Followers", "Usuario", "# Friends", "Usuario", "# Twits") xt <- xtable(table, align ="|l|ll|ll|ll|", digits = 0, caption = "Tabla 1. Usuarios influyentes en Twitter") print(xt, type = "html", floating = TRUE, latex.environments = "c")
Una vez analizados los usuarios más influyentes, se procede a estudiar el vínculo que une al PP con el global de usuarios. En este sentido, se construye un grafo para visualizar el vínculo entre usuarios: quién sigue a quién y si se da el caso que se siguen mútuamente.
# Grafo code plotReciprocalFollowsGraph(tuserPP, followersDataFramePp)
Adicionalmente, podemos extraer el comportamiento de lo usuarios mediante la distribución de su nivel de actividad en la red.
# Graph distribution of "Num of Users"" vs "Num of Tweets"" par(mar = rep(2,4)) hist(followersDataFramePp$statusesCount, breaks = 10, main = "Distribución de la activiad de los usuarios [nº usuarios/nº de Tweets]", col = "blue", border = "blue", axes = TRUE)
Finalmente, mediante la ubicación de los usuarios, podemos observar su distribución geográfica en el territorio.
De este modo, ánalogamente a los cálculos ya realizados, se obtienen los datos del PSOE (https://twitter.com/PSOE) y se realiza la comparativa de distribuciones geográficas entre los Followers de PP y PSOE.
library("twitteR") twitterAuthentication() # Data frames with PSOE profile information tuserPsoe <- getUser("PSOE") # PP data frames with information of 50 friends followersDataFramePsoe <<- getFollowersDataFrame(tuserPsoe)
# Map with PP and PSOE Followers library("ggmap") library("ggplot2") library("mapproj") library("plyr") mapLocations(followersDataFramePp, followersDataFramePsoe, colours = c("blue","red") )
Es posible extender el análisis a los Tweets enviados por los perfiles de usuario de los partidos políticos. En el estudio efectuado, se han tomado los últimos 100 Tweets escritos por PP y PSOE.
library("twitteR") library("plyr") twitterAuthentication() tweetsOfUserDataFramePsoe <<- getUserTweetsDataFrame(tuserPsoe, 100) tweetsOfUserDataFramePp <<- getUserTweetsDataFrame(tuserPp, 100)
De este modo, es posible obtener el historial temporal con la actividad en la red y comparar la cantidad de mensajes enviados entre partidos.
# Graphs of activity qplot(x = created, data = tweetsOfUserDataFramePp, main = "Actividad del PP [nº Tweets/tiempo]", xlab ="Tiempo", ylab = "Tweets", geom = "auto", colour = I("blue"), fill = I("blue")) qplot(x = created, data = tweetsOfUserDataFramePsoe, main = "Actividad del PSOE [nº Tweets/tiempo]", xlab ="Tiempo", ylab = "Tweets", geom = "auto", colour = I("red"), fill = I("red"))
A nivel de la actividad global en red, se analizan los últimos 100 Tweets que tratan sobre el PP o el PSOE enviados dentro del territorio español.
library("twitteR") library("plyr") twitterAuthentication() tweetsDataFramePp <- getTweetsDataFrame("PP", "40.2,-3.71,700km", number=200) tweetsDataFramePsoe <- getTweetsDataFrame("PSOE", "40.42,-3.71,700km", number=200)
A partir de los Tweets obtenidos sobre los diferentes partidos políticos, es posible analizar su contenido. De este modo, se estudia cuál de los hilos temáticos correspondientes usa un peor tono e incluye un mayor número de palabrotas.
keyWordsList <- readLines("data/insultos.txt") keyWordsDataFramePp <<- getTweetsWithKeyword(tweetsDataFramePp, keyWordsList) keyWordsDataFramePsoe <<- getTweetsWithKeyword(tweetsDataFramePsoe, keyWordsList)
library("graphics") library("base") pie(c(sum(keyWordsDataFramePp[,2]), 200 - sum(keyWordsDataFramePp[,2])), labels = c(paste ("Tweets con palabrotas - ", sum(keyWordsDataFramePp[,2]/200)*100, "%")), radius = 1, col = c("yellow", "blue"), main="Tweets sobre PP") pie(c(sum(keyWordsDataFramePsoe[,2]), 200 - sum(keyWordsDataFramePsoe[,2])), labels = c(paste ("Tweets con palabrotas - ", sum(keyWordsDataFramePsoe[,2]/200)*100, "%")), radius = 1, col = c("yellow", "red"), main="Tweets sobre PSOE")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.