Objectifs

Evaluer la non-acceptabilité du public, les actions juridiques en cours et prévues contre les compteurs communiquants, voire la complexité technique d’installation des compteurs.
Identifier les communes concernées, afin d’anticiper d’éventuels freins au déploiement.

Synthèse des tweets par un nuage de mots clés

Les tweets ont été collectés à travers les mots clés : “compteurs linky” OU “compteurs intelligents” OU “gazpar” (API Tweeter).
La librairie Wordcloud de R permet de générer le nuage ci-dessous assez facilement :

Analyse selon 3 axes : sentiments, actions juridiques, et complexité technique

Hypothèses : nous utilisons les dictionnaires ci-dessous, construits sur la base d’observations des tweets des mois passés.

## Dictionnaires
sentiment <- c("nuisible","stop","mauvaise foi","danger","empêcher","espion","big brother","bigbro","refus","arrêt","agress","agass","question","problème","risque","arnaque","manifest","mobilisé","mobilisation","nocif","mouchard","santé","radiatif","cancer","boycot","malfaisant","magnétique","non merci","contre","passoire")
juridique <- c("tribunal","droit","élu","ordonnance","moratoire","délibération","délibéré","arrêté","motion","courrier","administr","liberté de choix","majorité","unanime","maire","collectif","ordonner","interdi","commune","ministère","juge","pétition","juridique","bataille")
technique <- c("mal install","diffic","complex","compliqu","techniq","lourd","echec","échou","impossible","long","incapable","défaut","bug")
len_sent <- length(sentiment)
len_jur <- length(juridique)
len_tech <- length(technique)

Ensuite, le calcul du nombre de matchs pour chaque tweet / et pour chaque dictionnaire permet d’aboutir aux graphes ci-dessous :

Analyse de l’influence : un tweet négatif est retweeté 4 à 5 fois plus qu’un tweet neutre !

En effet, la vue ci-dessous montre que les tweets neutres sont retweetés 4 fois en moyenne, alors que les tweets négatifs près de 20 fois.

tweetsDF2$Impact_Negatif <- (tweetsDF2$nb_sentiment_match+tweetsDF2$nb_juridique_match+tweetsDF2$nb_technique_match)
##plot(tweetsDF2$Impact_Negatif, tweetsDF2$retweetCount)
tapply(tweetsDF2$retweetCount,tweetsDF2$Impact_Negatif,mean) ## En moyenne un tweet négatif est retweeté 4 à 5 fois plus qu'un tweet neutre !
##         0         1         2         3         4 
##  4.406061 17.869565 28.924051  3.000000  3.000000

Localisation des tweets sur la carte de France, par niveau “d’hostilité”

Comme expliqué dans la légende, la couleur illustre si le tweet est positif ou négatif.
De plus, la taille du point (entre 0 et 8) est proportionnelle à l’influence du tweet : c’est à dire le nombre de retweets (entre 0 et 80).

## Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=France&zoom=6&size=640x640&scale=2&maptype=terrain&language=en-EN&sensor=false
## Information from URL : http://maps.googleapis.com/maps/api/geocode/json?address=France&sensor=false

A venir

Utilisation des librairies TOPIC et OPINION mining (au lieu des 3 dictionnaires faits à la main).
Nuance des avis négatifs en analysant les autres tweets postés par les personnes concernées : s’agit-il de critiques significatives, ou les profils sont-ils d’éternels râleurs ? (ie négatifs sur tous les sujets)

Annexe : code

##doInstall <- FALSE
##toInstall <- c("maps", "ggplot2","tm","wordcloud","twitteR","ROAuth","googleVis","ggmap")
##if(doInstall){install.packages(toInstall, repos = "http://cran.us.r-project.org")}
##lapply(toInstall, library, character.only = TRUE)

##consumer_key <- 
##consumer_secret <- 
##access_token <- 
##access_secret <- 
##setup_twitter_oauth(consumer_key, consumer_secret, access_token, access_secret)

# Download "cacert.pem" file
##download.file(url="http://curl.haxx.se/ca/cacert.pem",destfile="cacert.pem")

#create an object "cred" that will save the authenticated object that we can use for later sessions
##cred <- OAuthFactory$new(consumerKey= ,
                         ##consumerSecret= ,
                         ##requestURL='https://api.twitter.com/oauth/request_token',
                         ##accessURL='https://api.twitter.com/oauth/access_token',
                         ##authURL='https://api.twitter.com/oauth/authorize')

##cred$handshake(cainfo="cacert.pem")

#save for later use for Windows
##save(cred, file="twitter authentication.Rdata")
##load("twitter authentication.Rdata")

## Les lignes ci-dessous ont effectivement permi de collecter les données
##tweets <- searchTwitter("compteurs linky", n=500, lang="fr") # top 1000 tweets that contain search term (max is less than 300!)
##tweetsDFA <- twListToDF(tweets) # more info about tweets.
##tweets <- searchTwitter("compteurs intelligents", n=500, lang="fr") # top 1000 tweets that contain search term (max is less than 300!)
##tweetsDFB <- twListToDF(tweets) # more info about tweets.
##tweets <- searchTwitter("gazpar", n=500, lang="fr") # top 1000 tweets that contain search term (max is less than 300!)
##tweetsDFC <- twListToDF(tweets) # more info about tweets.

##tweetsDF2 <- unique(rbind(tweetsDFA,tweetsDFB,tweetsDFC))
##save(tweetsDF2, file="tweetsDF2.Rdata")
##load(file="tweetsDF2.Rdata")

##tweets_corpus <- Corpus(VectorSource(tweetsDF2$text))
##tweets_corpus <- tm_map(tweets_corpus, removePunctuation) # ici cela va supprimer automatiquement tous les caractères de ponctuation
##tweets_corpus <- tm_map(tweets_corpus, removeWords, stopwords("fr")) # ici cela va supprimer automatiquement une bonne partie des mots français "basiques", tels que "le", "la", etc. mais il en manque ! Il manque par exemple "les"...
##tweets_corpus <- tm_map(tweets_corpus, stripWhitespace) # ici cela va supprimer automatiquement tous les espaces vides
  ##toSpace = content_transformer( function(x, pattern) gsub(pattern," ",x) )
##tweets_corpus <- tm_map(tweets_corpus, toSpace, "https*")
##wordcloud(tweets_corpus, max.words = 20, colors = brewer.pal(8, "Dark2"))

## Dictionnaires
sentiment <- c("nuisible","stop","mauvaise foi","danger","empêcher","espion","big brother","bigbro","refus","arrêt","agress","agass","question","problème","risque","arnaque","manifest","mobilisé","mobilisation","nocif","mouchard","santé","radiatif","cancer","boycot","malfaisant","magnétique","non merci","contre","passoire")
juridique <- c("tribunal","droit","élu","ordonnance","moratoire","délibération","délibéré","arrêté","motion","courrier","administr","liberté de choix","majorité","unanime","maire","collectif","ordonner","interdi","commune","ministère","juge","pétition","juridique","bataille")
technique <- c("mal install","diffic","complex","compliqu","techniq","lourd","echec","échou","impossible","long","incapable","défaut","bug")
len_sent <- length(sentiment)
len_jur <- length(juridique)
len_tech <- length(technique)

## Analyse

for (i in 1:length(tweetsDF2$text)) {
  tweet_i <- tweetsDF2$text[i]
  
  nb_sentiment_match <- 0 ## calculons le nombre de matchs
  for (j in 1:len_sent) {if (grepl(sentiment[j],tweet_i)) {nb_sentiment_match <- nb_sentiment_match+1}}
  tweetsDF2$nb_sentiment_match[i] <- nb_sentiment_match
  
  nb_juridique_match <- 0 ## calculons le nombre de matchs
  for (j in 1:len_jur) {if (grepl(juridique[j],tweet_i)) {nb_juridique_match <- nb_juridique_match+1}}
  tweetsDF2$nb_juridique_match[i] <- nb_juridique_match
  
  nb_technique_match <- 0 ## calculons le nombre de matchs
  for (j in 1:len_tech) {if (grepl(technique[j],tweet_i)) {nb_technique_match <- nb_technique_match+1}}
  tweetsDF2$nb_technique_match[i] <- nb_technique_match
  
}

## Affichage
score_sentiment <- c(sum(tweetsDF2$nb_sentiment_match==0),sum(tweetsDF2$nb_sentiment_match==1),sum(tweetsDF2$nb_sentiment_match>1))
names(score_sentiment) <- c("Neutre","Négatif","Très Négatif")
score_juridique <- c(sum(tweetsDF2$nb_juridique_match==0),sum(tweetsDF2$nb_juridique_match==1),sum(tweetsDF2$nb_juridique_match>1))
names(score_juridique) <- c("Neutre","Négatif","Très Négatif")
score_technique <- c(sum(tweetsDF2$nb_technique_match==0),sum(tweetsDF2$nb_technique_match==1),sum(tweetsDF2$nb_technique_match>1))
names(score_technique) <- c("Neutre","Négatif","Très Négatif")

##par(mfrow=c(3,1))
##barplot(score_sentiment, xlab="",ylab="Nombre de tweets", main="Sentiment exprimé sur Twitter sur les compteurs Linky")
##barplot(score_juridique, xlab="",ylab="Nombre de tweets", main = "Zoom sur le vocabulaire d'actions juridique")
##barplot(score_technique, xlab="",ylab="Nombre de tweets", main = "Zoom sur le vocabulaire de complexité technique")

##userInfo <- lookupUsers(tweetsDF2$screenName)  # Batch lookup of user info
##userFrame <- twListToDF(userInfo)  # Convert to a nice dF
##locatedUsers <- !is.na(userFrame$location)  # Keep only users with location info

##locations <- geocode(userFrame$location[locatedUsers])  ## Use amazing API to guess
## approximate lat/lon from textual location data.
## with(locations, plot(lon, lat))

##userFrame$lon <- locations$lon
##userFrame$lat <- locations$lat

##lon <- function(name){
##  userFrame$lon[which(userFrame$screenName==name)]
##}
##lat <- function(name){
##  userFrame$lat[which(userFrame$screenName==name)]
##}
##location <- function(name){
##  userFrame$location[which(userFrame$screenName==name)]
##}

##for (i in 1:dim(tweetsDF2)[1]) {
  ##tweetsDF2$lon[i] <- lon(tweetsDF2$screenName[i])
  ##tweetsDF2$lat[i] <- lat(tweetsDF2$screenName[i])
  ##if(tweetsDF2$Impact_Negatif[i]==1){tweetsDF2$color[i] <- "orange"}
  ##if(tweetsDF2$Impact_Negatif[i]>1){tweetsDF2$color[i] <- "red"}
##}

##data_select <- cbind(tweetsDF2$screenName,tweetsDF2$text,tweetsDF2$Impact_Negatif,tweetsDF2$retweetCount,tweetsDF2$color,tweetsDF2$lon,tweetsDF2$lat,tweetsDF2$location)
##colnames(data_select) <- c("nom","texte","hostilite","nb_retweets","couleur","lon","lat","location")
##data_select <- as.data.frame(data_select)
##data_select$lon <- as.numeric(as.character(data_select$lon))
##data_select$lat <- as.numeric(as.character(data_select$lat))
##data_select$hostilite <- as.numeric(as.character(data_select$hostilite))
##data_select$nb_retweets <- as.numeric(as.character(data_select$nb_retweets))

##data_select_clean <- data_select[which(!is.na(data_select$lon)),]
##dim(data_select_clean)

## France <- get_map("France", zoom=6)  # Grab France map
##ggmap(France)

##p <- ggmap(France)
##p <- p + geom_point(data=data_select, aes(x=lon, y=lat))
##p <- p + geom_point(data=data_select, aes(size=nb_retweets/10))
##p <- p + geom_point(data=data_select, aes(colour = hostilite))
##p + scale_colour_gradient(limits=c(0, 4), low="green", high="red")