R et Twitter

[This article was first published on Learning Data Science , and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

On va dans ce post, illustrer une utilisation simple des packages twitteR, StreamR, tm qui permettent faire du textmining. En réalité, les deux premiers permettent de récuperer les tweets et de faire des comptages simples et complexes et le dernier permet de faire du textmining; On reviendra plus en détail sur ce dernier dans un prochain billet.

Analyse simple – Twitter :comment récupérer les tweets?

Il est un peu difficile (avec la dernière api de Tweeter) de se connecter pour récupérer les tweets.

Il faut en réalité se connecter avec un compte twitter de développeur à créer sur le site api.twitter.com

Voici le code à adapter pour indiquer à votre ordinateur connecté à votre réseau, comment se connecter sur votre compte développeur.

Les codes consumerKey et consumersecret sont donnés par tweeter et sont personnels.

# download.file(url='http://curl.haxx.se/ca/cacert.pem',
# destfile='cacert.pem') requestURL <-
# 'https://api.twitter.com/oauth/request_token' authURL =
# 'http://api.twitter.com/oauth/authorize' accessURL=
# 'http://api.twitter.com/oauth/access_token' consumerKey =xxxxxx
# consumerSecret =xxxxxxxx myacc <-
# OAuthFactory$new(consumerKey=consumerKey, consumerSecret=consumerSecret,
# requestURL=requestURL, accessURL=accessURL, authURL=authURL)
# myacc$handshake(cainfo = paste0( temp dir() ,
#'/cacert.pem' ) , ssl.verifypeer = FALSE )
# myacc$handshake() registerTwitterOAuth(myacc)

Une fois enrégistré et sauvegardé, on n'a plus besoin dans une autre session R de recommencer la manipulation.

setwd("D:\\PERSO\\Tutoriels\\TwitteR")
load("twitter.Rdata")
registerTwitterOAuth(myacc)

# Récupérer 500 tweets les plus récents de la manif pour
# tous depuis le mois de septembre 2012
manif <- searchTwitter("#lamanifpourtous", n = 500, since = "2012-09-01", 
    cainfo = "cacert.pem")
# C'est une liste qui est créée. On peut récupérer les
# résultats dans un dataframe
# manif.df<-twListToDF(twList=manif) Ou encore de manière
# plus élégante. Pour ceux qui n'ont pas encore pratiqué R,
# cette fonction est très utile dans toutes circonstances.
manif.df <- do.call("rbind", lapply(manif, as.data.frame))
# Le dataframe créé comprend plusieurs variables. On y
# reviendra par la suite. Mais pour accéder au texte
head(manif.df$text)

## [1] "RT @FranceOFrancais: Un véritable Mensonge d'Etat : #Valls trafique les vidéos de la #ManifPourTous \n#lamanifpourtous \nhttps://t.co/z9AOPYS…"  
## [2] "RT @ALC_officiel: #MensongedEtat : #Valls trafique les vidéos de la #ManifPourTous \n#PSmenteur \n#OnLacheRien \n#lamanifpourtous \nhttps://t.c…"
## [3] "C'est impressionnant de voir le nbr de néonazis qui soutiennent la cause de la #LaManifPourTous 0_0 @christineboutin @Frigidebarjot"             
## [4] "@itele un heterophobe ! #MariagaPourTous #lamanifpourtous"                                                                                       
## [5] "RT @FranceOFrancais: Un véritable Mensonge d'Etat : #Valls trafique les vidéos de la #ManifPourTous \n#lamanifpourtous \nhttps://t.co/z9AOPYS…"  
## [6] "RT @ALC_officiel: #MensongedEtat : #Valls trafique les vidéos de la #ManifPourTous \n#PSmenteur \n#OnLacheRien \n#lamanifpourtous \nhttps://t.c…"

Quelques questions :

  • Où tweete t-on le plus?
  • Quels sont les tweets les plus retweetés?
  • Qui twete le plus?
  • Quels sont les mots qui resortent le plus?
  • etc..
# Quand est ce qu'il y a eu le plus de tweets en rapport
# avec lamanif pour tous?
leplusdetweet <- userTimeline("lamanifpourtous", n = 2000, cainfo = "cacert.pem")
system.time(leplus.df <- do.call("rbind", lapply(leplusdetweet, 
    as.data.frame)))

user system elapsed 5.39 0.00 5.43

# Attention : Télécharger 2000 tweets on pris environ 7
# secondes sur en 64 bits avec 8 Go de RAM. On peut donc
# très rapidement arriver à saturation si l'on y prend
# garde.  Date de création du tweet
Cree.le <- leplus.df$created
counts <- table(as.Date(Cree.le))
print(xtable(counts), type = "html")
V1
2013-04-04 171
2013-04-05 249
2013-04-06 10
2013-04-07 46
2013-04-08 79
2013-04-09 90
2013-04-10 55
2013-04-11 114
2013-04-12 113
2013-04-13 40
2013-04-14 56
2013-04-15 68
2013-04-16 186
2013-04-17 239
2013-04-18 122
2013-04-19 92
2013-04-20 40
2013-04-21 173
2013-04-22 57
dates <- as.Date(names(counts))
barplot(counts[counts > 10], col = "sandybrown", las = 2, cex.names = 0.85, 
    main = "Quand a t-on le plus tweeté?")

plot of chunk unnamed-chunk-4

# Attention à la lectue des dates avec R COmme on pouvait
# le prévoir, le point culminant est le jour de la manif du
# 5 avril Qui tweete?
quitweete <- manif.df$screenName
head(quitweete)

[1] “patron_pme” “languillem” “drapsben” “COEURFEULE”
[5] “blantyranha1” “paceo13”

# Qui tweete le plus?
counts = table(manif.df$screenName)
barplot(counts[counts > 5], col = "skyblue", las = 2, cex.names = 0.9, 
    main = "Qui tweete le plus?")

plot of chunk unnamed-chunk-4

# combien de caractère par tweet : Utilisation des fonction
# de base de R
chars_per_tweet = sapply(leplus.df$text, nchar)
# Distribution
hist(chars_per_tweet, main = "Distribution du nombre de mots par tweets", 
    col = "seagreen2")

plot of chunk unnamed-chunk-4

# Ou encore : en observant la densité
densityplot(chars_per_tweet, col = "orange3")

plot of chunk unnamed-chunk-4

# Nombre de mots par tweet Cette fonction crée une liste de
# mots
mots = strsplit(leplus.df$text, " ")
head(mots, 2)

[[1]] [1] “\”#manifpourtous" “#24mars”
[3] “:” “images”
[5] “truquées” “ou”
[7] “pas” “?\”,“
[9] "via” “@MetroFrance.”
[11] “http://t.co/aBjFEYayle

[[2]] [1] “RT” “@MeresVeilleuses:” “Ce”
[4] “soir” “au” “”
[7] “#murdelapaix” “nous” “offrons”
[10] “l'apéro” “au” “600ème”
[13] “follower,” “des” “femmes”
[16] “qui” “vous” “servent”
[19] “un” “apéro” “pour”
[22] “la” “#paix,” “…”

# On crée un vecteur qui contient le nombre de mots par
# tweets
mot_tweet = sapply(mots, length)
# Ditribution
barplot(table(mot_tweet), border = NA, main = "Mots par tweet", 
    cex.main = 1, col = "purple")

plot of chunk unnamed-chunk-4

# Combien de mots clés, mots qui commencent par # et qui
# indiquent dans le monde tweet un mot clé de la
# conversation.
hash = sapply(mots, function(x) length(grep("#", x)))
unclass(table(hash))

hash 0 1 2 3 4 5 6 7 8 245 509 588 380 201 59 13 4 1

# Distribution des tweets retweetés
hist(leplus.df$retweetCount, col = "skyblue2", xlab = "", main = "Tweets retweetés")

plot of chunk unnamed-chunk-4

Relation entre le nombre de caractères par tweet et le nombre de mots par tweet par régression linéaire simple.

plot(df$chars, df$words, xlab = "Nb de caractères par tweets", 
    ylab = "nombre de mots par tweets", main = "", col = "gray20", 
    pch = 20)
# Intervalle de confiance
polygon(c(carac, rev(carac))[is.na(vu) == FALSE], vu[is.na(vu) == 
    FALSE], col = "lavender", border = FALSE)
lines(carac, prev$fit, col = "tomato3", lwd = 3)
lines(carac, prev$fit + 7 * prev$se.fit, col = "thistle4", lty = 2)
lines(carac, prev$fit - 7 * prev$se.fit, col = "thistle4", lty = 2)
lines(carac, prev$fit + 10 * prev$se.fit, col = "darkgoldenrod3", 
    lwd = 2)
lines(carac, prev$fit - 10 * prev$se.fit, col = "darkgoldenrod3", 
    lwd = 2)

plot of chunk unnamed-chunk-6

Textmining

  • Une petite classification

  • Une analyse geographique des tweets selon un thème

  • Une illustration d'un graphique interactif animé à partir des données de stats et de twitter

Il existe via xml, une autre façon d'avoir accès aux données de tweet : Attention si vous êtes en entreprise d'ouvrir les ports qui vont bien. Repris de (donner la source)

mydata.vectors <- character(0)
for (page in c(1:15))
{
 twitter_q <- URLencode('#cahuzac');
twitter_url = paste('http://search.twitter.com/search.atom?q=',
              twitter_q,'&rpp=100&page=', page, sep='');
mydata.xml <- xmlParseDoc(twitter_url, asText=F);
mydata.vector <- xpathSApply(mydata.xml, '//s:entry/s:title',
              xmlValue,namespaces =c('s'='http://www.w3.org/2005/Atom'));
mydata.vectors <- c(mydata.vector, mydata.vectors);
} 

On ne peut charger plus de 1500 tweets de façon générale. L'opération est plutôt rapide.

Quelques fonctions du package tm

# L'outil de base est le corpus
mydata.corpus <- Corpus(VectorSource(mydata.vectors))
# On met tous en miuscules
mydata.corpus <- tm_map(mydata.corpus, tolower)
# On enlève la ponctuation
mydata.corpus <- tm_map(mydata.corpus, removePunctuation)
# On construit un term-document matrix
mydata.dtm <- TermDocumentMatrix(mydata.corpus)
# Que contient un document-term matrix?
mydata.dtm

## A term-document matrix (3952 terms, 1490 documents)
## 
## Non-/sparse entries: 18302/5870178
## Sparsity           : 100%
## Maximal term length: 33 
## Weighting          : term frequency (tf)

# Quels sont les termes les plus fréquents dans
# le document matrix?
b = findFreqTerms(mydata.dtm, lowfreq = 20)
tail(b, 10)

##  [1] "taubira" "tous"    "tout"    "toute"   "une"     "valeurs" "valls"  
##  [8] "via"     "vous"    "yeux"

# On peut chercher les associations entre mots
# calculé par un score d'association
# (corrélation)
a = findAssocs(mydata.dtm, "cahuzac", corlimit = 0.1)
head(a)

## christineboutin         mémoire         donnait         httptc… 
##            0.54            0.54            0.53            0.53 
##           avant         parlait 
##            0.50            0.50

# On enlève les termes rares selon un coéficient
# de rareté
mydata.dtm2 <- removeSparseTerms(mydata.dtm, sparse = 0.95)
# On convertit en data.frame

## [1] 24

## [1] 1490

# Une CAH sur les corpus les plus retouvés
d <- dist(mydata.df.scale, method = "euclidean")
fit <- hclust(d, method = "ward")
plot(fit)
groups <- cutree(fit, k = 5)
rect.hclust(fit, k = 5, border = "mediumaquamarine")

plot of chunk unnamed-chunk-11

cor.mesvars <- cor(t(mydata.df))
row.names(cor.mesvars) = colnames(cor.mesvars)
cor.plot <- levelplot(cor.mesvars, scales = list(x = list(rot = 90)), xlab = "", 
    ylab = "", main = "Corrélation entre mots clés", cex = 1)
print(cor.plot)

plot of chunk unnamed-chunk-11

Avec un peu de cartographie

  • Où tweete t-on le plus dans le monde?
filterStream("tweet_monde.json", locations = c(-180, -90, 180, 
    90), timeout = 20, oauth = myacc)

## Capturing tweets...

## Connection to Twitter stream was closed after 20 seconds with 2586 kB
## received.

tweets.df <- parseTweets("tweet_monde.json", verbose = FALSE)
head(tweets.df$text, 5)

## [1] "Hari ni hujan la horay blah tido puas2"                                                                                                               
## [2] "Just received info that the suspect #2 might be wearing a bomb. Suspect #1 was wearing a bomb when he was killed. #Watertown #Boston"                 
## [3] "Q tl estuvo @mikel_ar94  ayer a la noche con la mantica y el periódico?? Jajajaja"                                                                    
## [4] "@NguyenLiisa hahaha yeah shes dumb. Lol wasnt our fault that we got so close ! Especially because our name is Lisa <ed><U+00A0><U+00BD><ed><U+00B8><U+008A><ed><U+00A0><U+00BD><ed><U+00B8><U+0098>"
## [5] "@tutisiialamiyah bukannya tadi die lagi maen sama si itu2"

# Quels sont les pays d'où vienne tle plus de tweet en
# moyenne
a = table(tweets.df$country)
barplot(a[a > mean(a)], col = "orchid4", las = 2, cex.names = 1, 
    main = "Pays qui ont le plus tweeté?")

plot of chunk unnamed-chunk-12

# Quelle sont les 5 langues les plus utilisées ?
a = table(tweets.df$lang)
ab = sort(a, decreasing = T)[1:5]
slices <- ab
lbls <- c("Anglais", "Espagnol", "Indonésien", "Turque", "Portugais")
pct <- round(slices/sum(slices) * 100)
lbls <- paste(lbls, pct)  # add percents to labels
lbls <- paste(lbls, "%", sep = "")  # ad % to labels
couleur = brewer.pal(n = 5, name = "Set1")
pie(slices, labels = lbls, col = couleur, main = "les 5 langues les plus utilisées", 
    cex = 0.7)

plot of chunk unnamed-chunk-12

On pourrait faire la même chose avec les pays

plot of chunk unnamed-chunk-14

Sur unr carte du monde, cela donne :

points <- data.frame(x = as.numeric(tweets.df$lon), 
    y = as.numeric(tweets.df$lat))
map.data <- map_data("world")
p <- ggplot(map.data) + geom_map(aes(map_id = region), 
    map = map.data, fill = "whitesmoke", 
    color = "grey30", size = 0.2) + 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())
p = p + geom_point(data = points, aes(x = x, 
    y = y), size = 1, alpha = 1/5, color = "indianred2")
p

plot of chunk unnamed-chunk-15

On peut aussi s'intéresser à partir des données de tweeter aux opinions positives (côte de popularité de Francois Hollande et celle de son rival Sarkoy par exemple entre deux dates. Les côtes de popularité sont disponible sur le site d'opinionway

On a constitué des données qui récupéraient des tweets où étaient mentionnés leurs deux noms entre avril 2012 et avril 2013; On définit un corpus de mots positifs et on fait un lien avec le taux de chômage des mois concernés;

l'analyse interactive que nous donne le package googlevis est présentée ci dessous :

# require(GoogleVis)
M <- gvisMotionChart(dt, "key", "date", date.format = "%YW%W")
print(M, "chart")
_Le code pour créer tous les objets de ce post est disponible sur demande_

To leave a comment for the author, please follow the link and comment on their blog: Learning Data Science .

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)