1.2. L'image du PSG
5.1. Les Etats-Unis
5.2. Le Monde
Twitter est un réseau social de microblogage créé en mars 2006
par J. Dorsey, E. Williams, B. Stone, N. Glass. Il permet à ses
utilisateurs de publier des messages limités à 140 caractères appelés
tweets. Twitter est aujourd'hui côté en bourse et compte 317 millions
d'utilisateurs. En moyenne 500 millions de tweets sont échangés chaque
jour sur ce réseau social. Des hommes politiques, des personnalités ou
encore des entreprises utilisent ce réseau à des fins de communication.
Chaque jour des millions de données sont générées et un tweet contient 31 métadonnées (identifiant de l'auteur du tweet, localisation, nombre de followers, identifiants des followers, nombre de retweets, etc...).
Afin d'exploiter ces Open Data, deux chemins s'offrent à nous :
effectuer une analyse textuelle du contenu des tweets (nuage de mots, analyse de l'état émotionnel d'un utilisateur, ...),
effectuer une analyse statistique des utilisateurs à l'aide des métadonnées.
Pour effectuer ces analyses, nous utilisons un package R : twitteR et
nous avons créé une API pour récupérer les données.
Il faut
renseigner les paramètres suivants : api_key, api_secret,
access_token, access_token_secret qui sont fournis par l'API Twitter
pour récupérer des tweets.
setup_twitter_oauth(api_key,api_secret,access_token,access_token_secret)
## [1] "Using direct authentication"
Dans un premier temps, nous proposons de faire des comparaisons
des mots les plus utilisés par les 7 candidats de la primaire de la
gauche. Il s'agit ici d'analyser le contenu des tweets des 7 candidats à
la primaire de la gauche, à savoir :
Le but étant d'afficher les mots qu'ils emploient le plus sur un même
nuage. En effet, les nuages de mots sont appréciés en datavisualisation
car ils permettent d'avoir une représentation graphique simple et
lisible de l'information contenue dans du texte.
Pour cela, nous
récupérons le texte des 1000 derniers tweets émis par les comptes des
différents candidats et ceux des retweets (sur Twitter lorsqu'un tweet
nous intéresse, nous pouvons le partager à nos abonnés à l'aide d'un
retweet).
Prenons pour exemple Manuel Valls. Nous utilisons la fonction userTimeline() pour récupérer 1000 de ses tweets (et les métadonnées sous-jacentes). Nous convertissons la liste des tweets en dataframe, puis nous récupérons le texte des tweets.
Nous itérons la procédure pour les 6 autres candidats.
# Manuel Valls
manuel_tweet = userTimeline("manuelvalls", n=1000, includeRts = TRUE)
m_tweet = twListToDF(manuel_tweet)
manuel_text = m_tweet$text
Nous nettoyons le texte à l'aide de la fonction clean.text() qui
permet d'enlever les caractères inutiles à notre analyse tels que les
accents, les liens, les caractères spéciaux...
# Fonction de nettoyage du texte (plus d'accents, de liens et de divers caractères spécifiques)
clean.text = function(x_text, word = stopwords(), lang = "fr")
{
if (lang == "fr"){
x_text = str_replace_all(x_text, "à", "a")
x_text = str_replace_all(x_text, "â", "a")
x_text = str_replace_all(x_text, "ç", "c")
x_text = str_replace_all(x_text, "é", "e")
x_text = str_replace_all(x_text, "è", "e")
x_text = str_replace_all(x_text, "ê", "e")
x_text = str_replace_all(x_text, "ù", "u")
x_text = str_replace_all(x_text, "ï", "i")
x_text = str_replace_all(x_text, "û", "u")
x_text = str_replace_all(x_text, "ô", "o")
x_text = str_replace_all(x_text, "î", "i")
}
x_text = sapply(x_text,function(x) iconv(x, "latin1", "ASCII", sub=""))
x_text = str_replace_all(x_text, "(RT|via)((?:\\b\\W*@\\w+)+)", " ")
x_text = str_replace_all(x_text, "(\r)", " ")
x_text = str_replace_all(x_text, "@\\w+", " ")
x_text = str_replace_all(x_text, "http.+", " ")
x_text = str_replace_all(x_text, "[[:punct:]]", " ")
x_text = str_replace_all(x_text, "[[:digit:]]", " ")
x_text = str_replace_all(x_text, "[ \t]{2,}", " ")
x_text = str_replace_all(x_text, "^\\s+|\\s+$", "")
x_text = str_trim(x_text)
return(x_text)
}
# Nettoyage des tweets de Manuel Valls
m_text = clean.text(manuel_text)
Après avoir agrégé les textes de tous les candidats, nous
convertissons cette liste en corpus qui contient 7 documents (un
document par candidat), puis appliquons la fonction TermDocumentMatrix
qui permet de compter les occurrences de chaque mots en prenant soin
d'enlever les stopwords (les stopwords sont des mots très courants dans
les phrases et vide de sens tels que les articles ou encore les
prépositions). Nous convertissons cet objet en matrice puis il ne reste
plus qu'à effectuer le nuage comparatif de mots.
# On convertit en corpus qui contient 7 documents
corpus = Corpus(VectorSource(primaire_text))
# On compte le nombre d'occurrences par mots pour chaque candidat (sans compter les stopwords et en mettant tous les caractères en minuscule)
tdm = TermDocumentMatrix(corpus, control = list(tolower = TRUE, stopwords = word))
tdm = as.matrix(tdm)
# On choisit la palette de couleurs à appliquer au nuage
couleurs <- brewer.pal(7,"Dark2")
# On construit le nuage de comparaison des candidats (par fréquence de mots décroissante)
comparison.cloud(tdm, scale=c(.75,.5), random.order=FALSE, colors = couleurs, title.size=1, max.words=150)
Le nuage comparatif permet de visualiser les mots les plus tweetés par les 7 candidats (chaque candidat est représenté par une couleur différente). Nous observons que les mots chers à chaque candidat apparaissent clairement. Par exemple :
pour Benoît Hamon se dégage le mot "revenu universel" (un des points du programme de ce candidat);
pour Sylvia Pinel le mot "logement" (ancienne ministre du logement);
pour Vincent Peillon le mot "ecole" (ancien ministre de l'éducation nationale);
pour Arnaud Montebourg les mots "made in France" et "economie" (ancien ministre de l'économie);
etc...
Rapidement, nous pouvons nous faire une idée des thèmes chers aux candidats.
Retour à la table des matières
Dans cette section, nous nous intéressons à la localisation des
tweets sur un même sujet, ici le Paris Saint-Germain. Nous cherchons à
observer l'existence de divergences sur les mots les plus utilisés dans
les tweets citant le PSG autour de Paris et autour de Marseille. Nous
utilisons cette fois la fonction searchTwitter() qui permet de récupérer
des tweets contenant un mot ou un hashtag spécifique en précisant la
langue des tweets et le géocode qui correspond à la latitude, la
longitude ainsi que le rayon (définissant le périmètre autour d'un point
géographique).
# Récupération des tweets en français contenant #psg dans un rayon de 100 kilomètres autour de Paris
psg_tweets_paris = searchTwitter('#psg', n=100, lang='fr', geocode="48.8,2.3,100km")
# Récupération du texte des tweets
psg_txt_paris = sapply(psg_tweets_paris, function(x) x$getText())
De la même manière que dans la précédente section, nous nettoyons
le texte des tweets et nous créons un Corpus afin d'appliquer la
fonction TermDocumentMatrix(). Nous effectuons ensuite un nuage
comparatif en utilisant la localisation des tweets.
# On construit le nuage de comparaison des deux villes (par fréquence de mots décroissante)
comparison.cloud(tdm, scale=c(2,.5), random.order=FALSE, colors = c("#6BAED6","#084594"), title.size=1.5, max.words=50, min.freq=3)
Nous pouvons ainsi visualiser dans deux villes différentes ce qui se dit sur un sujet.
Retour à la table des matières
Les nuages de mots précédemment utilisés ont leur limite. En
effet, ils se contentent de juxtaposer des mots et la taille de ces
derniers dépend de leur fréquence d'utilisation.
Drew Conway, dans son article
BUILDING
A BETTER WORD CLOUD, introduit un nouveau type de nuage de mot qui
permet de prendre en compte la fréquence d'apparition des mots mais
également de comparer la fréquence d'utilisation de ces mots par deux
individus.
Ici, nous récupérons 1500 tweets issus des comptes de
deux présidents des Etats-Unis : Barack Obama et Donald Trump. Nous
effectuons la même procédure que précédemment afin d'obtenir un
TermDocumentMatrix.
Ensuite, nous enlevons les mots présents moins de 2 fois dans la colonne de chaque individu. La différence de fréquence d'utilisation des mots est la différence entre un mot tweeté par Barack Obama et un mot tweeté par Donald Trump.
Si cette différence est positive alors Barack Obama utilise plus ce mot que Donald Trump;
Si cette différence est négative alors Donald Trump utilise plus ce mot que Barack Obama;
Si cette différence est nulle alors Barack Obama utilise ce mot autant que Donald Trump.
Pour plus de lisibilité sur le nuage final, nous appliquons une fonction d'espacement des mots.
# Comparaison des mots employés par les deux utilisateurs
ggplot(obama_df, aes(x=freq.dif, y=Spacing)) +
# Mots utilisateur 1
geom_text(aes(size=obama.txt, label=row.names(obama_df),
colour=freq.dif), alpha=0.7, family='Arial') +
# Mots utilisateur 2
geom_text(data=trump_df, aes(x=freq.dif, y=Spacing,
label=row.names(trump_df), size=trump.txt, color=freq.dif),
alpha=0.7, family='Arial') +
# Mots des deux utilisateurs (qui ont la même fréquence)
geom_text(data=both_df, aes(x=freq.dif, y=Spacing,
label=row.names(both_df), size=obama.txt, color=freq.dif),
alpha=0.7, family='Arial') +
# Echelle des mots selon la fréquence
scale_size(range=c(3,11)) +
# Couleur selon qu'on s'écarte de 0 (plus la différence de fréquence des mots est grande)
scale_colour_gradient(low="red3", high="blue3", guide="none") +
scale_x_continuous(breaks=c(min(trump_df$freq.dif), 0, max(obama_df$freq.dif)),
labels=c("Tweeté plus par Trump","Tweeté par les deux","Tweeté plus par Obama")) +
scale_y_continuous(breaks=c(0), labels=c("")) +
labs(x="", y="", size="Fréquence des mots") +
theme_bw() +
labs(#panel.grid.major = theme_blank(),
#panel.grid.minor = theme_blank(),
title="Nuage de mots de Conway, tweets Trump / Obama")
Le premier graphique est
la première étape de construction du nuage de mots de Conway. Nous
observons les mots employés par Barack Obama. En abscisse, la différence
de fréquence des mots par rapport à Donald Trump est représentée. Par
exemple, le mot "senat" a été prononcé par Obama plus de 60 fois par
rapport à Donald Trump. En revanche, le mot "obama care" a été prononcé
autant de fois par les deux individus. La taille du texte représente la
fréquence dans les tweets de Barack Obama : "leaders" a été plus de fois
tweeté que "team".
Voici le nuage de mots de Conway. Sur cette représentation, les mots
tweetés par Barack Obama et Donald Trump apparaissent simultanément. Les
mots situés au milieu du graphique sont autant employés par les deux
individus. Plus on va vers la gauche, plus on observe les mots employés
par Donald Trump et inversement, plus on va vers la droite, plus on
observe les mots employés par Barack Obama.
Retour à la table des matières
Retour à la table des matières
Retour à la table des matières
Retour à la table des matières
Enfin, nous allons utiliser les métadonnées pour tenter de faire
une représentation géographique des tweets. En effet, sur certains
tweets il est possible d'obtenir la géolocalisation (latitude,
longitude).
Ici, nous utilisons la fonction filterStream() qui permet de récupérer en temps réel sur une durée déterminée en secondes (argument timeout) les tweets situés à un endroit précis (argument locations) ou sur un ou plusieurs sujets (argument track). Afin de récupérer dans un dataframe les tweets il faut utiliser la fonction parseTweets(). La localisation des Etats-Unis est "-125,25,-66,50" ("longitude_min,latitude_min,longitude_max,latitude_max").
load("Camara-Canal_files/my_oauth.Rdata")
# Exemple de récupération de tweets pendant 1 minute contenant le mot Obama
filterStream("tweets.json", track = "Obama", timeout = 60, oauth = my_oauth)
tweets.df <- parseTweets("tweets.json", simplify = TRUE)
# Exemple de récupération de tweets émis depuis les Etats-Unis pendant 1 minute
filterStream("tweetsUS.json", locations = c(-125, 25, -66, 50), timeout = 60, oauth = my_oauth)
tweets.df <- parseTweets("tweetsUS.json", verbose = FALSE)
map.data <- map_data("state")
points <- data.frame(x = as.numeric(tweets.df$lon), y = as.numeric(tweets.df$lat))
points <- points[points$y > 25, ]
ggplot(map.data) + geom_map(aes(map_id = region), map = map.data, fill = "white",
color = "grey20", size = 0.25) + expand_limits(x = map.data$long, y = map.data$lat) +
theme(axis.line = element_blank(), axis.text = element_blank(), axis.ticks = element_blank(),
axis.title = element_blank(), panel.background = element_blank(), panel.border = element_blank(),
panel.grid.major = element_blank(), plot.background = element_blank(),
plot.margin = unit(0 * c(-1.5, -1.5, -1.5, -1.5), "lines")) + geom_point(data = points,
aes(x = x, y = y), size = 1, alpha = 1/5, color = "darkblue")
Nous observons que certains Etats émettent plus de tweets que d'autres. En effet, il semble y en avoir plus dans les grandes villes telles que Seattle, San Francisco, Los Angeles, Miami, Chicago, New-York.
Retour à la table des matières
Nous procédons de manière identique pour récupérer les tweets émis dans le monde entier, en spécifiant locations = c(-180, -90, 180, 90).
La Triade ressort très clairement sur cette carte.
Retour à la table des matières
Ici, nous nous intéressons au sexe des utilisateurs. Nous souhaitons déterminer si un individu est un homme ou une femme. Pour ce faire, nous avons récupéré la liste de prénoms féminins et masculins sur Data.gouv pour analyser les noms d'utilisateurs.
Nous récupérons 1000 tweets en français contenant le mot "football" afin de déterminer le sexe des utilisateurs.
# Récupération des tweets et conversion en data.frame
test <- searchTwitter("football", n = 1000, lang = "fr")
test_2 <- twListToDF(test)
# Récupération des noms d'utilisateurs
utilisateur <- test_2$screenName
head(utilisateur)
# Chargement du fichier des prénoms
names <- read.csv("Camara-Canal_files/liste_des_prenoms_2004_a_2012.csv",sep=";")
tryTolower = function(x)
{
# create missing value
y = NA
# tryCatch error
try_error = tryCatch(tolower(x), error=function(e) e)
# if not an error
if (!inherits(try_error, "error"))
y = tolower(x)
# result
return(y)
}
# On enlève la ponctuation, les caractères de contrôle
sentence = gsub("[[:punct:]]", "", utilisateur)
sentence = gsub("[[:cntrl:]]", "", utilisateur)
sentence = gsub('\\d+', '', utilisateur)
# On crée une liste contenant les noms d'utilisateurs
sentence = sapply(utilisateur, tryTolower)
word.list = str_split(sentence, "\\s+")
words = unlist(word.list)
# Création d'un fichier féminin d'un fichier masculin
feminin <- subset(names,names$sexe=="F")
masculin <- subset(names,names$sexe=="M")
# On conserve uniquement les prénoms qui ont plus de trois lettres
feminin_2 <- subset(feminin,nchar(as.character(feminin$prenoms)) > 3)
masculin_2 <- subset(masculin,nchar(as.character(masculin$prenoms)) > 3)
prenoms_feminins <- sapply(feminin_2$prenoms,tryTolower)
prenoms_masculins <- sapply(masculin_2$prenoms,tryTolower)
# On identifie les prénoms féminins
genre_1 <- rep(NA,1000)
for (i in 1:length(prenoms_feminins))
{
for (j in 1:length(words))
{
if (grepl(prenoms_feminins[i],words[j]) == TRUE) genre_1[j] <- "Feminin"
}
}
# On identifie les prénoms masculins
genre_2 <- rep(NA,1000)
for (i in 1:length(prenoms_masculins))
{
for (j in 1:length(words))
{
if (grepl(prenoms_masculins[i],words[j]) == TRUE) genre_2[j] <- "Masculin"
}
}
sexe <- genre_1
# Condition pour gérer les prénoms mixtes et les pseudos qui ont à la fois juxtaposés un prénom masculin et féminin
cond <- genre_1=="Feminin" & genre_2=="Masculin"
# Construction d'une seule liste
masc <- which(genre_2=="Masculin")
sexe[masc] <- "Masculin"
commun <- which(cond==TRUE)
sexe[commun] <- "Mixte"
# Affichage des 100 premiers éléments de la liste
head(sexe,100)
# Récupération du nombre dans chaque catégorie
nb_masc <- count(sexe=="Masculin")[2,2]
nb_fem <- count(sexe=="Feminin")[2,2]
nb_mixte <- count(sexe=="Mixte")[2,2]
nb_NA <- count(sexe=="NA")[2,2]
# Paramètres du graphique
x <- c(nb_masc,nb_fem,nb_mixte,nb_NA)
pourcentage <- round(x/sum(x)*100)
noms <- c("Masculin","Feminin","Mixte","NA")
noms <- paste(noms,pourcentage)
noms <- paste(noms,"%",sep="")
# Graphique
pie(x,labels=noms,col=brewer.pal(7,"Blues"),main="Répartition des utilisateurs par sexe")
On obtient la liste du sexe des utilisateurs. Les individus qui ont pour valeur NA sont soit des utilisateurs qui n'ont pas mis de prénom dans leur nom d'utilisateur soit ce sont des entreprises. Pour ceux qui ont pour valeur NA et les prénoms mixtes, il faut pousser plus loin l'analyse en exploitant le contenu de la description de leur compte Twitter.
Afin de détecter les entreprises, il faut disposer d'un fichier contenant les entreprises que l'on peut récupérer sur le site de l'INSEE.
Retour à la table des matières
Dans ce post, nous avons passé en revue différentes techniques permettant d'analyser les données ouvertes de Twitter : nuages de mots, cartes, clustering... Ce sont des outils qui peuvent être intéressants pour des entreprises afin de connaître leur image auprès des Twittos. En effet, Twitter agit comme du bouche à oreille. Si un utilisateur a aimé un film ou un produit, il va en parler et en informer ses followers.
Nous proposons une application Shiny permettant d'effectuer ces différentes analyses en choisissant vous-même les paramètres et ainsi produire les analyses que vous jugerez pertinentes. Cliquez ici pour y accéder.
http://drewconway.com/zia/2013/3/26/building-a-better-word-cloud
https://sites.google.com/site/miningtwitter/
http://www2.rdatamining.com/uploads/5/7/1/3/57136767/rdatamining-slides-text-mining.pdf