Twitter est un réseau social populaire qui a été créé le 21 mars 2006 où les utilisateurs peuvent partager de courts messages de type SMS appelés tweets. Les hommes politiques, les sportifs l’utilisent pour donner la primeur de leur actualité, leurs décisions, leurs actions à venir, les journalistes commentent les événements en direct, les entreprises font la promotions des produits et interagissent avec les clients. Au 5 mars 2017, Twitter comptait 313 millions d’utilisateurs actifs par mois avec 500 millions de tweets envoyés par jour et était disponible en plus de 40 langues.
L’analyse des tweets s’inscrit dans le cadre de l’analyse textuelle (text mining), chaque document est un texte rédigé. Afin d’effectuer ce projet Open Data, nous commençons d’abord par une analyse statistique descriptive.
Le package twitteR nous permet d’accéder aux données du site Twitter : [https://twitter.com]. Ces données sont constituées de mots et de phrases déposées quotidiennement par des millions d’utilisateurs dans le monde, ainsi que de méta-données sur les utilisateurs de ce réseau social.
Il faut au préalable disposer soi-même d’un compte Twitter et créer une application Twitter [https://apps.twitter.com] qui nous permettra d’effectuer des analyses en connectant notre console R à Twitter en utilisant l’API Twitter.
setup_twitter_oauth(consumer_key, consumer_secret, access_token,access_secret)
## [1] "Using direct authentication"
Dans un premier temps, nous nous concentrons sur les tweets qui traitent de l’annonce du mariage du prince Harry et de sa financée Meghan Markle.
Nous allons étudier les auteurs et le contenu de ces tweets.
La fonction searchTwitter permet de charger des tweets qui contiennent le mot clé “prince Harry Meghan”. On limite le nombre de messages extraits à 500.
tweets_prince = searchTwitter("prince Harry Meghan", lang="en", since='2017-11-27', n=500)
Nous pouvons établir une liste des 10 auteurs les plus actifs avec le nombre de messages envoyés.
#comptage du nombre de message par auteurs
comptage <- table(tweets.df$screenName)
#tri décroissant
comptage <- sort(comptage,decreasing=TRUE)
#10 premiers auteurs les plus actifs
print(comptage[1:10])
##
## Daily_Express MizpahJohnson ReportUK TheTruth24UK Tooo_Know
## 8 6 6 6 6
## Wedding_Agent cbc_diff sliaisonmonick ToooKnow azheykhunweper
## 6 4 4 4 3
Nous pouvons identifier les pseudo des auteurs ayant envoyé 4 messages ou plus.
print(length(unique(tweets.df$screenName)))
## [1] 406
barplot(comptage [comptage >= 4], las = 2,cex.names=0.7, col="darkolivegreen4")
Finalement, la concentration des auteurs est assez forte. Par rapport au nombre de messages (n=500), le nombre unique d’auteurs l’est également (406) et Daily_Express est le premier auteur qui envoie plus de messages.
Ce premier classement donne un premier point de vue sur l’activité des auteurs. Mais il peut être biaisé par le fait que certains messages sont en réalité de simples retweets. Pour identifier les auteurs de messages “originaux”, qui amènent une réelle valeur ajoutée dans les échanges, nous essayons d’isoler les messages qui ne sont pas des retweets, puis nous comptabilisons de nouveau les auteurs.
Nous identifions tout d’abord les messages qui ne sont pas des retweets.
#liste des messages originaux
id_originaux <- which(!tweets.df$isRetweet)
#nombre de messages originaux
print(length(id_originaux))
## [1] 318
#Ils sont au nombre 291 (sur les 500 messages initiaux).
#comptage du nombre de message par auteurs
comptage_bis <- table(tweets.df$screenName[id_originaux]) #tri décroissant
comptage_bis <- sort(comptage_bis,decreasing=TRUE)
#graphique de ceux qui ont plus de 4 (inclus) messages
barplot(comptage_bis [comptage_bis >= 4], las = 2,cex.names=0.7, col = "lightgoldenrod3")
Les auteurs ayant rédigé 4 messages originaux ou plus sont plus rares (5), alors qu’ils étaient 9 si l’on comptabilisait les retweets. Certains, apparemment très actifs, ont disparu de la circulation.
Les internautes retweetent les messages lorsqu’ils en ont apprécié la teneur. Parmi les messages qui sont des retweets, nous essayerons d’isoler les 2 messages qui sont les plus populaires.
## screenName id retweetCount
## 90 stydiagissette 9.585896e+17 116108
## 92 flukez123 9.585881e+17 116108
## [1] RT @BarackObama: Michelle and I are delighted to congratulate Prince Harry and Meghan Markle on their engagement. We wish you a lifetime of…
## [2] RT @BarackObama: Michelle and I are delighted to congratulate Prince Harry and Meghan Markle on their engagement. We wish you a lifetime of…
## 404 Levels: .@NaughtyNiceRob: Kylie Jenner wants that epidural; Meghan Markle & Prince Harry will replace Will & Kate at Common… https://t.co/blAc6sx0Gk ...
Nous avons 2 messages avec des auteurs et des identifiants distincts qui sont répétés chacun 116108 fois et qui correspondent au même texte. On se rend qu’il s’agit du même message que les internautes aiment marteler visiblement. Donc, il nous faut enlever les messages en doublon. Nous nous servons de la fonction duplicated() qui permet de les identifier.
## [1] RT @BarackObama: Michelle and I are delighted to congratulate Prince Harry and Meghan Markle on their engagement. We wish you a lifetime of…
## [2] RT @ClarenceHouse: The Prince of Wales is delighted to announce the engagement of Prince Harry to Ms. Meghan Markle. https://t.co/zdaHR4mcY6
## 404 Levels: .@NaughtyNiceRob: Kylie Jenner wants that epidural; Meghan Markle & Prince Harry will replace Will & Kate at Common… https://t.co/blAc6sx0Gk ...
## [1] 116108 32987
Nous avons bien deux messages distincts maintenant, qui sont répétés respectivement 116108 et 32987 fois.
Nous pouvons aussi représenter le nombre d’occurrence de 15 premiers tweets avec leur ID.
Ou encore afficher l’histogramme des fréquences du nombre de retweets.
Nous souhaitons dans un premier temps analyser les références aux thèmes (#) et aux auteurs (@) qui apparaissent dans les messages.
Un premier nettoyage est nécessaire pour éliminer les éléments qui peuvent engendrer du bruit et des doublons, puisqu’il y a souvent des répétitions dans les messages, ensuite on retire les sauts de ligne, les URL, les espaces en trop et les accents.
# éliminer les doublons
dfUnique <- tweets.df[!duplicated(tweets.df$text),]
print(nrow(dfUnique))
messages <- dfUnique$text
print(length(messages))
print(messages[22])
msgClean <- gsub("\n"," ",messages)
msgClean <- gsub('http\\S+\\s*',"",msgClean)
msgClean <- gsub("\\s+"," ",msgClean)
msgClean <- gsub("[\\]","",msgClean)
msgClean <- gsub("\\s*$","",msgClean)
#msgClean <- tolower(msgClean)
msgClean <- gsub("[éèê]","e",msgClean)
msgClean <- gsub("[àâ]","a",msgClean)
msgClean <- gsub("[ùû]","u",msgClean)
msgClean <-gsub("rt ", "", msgClean)
msgClean <-msgClean[!duplicated(msgClean)]
print(length(msgClean))
Les auteurs sont identifiés par le caractère “@” (screenname). Ils apparaissent dans les messages parce qu’ils sont retweetés, ou parce qu’ils sont cités nommément. Dans ce qui suit, nous allons les comptabiliser. On peut trouver les 10 individus les plus fréquents.
## liste_individus
## @YouTube @ReportUK @Independent @ClarenceHouse
## 10 6 4 3
## @Daily_Express @ELLEUK @BazaarUK @Bridesmagazine
## 3 3 2 2
## @Celebrity_VIP1 @ELLEmagazine
## 2 2
Après avoir agrégé les textes de tous les individus, nous convertissons cette liste en corpus qui contient 500 documents (un document par individu), puis appliquons la fonction TermDocumentMatrix qui permet de compter les occurrences de chaque mot en prenant soin d’enlever les stopwords (les stopwords sont des mots très courants dans les phrases et vides de sens tels que les articles ou encore les prépositions).
# construire la matrice des fréquences:
# On compte le nombre d'occurrences par mots
dtm = TermDocumentMatrix(corpus, control = list(tolower = TRUE, stopwords = word))
dtm.matrix = as.matrix(dtm)
v <- sort(rowSums(dtm.matrix), decreasing = TRUE)
d <- data.frame(word = names(v), freq = v)
barplot(d[1:25,]$freq, las = 2, names.arg = d[1:25,]$word,
col ="lightblue", main ="Mots les plus fréquents",
ylab = "Fréquences")
L’analyse de sentiments est une branche de l’analyse textuelle qui essaye de définir les opinions, sentiments et attitudes présentes dans un texte. Nous utilisons ** NRC Emotion Lexicon** qui est un lexique de mots et de leurs associations avec huit émotions (colère, peur, anticipation, confiance, surprise, tristesse, joie et dégoût) et deux sentiments (négatifs et positifs). Tous les lexiques incluant des entrées pour des mots anglais peuvent être utilisés pour analyser des textes anglais, des traductions automatiques des entrées du lexique de l’association de mots sont disponibles dans 40 autres langues, y compris le français, l’arabe, le chinois et l’espagnol.
## [1] "peur" "anticipation" "surprise" "positif"
## [5] "tristesse" "colère" "négatif" "dégoût"
## [9] "joie" "confiance"
Les tweets concernant l’annonce du mariage de prince Harry et sa fiancée Meghan Markle sont majoritairement positifs.
Maintenant nous allons effectuer une Classification Ascendante Hiérarchique afin d’observer si nous pouvons faire des regroupements en classes. Pour ce faire, nous récupérons toujours 1000 tweets mentionnant le prince Harry et sa fiancée.
Le dendrogramme au-dessus met en évidence un regroupement en k = 5 classes. Nous observons que ce regroupement est plutôt cohérent :
Ensuite, nous allons utiliser les tweets mentionnant #Metoo pour créer une cartographie interactive avec la fonction leaflet() qui permet de réaliser des cartes dynamiques tout en codant en R. Sur cette carte, nous pouvons localiser les membres qui ont utilisé le hashtag #Metoo et il est possible de zoomer et de se déplacer sur la carte, les cercles sont cliquables.
#------------------------#
# Visualization: leaflet #
#------------------------#
# Set colours
pal <- colorNumeric(palette = c("#ffe6e6", "#ff8080", "#ff0000"), domain = c(0, 100))
# Plot user locations with color of locations reflecting number of followers
leaflet(userFrame_final, width = "100%") %>%
addProviderTiles("CartoDB.DarkMatter") %>%
addCircleMarkers(~lng,
~lat,
color = ~pal(followersCount),
radius = 1.5)
#------------------------#
# Visualization: ggplot2 #
#------------------------#
# Download, unzip and import shapefiles from Natural Earth webpage
#temp <- tempfile()
#download.file("http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_0_countries.zip", temp, mode = "w")
#unzip(temp)
world_shp <- readShapeSpatial("ne_50m_admin_0_countries.shp", proj4string = CRS("+proj=longlat +ellps=WGS84"))
#unlink(temp)
# Remove Antarctica
world_shp <- subset(world_shp, NAME != "Antarctica")
# Plot user locations
ggplot() +
geom_polygon(data = world_shp, aes(x = long, y = lat, group = group)) +
geom_point(data = userFrame_final, aes(x = lng, y = lat), size = 1.2, color = "red") +
labs(x = "", y = "") +
theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank(),
panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank()) +
coord_equal()
Sur la carte, chaque point rouge représente un tweet, nous observons que les États-Unis comptent le plus de tweets, suivi par l’Europe.
On souhaite prédire l’appartenance politique d’un utilisateur de Twitter à un parti grâce à l’analyse de ses tweets et plus précisément grâce à l’analyse de la fréquence des mots qu’il utilise. Nous allons considérer les 4 grands partis français : la France insoumise, la République en marche, les Républicains et le Front national.
Nous récupérons tout d’abord les tweets (et les retweets) effectués par les comptes Twitter des partis et des personnes suivants :
la France insousmise | la République en marche | les Républicains | le Front national |
---|---|---|---|
Compte officiel de la France insoumise | Compte officiel de la République en marche | Compte officiel des Républicains | Compte officiel du Front national |
Jean-Luc Mélenchon | Emmanuel Macron | Laurent Wauquiez | Marine LePen |
Alexis Corbière | Edouard Philippe | Alain Juppé | Florian Philippot |
Eric Coquerel | Christophe Castaner | Valérie Pécresse | Steeve Briois |
François Ruffin | Mounir Mahjoubi | Valérie Boyer | Gilbert Collard |
Comme la fréquence des mots des tweets peuvent être différents d’une actualité à une autre, nous ne retenons que les tweets d’une période assez courte. Ici nous conservons les tweets effectués entre le 1 novembre 2017 et le 1 février 2018.
Nous décidons d’enlever les accents des mots (“donné” est transformé en “donne”), de supprimer les “RT”, les “@”, les hashtags, la ponctuation, les nombres et les espaces en trop.
FI.clean <- clean.text(FI.df$text)
Jean.clean <- clean.text(Jean.df$text)
Francois.clean <- clean.text(Francois.df$text)
Alexis.clean <- clean.text(Alexis.df$text)
Eric.clean <- clean.text(Eric.df$text)
EM.clean <- clean.text(EM.df$text)
Emmanuel.clean <- clean.text(Emmanuel.df$text)
Edouard.clean <- clean.text(Edouard.df$text)
Christophe.clean <- clean.text(Christophe.df$text)
Mounir.clean <- clean.text(Mounir.df$text)
LR.clean <- clean.text(LR.df$text)
Laurent.clean <- clean.text(Laurent.df$text)
Alain.clean <- clean.text(Alain.df$text)
Valerie_P.clean <- clean.text(Valerie_P.df$text)
Valerie_B.clean <- clean.text(Valerie_B.df$text)
FN.clean <- clean.text(FN.df$text)
Marine.clean <- clean.text(Marine.df$text)
Florian.clean <- clean.text(Florian.df$text)
Steeve.clean <- clean.text(Steeve.df$text)
Gilbert.clean <- clean.text(Gilbert.df$text)
Nous concaténons ensuite les tweets des membres d’un même parti.
FI.all <-c(FI.clean, Jean.clean,Francois.clean,Alexis.clean,Eric.clean)
length(FI.all)
EM.all <- c(EM.clean,Emmanuel.clean,Edouard.clean,Christophe.clean,
Mounir.clean)
LR.all <- c(LR.clean, Laurent.clean, Alain.clean, Valerie_P.clean, Valerie_B.clean )
FN.all <- c(FN.clean, Marine.clean, Florian.clean, Steeve.clean, Gilbert.clean)
Touslestext <- c(FI.all, EM.all, LR.all, FN.all)
length(FI.all)
length(EM.all)
length(LR.all)
length(FN.all)
length(Touslestext)
Ensuite nous faisons un découpage de chaque concaténation de tweets en 10 groupes afin d’obtenir plus d’observations.
# Couper la liste des tweets de chaque parti en n sous-listes aléatoirement
n=10
FISplit<- split(FI.all, sample(rep(1:n, length.out = length(FI.all))))
EMSplit<- split(EM.all, sample(rep(1:n, length.out = length(EM.all))))
LRSplit <- split(LR.all, sample(rep(1:n, length.out = length(LR.all))))
FNSplit <- split(FN.all, sample(rep(1:n, length.out = length(FN.all))))
length(FISplit)
#FISplit[1]
Les tweets de chaque groupe sont ensuite agrégés.
# Aggréger les tweets d'un même groupe de tweets
FIGroup <- lapply(FISplit , function(x) paste(x, collapse = " "))
EMGroup <- lapply(EMSplit , function(x) paste(x, collapse = " "))
LRGroup <- lapply(LRSplit , function(x) paste(x, collapse = " "))
FNGroup <- lapply(FNSplit , function(x) paste(x, collapse = " "))
all <- c(FIGroup, EMGroup, LRGroup, FNGroup)
FIGroup[1]
length(FIGroup) #10
length(all) # 40
save(all, file="all_tweet_prediction.RData")
Nous construisons ensuite le corpus de mots en supprimant les mots très courants de la langue française et vides de sens tels que les articles ou encore les prépositions. Nous obtenons ensuite une matrice, les lignes sont les groupes de tweets et les colonnes le nombre d’occurrences pour chaque mot. Nous transformons cette matrice pour obtenir la fréquence des mots, autrement dit le nombre d’occurrences divisé par le nombre total d’un groupe de tweets donné.
n=10
# Créer la matrice de fréquence de mots
dtm <- DocumentTermMatrix(corpus)
#inspect(dtm)
m <- as.matrix(dtm)
nbr_rowMots <- apply(m,1,sum)
tableFreq <- sweep(m,1,nbr_rowMots,"/")
#tableFreq[1:6,1:8]
dim(tableFreq)
# Vérifier si les sommes de toutes les lignes sont 1
#rowSums(tableFreq)
parti <- as.factor(c(rep("FI",n),rep("EM",n), rep("LR",n), rep("FN",n)))
length(parti)
tableLabel = data.frame(parti, tableFreq)
tableLabel[1:6,1:8]
abord | abusif | accentue | acceptable | accepte | acces | accompagne | accompagnee | accord | accorder |
---|---|---|---|---|---|---|---|---|---|
3 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 |
2 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 3 | 0 |
2 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 2 | 0 |
2 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 3 | 0 |
0 | 1 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 3 | 1 | 0 | 1 | 0 |
1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Afin de visualiser l’appartenance en 4 classes distinctes, nous faisons une analyse en composantes principales du tableau de données.
library(FactoMineR)
res <- PCA(as.data.frame(tableLabel), quali.sup=1, graph=FALSE, scale.unit = TRUE, ncp = 10) # original data in input
par(mfrow= c(1,3))
plot(res,choix="ind", axes = c(1,2), cex=1.5,title="", habillage = 1, label="none", invisible = "quali")
plot(res,choix="ind", axes = c(1,3), cex=1.5,title="", habillage = 1,label="none")
plot(res,choix="ind", axes = c(2,3), cex=1.5,title="", habillage = 1, label="none")
Sur les 3 premiers plans factoriels, on constate bien une séparation en 4 classes disjointes.
Pour réduire le nombre de varibale, nous effectuons le classifieur forêt aléatoire en regardant la variable importance et choisissons 300 mots les plus importants pour chaque partie politique, puis nous ne gardons que des mots en commun, cela nous permt de passer de 10973 mots à 648.
rf_all <- randomForest(parti ~., data = tableLabel, importance = TRUE)
save(rf_all, file="rf_all.RData")
rfImp <- rf_all$importance
rfImpEM <-rfImp[, 1]
rfImpFI <-rfImp[, 2]
rfImpFN <-rfImp[, 3]
rfImpLR <-rfImp[, 4]
rfImpSortEM <- sort(rfImpEM, decreasing=TRUE, index.return=TRUE)
rfImpSortFI <- sort(rfImpFI, decreasing=TRUE, index.return=TRUE)
rfImpSortFN <- sort(rfImpFN, decreasing=TRUE, index.return=TRUE)
rfImpSortLR <- sort(rfImpLR, decreasing=TRUE, index.return=TRUE)
nMots=300
#print(names(rfImpSortEM$x[1:nMots]))
# Prendre la réuninon des mots les plus importants pour chaque parti
nomVar = c(names(rfImpSortEM$x[1:nMots]),names(rfImpSortFI$x[1:nMots]), names(rfImpSortFN$x[1:nMots]), names(rfImpSortLR$x[1:nMots]) )
nomVar <-unique(nomVar)
#nomVar
length(nomVar)
Pour vérifier si chaque parti politique est séparé des autres sur les trois premiers plans factoriels après la réduction du nombre de variables, nous effectuons une seconde ACP.
tableFreq2 <- tableLabel[, which(names(tableLabel) %in% nomVar)]
dim(tableFreq2)
## [1] 40 659
#colSums(tableFreq2)
tableLabel2 <- data.frame(parti, tableFreq2)
#tableLabel2[1:6,1:8]
res2 <- PCA(as.data.frame(tableLabel2), quali.sup=1, graph=FALSE, scale.unit = TRUE, ncp = 10) # original data in input
par(mfrow= c(1,3))
plot(res2,choix="ind", axes = c(1,2), cex=1.5,title="", habillage = 1, label="none")
plot(res2,choix="ind", axes = c(1,3), cex=1.5,title="", habillage = 1,label="none")
plot(res2,choix="ind", axes = c(2,3), cex=1.5,title="", habillage = 1, label="none")
Il est évident que chaque groupe est bien séparé, nous allons donc ensuite construire une forêt aléatoire avec seulement les mots sélectionnés.
dim(tableLabel)
x = tableLabel[, which(names(tableLabel) %in% nomVar) ]
dim(x)
#names(x)
# Réordonner les colonnes
#x = x[, c(nomVar, setdiff(colnames(x), nomVar))]
#colnames(x)
rf1 <- randomForest(x =x, y = tableLabel[, which(names(tableLabel) %in% "parti") ], importance = TRUE)
rf1
Pour créer la table de données de test, nous récupérons les 40 tweets des comptes suivants et les nettoyer comme pour les comptes d’apprentissage:
la France insoumise | la République en marche | les Républicains | le Front national |
---|---|---|---|
Loïc Prudhomme | François de Rugy | Nicolas Sarkozy | Louis Aliot |
Caroline FIAT | Cédric Villani | Jean-François | Nicolas BayVerified |
Michel Larive | Bruno Le Maire | Eric Ciotti | Bruno Bilde |
Bastien Lachaud | Gérard Collomb | Damien Abad | Sébastien ChenuVerified |
Adrien Quatennens | Gérald DARMANIN | Julien Aubert | Ludovic PAJOT |
… | … | … | … |
ntweet=1500
data.test <- data.frame()
noms_classif <- nomVar
for( user in all.test$pseudo) {
print(user)
# On récupère 200 tweets pour être sûr d'en avoir au moins 100 qui ne sont pas des RT
tweets = userTimeline(user, n=ntweet, includeRts = TRUE)
# On récupère le texte des tweets
some_txt = sapply(tweets,function(x) x$getText())
# On nettoie les tweets
some_txt = clean.text(some_txt)
p=length(some_txt)
# On garde les p premiers tweets
some_txt = some_txt[1:p]
# On les colle ensemble pour n'avoir qu'un groupe
some_txt = paste(some_txt,collapse=" ")
# On supprime les stop words et on génère la table des fréquences
some_txt = removeWords(some_txt,stopwords("french"))
corpus = Corpus(VectorSource(some_txt))
tdm = TermDocumentMatrix(corpus)
tdm = as.matrix(tdm)
noms = row.names(tdm)
tdm = as.data.frame(t(tdm))
nbr_ColMots <- apply(as.matrix(tdm),1,sum)
tableFreq <- sweep(tdm,1,nbr_ColMots,"/")
tdm = tableFreq
# On crée la matrice ne contenant que les mots utilisés dans la classification
tmp = c()
for (i in noms_classif){
ind = which(noms==i)
if (length(ind)==0){
tmp = cbind(tmp,rep(0,length(tdm[,1])))
}
else
tmp = cbind(tmp,tdm[,ind])
}
names(tmp) = noms_classif
tmp <- data.frame(as.list(tmp))
tdm = tmp
print(tdm[,1:5])
data.test <- rbind(data.test, tdm)
}
data.test <- data.frame(all.test, data.test)
save(data.test, file="datatest.RData")
load("datatest.RData")
pred = predict(rf1,newdata=data.test[, -c(1,2)])
erreur <- sum(pred!=data.test[, 2])/length(data.test[, 2])
erreur
La prédiction par forêt aléatoire nous donne un taux d’erreur 5%.
Nous avons vu qu’il est possible de prédire l’appartenance politique d’un compte Twitter avec une bonne précision si l’utilisateur est un membre d’un parti. Si le compte n’est pas celui d’une personne politique, la précision est moins bonne. Ceci est dû au fait que nous n’avons pris que des comptes d’hommes et de femmes politiques pour l’ensemble d’apprentissage.
De plus, notre façon d’obtenir les données d’apprentissage n’est pas très automatique, puisque l’on rentre manuellement un compte et son parti associé.
Notre analyse textuelle ne prend pas en compte les mots dans leur contexte et leur sens. Il serait intéressant de prendre en compte le moment où le tweet a été fait. De plus, au lieu de se limiter à l’analyse des mots des tweets on pourrait penser à l’avenir à considérer la liste des abonnements qu’un utilisateur possède.