Diagramme en bâtons représentant la part des votes rouges vs bleus

Nombre de votes pour les couleurs

La chaîne de télévision D8 diffuse pour la troisième année consécutive l’émission Nouvelle Star. Si ma mémoire est bonne, je n’avais pas suivi ce programme depuis la saison 2006-2007, mais j’avoue m’être pris au jeu cette année, d’autant plus que la production propose une nouveauté par rapport aux saisons précédentes : les votes par Twitter !

Jeudi dernier, le 12/02, lors du quatrième prime, je me suis diverti avec l’API de Twitter pour récupérer les tweets postés pendant l’émission.

Les résultats de ma petite analyse laissent penser que les votes par SMS et par téléphone pratiqués durant l’émission ne sont pas négligeable, et ne reflètent pas exactement ce qui se dit sur le réseau social Twitter.

Aussi, après un bref rappel du déroulement des primes, ce billet présentera quelques observations réalisées autour des tweets extraits pendant l’émission de jeudi. Une troisième partie s’adressant à ceux désirant récupérer eux-même les tweets et effectuer leur propre analyse, fournira quelques codes R.

1. Déroulement du prime

Jeudi 12 février 2015, il restait au début de l’émission 7 candidats (qui disposent chacun d’un compte Twitter) :

  1. Pauline, 17 ans (@Popymarie) ;
  2. Mathieu, 19 ans (@MatHood) ;
  3. Nelson, 18 ans (@Nelsonblond) ;
  4. Maëva, 18 ans (@Novastone) ;
  5. Martial, 25 ans (@Martialboboy) ;
  6. Micka, 22 ans (@MyKeyCover) ;
  7. Emji, 27 ans, (@Emji).

Ces candidats ont chanté à deux reprise dans la soirée, dans l’ordre indiqué dans la liste ci-dessous.

Deux types de vote

Durant tout l’émission, les téléspectateurs sont invités à voter pour leur candidat préféré, soit en employant les moyens traditionnels à ce type d’émission, à savoir par téléphone ou par SMS, soit en ayant recours à la nouveauté de cette année : le vote via Twitter. Ce nouveau canal a l’avantage pour le téléspectateur d’être gratuit. Le vote par Twitter possède de surcroit une caractéristique particulièrement intéressante : la transparence. En effet, comme les votes sont émis de manière publique, il est possible de récupérer les données et de faire soi-même le décompte à la maison.

À la fin des deux heures d’antenne, les votes sont comptabilisés, et pour les candidats ayant reçu le moins de soutien, l’aventure Nouvelle Star s’arrête.

Parallèlement, les candidats reçoivent des indicateurs de leur performance sous forme d’un signal binaire, après chacune de leurs performances. Ce signal prend la forme d’une couleur : – bleu, il signifie que la performance a plu ; – rouge, il traduit un prestation qui n’a pas plu.

L’indicateur de performance est donné à la fois par le public, et par chacun des membres du jury. Cette année, le jury est composé de :

  1. Élodie Frégé (@elodiefrege) ;
  2. André Manoukian (@andremanou) ;
  3. Yarol Poupaud (@yarolpoupaud) ;
  4. Sinclair (@sinclou).

Les résultats sont annoncés par le présentateur, Benjamin Castaldi (@b_castaldi).

Les votes par Twitter, comment ça marche ?

Pour voter pour un candidat par Twitter, il est nécessaire de faire figurer dans le tweet le hashtag #nsvote et le nom du candidat ou son compte Twitter, sans erreur.

Par exemple, pour voter pour Mathieu :

#nsvote Mathieu

ou encore

#nsvote @MatHood

Le tweet peut aussi contenir d’autres mots :

je vote pour Mathieu #nsvote #nouvellestar !

Si un tweet avec le hashtag #nsvote contient deux prénoms de candidats, le candidat dont le nom est inscrit en premier recevra le vote. Aussi, avec le tweet suivant :

je vote pour Mathieu et Emji #nsvote

Mathieu recevra un vote, mais pas Emji.

De plus, chaque twittos ne peut voter plus de 10 fois pour un candidat.

Plusieurs autres règles existent, elles sont données dans la FAQ de l’émission.

Ces règles visent principalement à écarter les robots. Les twittos ne respectant pas les règles suivantes voient leur vote annulé :

  • avoir un compte ayant été créé le jour du prime ;
  • avoir un profil renseigné ;
  • avoir une photo (différente de l’oeuf proposé par défaut).

Il est aisé de vérifier les deux premiers points de cette liste. Le troisième point en revanche, l’est un peu moins. En effet, avec l’API streaming de Twitter, la date de création et la biographie des comptes pour lesquels on récupère des tweets sont données, mais la présence ou non d’une photo ne l’est pas… Si on souhaite le savoir de manière automatisée, il faut passer par l’API REST. Or, il existe une limite de 180 appels toutes les 15 minutes à cette API. Aussi, au maximum, il est possible d’avoir les informations sur 21600 utilisateurs pendant 2 heures.

Dans les données que j’ai récupérées, il y a 7464 twittos différents. De fait, la vérification de la présence d’une photo est possible à réaliser pendant l’émission, mais pénible. Je n’ai pas vérifié cette règle jeudi soir, il est donc possible qu’il existe quelques votes comptés en trop pour certains candidats dans mes analyses.

2. Quelques résultats

Dans cette section, je vais présenter quelques graphiques et statistiques descriptives de l’émission du 12 février 2015. Pendant la durée de l’émission, j’ai récupéré 40953 tweets.

Les prestations des candidats

Tout au long de l’émission, les téléspectateurs donnent leur ressenti en twittant “#nsbleu” s’ils sont satisfait de la prestation, ou “#nsrouge” s’ils ne le sont pas. Jeudi, j’ai récupéré 13209 tweets exprimant un vote de couleur, dont 4899 rouges et 8310 bleus.

Graphique de l'évolution des votes bleus et rouges au cours de l'émission

Je suis impressionné par ce résultat. Je ne m’attendais pas à voir quelque chose d’aussi net. J’aimerais bien savoir à quoi correspondent les absences de vote entre chaque pic. Autant les longues absences de votes correspondent à la publicité, mais qu’en est-il des autres creux, comme celui qu’on observe entre la prestation de Pauline et celle de Mathieu ?

  • Est-ce pendant que le jury délibère ?
  • Est-ce pendant le moment où une petite capsule vidéo est diffusée au sujet du prochain candidat ?

Je pencherais pour la première solution, mais peut-être que mon agrégation par minute est mauvaise. En essayant de regrouper par 30 secondes, on ne voit plus rien. Il faut que je mette la main sur une télévision et que je note spécifiquement tous les moments clés de l’émission (actuellement, sur le streaming, je crois qu’il y a un petit décalage avec ce qui est diffusé sur un téléviseur). J’aimerais savoir s’il y a un changement de tendance une fois que le jury a donné son avis, entre le moment où la couleur de chaque membre du jury est donnée, et celle où l’avis du public est révélé.

Dans tous les cas, pendant l’émission, on peut connaître l’état des votes entre deux instants. On peut regarder la tendance générale, tous candidats confondus, pour savoir si dans l’ensemble, les gens ont pris du plaisir à regarder l’émission.

Diagramme en bâtons représentant la part des votes rouges vs bleus

On le constate sur ce graphique, ceux qui votent le font en majorité pour défendre un candidat. La semaine prochaine, je regarderai peut-être ceux qui parlent de la nouvelle star au sens large sur Twitter : en parcourant quelques tweets à la main, je me suis rendu compte qu’il y a quelques statuts qui parlent de l’émission de manière négative, sans pour autant prendre part aux votes.

En restant sur l’idée des sentiments, sans pour autant en faire une réelle analyse, on peut se pencher sur les mots les plus fréquents associés aux tweets qui concernent des votes de couleur. L’orthographe des mots laisse à désirer dans les tableaux qui suivent : j’ai coupé les terminaisons des mots, pour conserver des racines, afin d’éviter de retrouver “aimer”, “aimé”, etc.

Les mots associés aux votes rouges sont reportés dans le tableau ci-dessous.

Racine Fréquence
non 234
chanson 206
trop 185
aim 131
faux 114
voix 112
tout 108
fait 100
chant 96
plus 89
bien 72
meme 68
massacr 65
vraiment 62
bof 61
quand 58
chanter 57
comm 56
nul 55
peu 54
encor 51
soir 50
toujour 50

Concernant les mots les plus associés aux votes bleus, ils sont reportés dans le tableau ci-dessous.

Racine Fréquence
bien 441
voix 293
chanson 287
aim 210
ador 203
tres 193
prestat 183
tout 175
magnifiqu 169
bell 165
bravo 160
trop 159
chant 147
comm 141
fait 138
plus 135
meme 129
super 104
meilleur 101
bon 99
etait 98
just 96
vraiment 96
soir 94
toujour 91
mal 90
parfait 89
beau 88
quand 87
interpret 85
lt3 84
merci 82
mieux 79
enfin 77
foi 77
encor 75
top 71
oui 69
frisson 66
vote 62
joli 59
petit 59
tellement 59
star 56
superb 56
emot 55
prime 54
chanter 53
aussi 52
peu 50

Sans grosse surprise, on voit que les votes rouges comportent quelques mots à connotation négative, comme “faux”, “massacr”, “bof”, “nul”. A contrario, on obtient “bien”, “ador”, “magnifiqu”, “bell”, “super”, etc. dans les mots associés aux votes bleus.

Pour le fun, un nuage de mots sur lequel figurent les termes présents au moins 40 fois dans les tweets de votes rouges ou bleus. La taile des mots est proportionnelle à la fréquence d’apparition.

Nuage de mots des termes apparus au moins 40 fois dans les tweets de votes rouges ou bleus

Le classement des candidats : les SMS ont la part belle

Un des objectifs de la Nouvelle Star, est de la trouver, cette nouvelle star. Le classement des candidats en fonction des votes accordés par le public permet de désigner qui est éliminé à chaque émission.

Les résultats que j’obtiens via les votes par Twitter donnent une issue différente de celle ayant eu lieu jeudi dernier. Ce résultat me surprend. Jeudi, Maëva et Nelson sont les deux candidats qui ont été éliminés. Les résultats que j’obtiens sur Twitter sont différents : Nelson occupe la 4e position sur les votes Twitter !

Ce constat est intéressant. D’où provient la différence ?

Une erreur dans mon code, voici ce qu’a été ma première réaction. Cette hypothèse n’est pas à balayer du revers de la main, mais je suis plutôt confiant dans mes calculs. En revanche, je n’ai aucune certitude sur la manière dont les votes sont comptés. Est-ce qu’un tweet “#NSVoteMicka” accorde un vote à Micka ? De plus, je ne jouis pas du partenariat avec Twitter, contrairement à FermantleMedia (producteur de la nouvelle star), ce qui complique un peu les choses.

Une seconde hypothèse beaucoup plus probable est de se dire que la part de gens votant par SMS/téléphone mobile surpasse celle des votants par Twitter. Le téléspectateur est confronté à un arbitrage entre un vote payant mais très simple d’utilisation, ou un vote gratuit mais un peu moins simple pour qui n’a jamais utilisé de compte Twitter. De plus, le vote par Twitter est public, donc moins discret. Si j’avais à voter pour un candidat, je n’aurais pas envie de partager mon vote avec mes (rares) followers. Si cette hypothèse tient, la production ne doit pas regretter son choix de ne pas avoir axé les votes uniquement par Twitter !

Diagramme en bâtons des résultats des votes sur Twitter pour chaque candidat

Ce qui est frappant dans ce graphique, c’est la position largement dominante d’Emji. Jeudi, le premier candidat appelé était Mathieu, et non pas Emji : un effet de suspens supplémentaire pour le spectateur ?

Une autre manière de visualiser les votes est de regarder l’évolution tout au long de l’émission. On peut voir qu’au début de l’émission, Mathieu est devant Emji. Il faut attendre le passage de cette dernière, peu après 22h, pour qu’elle passe devant. Son compteur de voix s’envole après son second passage.

Évolution du cumul des votes pour chaque candidat au fil du temps

Évolution du cumul des votes pour chaque candidat au fil du temps

Enfin, un aperçu du nombre de votes par minute pour chaque candidat permet de visualiser deux effets nets :

  1. après le passage d’un participant, les twittos se mobilisent ;
  2. juste avant la fin de l’émission, les retardataires votent une dernière fois.

Diagramme en bâton du nombre de votes par minute pour chaque candidat

Un aperçu de la localisation des twittos

Une petite portion de tweets possède des informations relatives aux coordonnées (longitude, latitude). Je n’ai pas cherché à géocoder les positions déclarées par les twittos (travail trop important pour un résultat sûrement mauvais, du fait de la nature déclarative du champ de position). Aussi, je m’appuie sur seulement 661 tweets pour produire la carte qui suit. C’est l’occasion de réutiliser du code développé avec @freakonometrics lors d’un précédent billet, au sujet de l’estimation de densité par la méthode du noyau.

Les tweets géolocalisés sont émis principalement depuis la région parisienne, mais aussi à Bruxelles et à Marseille.

Carte montrant la densité des tweets géotaggés

Quelques caractéristiques des votants

Nombre de votes par twittos

Chaque votant a le droit de s’exprimer jusqu’à 10 fois pour chaque candidat, pour lui apporter un soutien. Qu’en est-il dans les données ?

Dans l’ensemble, on peut noter qu’il n’y a que très peu de personnes à dépasser les 10 votes (quelques outliers accordent 56 votes à Nelson, 40 à Emji, etc.). Dans la majorité des cas de personnes votant plus de 10 fois, le dépassement n’est que très faible, comme le montre le graphique ci-dessous.

Boxplot du nombre de votes parmi ceux qui dépassent la limite de 10 votes

En ramenant à présent à 10 les valeurs excédentaires, regardons le nombre de votes moyen que chaque candidat a reçu par Twitter.

Candidat Nombre de votes moyen
Emji 2.23
Mathieu 2.14
Martial 2.31
Nelson 2.77
Pauline 2.92
Micka 1.85
Maeva 1.82

À première vue, on peut se dire que les supporters de Pauline votent en moyenne plus que ceux de Maëva, mais cette différence de moyenne n’est pas statistiquement différente de zéro (avec un risque de 5‰). Sans présenter les résultats du test de Tukey, on peut s’en convaincre avec le gaphique ci-dessous.

Boxplot du nombre de votes moyens par Twittos pour chaque candidat

Ce que l’on peut voir, par contre, c’est que la limite des 10 votes par twittos par candidat est bien loin d’être atteinte… À la place des candidats, j’irais faire un tour sur Twitter pour booster les troupes… 🙂

Source des tweets

Par quel biais les votants expriment-ils leur soutien à un candidat sur Twitter ? Les tweets récoltés fournissent une information relative au canal utilisé lors de la création d’un tweet. Le graphique ci-dessous révèle que les votants, dans près d’un tiers des cas, utilisent un iPhone. Vient ensuite l’utilisation de Twitter sur le site web, talonnée par Twitter pour Android. À eux trois, ces moyens représentent 78% des tweets émis par les votants.

Diagramme en bâtons de la source d'émission des tweets pour les comptes votants

Récence des comptes

Je me suis demandé si les personnes votant pour un candidat via Twitter depuis plusieurs années, ou si elles ont créé un compte spécialement à cet effet. Une manière d’avoir une idée de la réponse est de réaliser une estimation de la distribution de la date de création des comptes.

Sur le graphique ci-après, la taille des barres noires correspond au nombre de comptes créés durant un intervalle d’un mois (l’axe des ordonnées n’est pas présent) ; la ligne rouge correspond à une estimation de la densité, dont les valeurs sont visibles sur l’axe des ordonnées ; la barre bleue correspond à la date du premier prime, le 22 janvier 2015.

On peut voir que de nombreux comptes ont été créés dans le mois précédant le premier prime, et juste après celui-ci. La courbe de densité montre cependant que de nombreux votants possédaient déjà un compte avant l’émission.

Graphique de l'estimation de la densité de la date de création des comptes des votants

Si on décompose la base en fonction des candidats pour lesquels les twittos votent, on peut voir que les supporters de Maëva et de Pauline sont nombreux à avoir créé un compte juste avant l’émission. Hasard ? 🙂

Graphique de l'estimation de la densité de la date de création des comptes des votants, par candidat

3. Récupération des Tweets avec l’API Twitter

Cette partie un poil plus technique s’adresse au lecteur intéressé de récupérer lui aussi les tweets, en passant par l’API streaming, et en utilisant le logiciel R.

Je considère le lecteur familier avec le logiciel R. De même, je suppose le lecteur familier avec les APIs Twitter et prêt à communiquer avec en utilisant R, en s’appuyant sur les méthodes fournies par le package twitteR. Si ce dernier point n’est pas vérifié, le créateur du package, Jeff Gentry, décrit pas-à-pas la procédure à suivre pour mettre en relation R et une API Twitter dans une vignette.

Tracking de mots

Durant les deux heures d’émission, je laisse le lien avec l’API Twitter ouvert, pour récolter des tweets contenant certains hashtags :

hashtags <- c("#NSBleu", "#NSRouge", "#NSVote")

Pour récupérer les tweets, je m’appuie sur la fonction filterStream() du package streamR. Ils sont automatiquement enregistrés dans un fichier au format JSON.

library(streamR)
# timeout : nombre de secondes pendant lesquelles laisser la liaison ouverte
#           si 0, la connexion ne se ferme pas.
filterStream(file.name = "ns_votes_12_02_2015.json",
             oauth=twitCred, verbose = TRUE, timeout = 0,
             track = hashtags)

où l’objet twitCred permet d’être authentifié aurpès de l’API via le protocole Oauth (il correspond à l’objet my_oauth tel que décrit sur la page d’introduction du package streamR).

Pour charger les tweets dans la session R, sous forme d’un tableau de données, il suffit d’utiliser la fonction parseTweets :

tweets_df <- parseTweets("ns_votes_12_02_2015.json")

Respect des règles de D8

Une fois les tweets chargés dans la mémoire de la session R, il est nécessaire de faire du tri, pour supprimer les tweets non conformes aux règles (il pourrait être intéressant de se concentrer justement sur ces tweets…), ou qui ne nous intéressent pas.

D’abord, on récupère les identifiants de gazouillis auxquels le compte “nsvoteerreur” indique un non respect des règles. Cela permet de retirer rapidement quelques “mauvais” statuts.

# Les tweets emis par le robot de la NS
tweets_robot <- tweets_df[which(tweets_df$screen_name == "nsvoteerreur"),]

# Quelques tweets non comptabilises
ind_non_compt <- which(tweets_df$id_str %in% tweets_robot$in_reply_to_status_id_str)

# Retirer les tweets emis par le robot de la NS
tweets_df <- tweets_df[-which(tweets_df$screen_name == "nsvoteerreur"),]
# Ainsi que quelques-uns non comptabilisés
tweets_df <- tweets_df[-ind_non_compt,]

On se charge ensuite de retirer les tweets émis par des comptes trop récents, ou pour lesquels la biographie est absente. Pour ce faire, on s’appuie sur une fonction qui va permettre de transformer la date fournie par l’API dans un format lisible par R :

library(stringR)
library(lubridate)
# Permet de retourner la date de création des tweets dans un format lisible par R
# @x : data.frame contenant les tweets
# @variable : nom de la variable de date
convert_date <- function(x, variable){
  mois_annee <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
  annee <- str_sub(x[, variable], -4)
  mois <- sprintf("%02s", match(str_sub(x[, variable], 5, 7), mois_annee))
  jour <- str_sub(x[, variable], 9, 10)
  hms <- str_sub(x[, variable], 12, 19)
  tz <- str_sub(x[, variable], 21, 25)
  res <- str_c(str_c(annee, mois, jour, sep = "-"), hms, tz, sep = " ")
  res <- ymd_hms(res)
  with_tz(res, "Europe/Paris")
}# End of convert_date()

On applique cette fonction à la variable de création du compte (et à celle de l’émission du tweet, dans le même temps) :

# Date de creation du tweet
tweets_df$date_tweet <- convert_date(tweets_df, "created_at")

# Date de creation du compte twitter
tweets_df$user_created_at <- convert_date(tweets_df, "user_created_at")

Il est alors aisé de retirer les tweets émis en dehors du temps de vote :

# On ne conserve que les tweets entre 21h et 23h07
ind <- which(tweets_df$date_tweet >= with_tz(ymd_hms(str_c(date_emission,
                                                           " 21:00:00+01")), "Europe/Paris") & 
               tweets_df$date_tweet <= with_tz(ymd_hms(str_c(date_emission, " 23:07:00+01")),
                                               "Europe/Paris"))
tweets_df <- tweets_df[ind,]

On peut alors retirer les statuts des twittos ayant créé leur compte le jour du prime ou pour lesquels la biographie est absente :

# On retire les tweets emis par des personnes ayant cree leur compte le jour meme
# ou qui n'ont pas de biographie
# Mais on les stock dans un autre data.frame
ind_rm <- which(as.Date(strptime(tweets_df$user_created_at, "%F")) == date_emission |
                  is.na(tweets_df$description))

if(any(ind_rm)){
  tweets_df_votes <- tweets_df[-ind_rm,]
}

Votes Bleu/Rouge

Sur la totalité des données

Pour travailler sur les votes, on n’exclut pas les tweets des personnes avec un compte trop récent (du moins j’en ai l’impression…). On se cale donc sur le tableau de donnéees tweets_df$text.

Dans un premier temps, on repère les tweets qui contiennent le hashtag “#nsbleu” et ceux qui contiennent le hashtag “#nsrouge”, en faisant fi de la casse :

# Les indices des tweets #nsbleu
ind_bleu <- grep(x = tweets_df$text, pattern = "#nsbleu", ignore.case = TRUE)
# Les indices des tweets #nsrouge
ind_rouge <- grep(x = tweets_df$text, pattern = "#nsrouge", ignore.case = TRUE)

On ajoute une variable indicatrice, qui prend la valeur TRUE quand le tweet est un vote de couleur, et FALSE sinon.

# Pour chaque tweet, indique s'il s'agit d'un vote de couleur ou non
tweets_df$vote <- FALSE
tweets_df$vote[unique(c(ind_bleu, ind_rouge))] <- TRUE

# Pourcentage des tweets qui concernent des votes couleur
mean(tweets_df$vote)

Plus important, on créé les variables nsbleu et nsrouge qui prennent la valeur 1 pour les gazouillis votant bleu et rouge respectivement, et 0 s’ils ne concernent pas un vote de couleur.

# Pour chaque couleur, rajout d'une variable indiquant s'il s'agit d'un vote de la couleur
tweets_df$nsbleu <- tweets_df$nsrouge <- 0
tweets_df$nsbleu[ind_bleu] <- 1
tweets_df$nsrouge[ind_rouge] <- 1

Si le vote contient à la fois “#nsrouge” et “#nsbleu”, on ne le considère pas comme un vote :

# On indique que les tweets qui contiennent les deux ne sont pas valides
ind_br <- which(tweets_df$nsbleu == 1 & tweets_df$nsrouge == 1)
tweets_df$vote[ind_br] <- FALSE
tweets_df$nsbleu[ind_br] <- tweets_df$nsrouge[ind_br] <- 0

Pour pouvoir visualiser le nombre de votes par minute, selon leur couleur, il est nécessaire de procéder à une agrégation des données :

# Creation d'une variable pour agreger les resultats par minute
tweets_df$hm <- str_c(hour(tweets_df$date_tweet), minute(tweets_df$date_tweet), sep = "_")

# Agregation des votes de couleur par minutes
votes_couleur_minutes <- aggregate(tweets_df[, c("nsbleu", "nsrouge")],
                           by = list(temps = tweets_df$hm), FUN = sum)

L’étape précédente a nécessité la réécriture de la variable de date, qui n’est plus reconnue comme telle par R (il doit exister un moyen d’agréger les dates, mais je n’en ai pas connaissance pour le moment…). On recode alors la date dans le bon format :

# Remise sous forme de date
votes_couleur_minutes <- within(votes_couleur_minutes,{
  date <- ymd_hms(str_c(date_emission, " ", word(temps, sep = "_", 1), ":",
                                word(temps, sep = "_", 2), ":00"), tz = "Europe/Paris")
})

Pour créer le graphique, il faut transformer légèrement le tableau de données :

# Preparation des data.frames pour ggplot2
prep_ggplot2_votes_couleur <- function(df){
  df <- melt(df, id.vars = c("temps", "date"), value.name = "nb", variable.name = "couleur")
  arrange(df, date)
}# End of prep_ggplot2_votes_couleur()

votes_couleur_minutes <- prep_ggplot2_votes_couleur(votes_couleur_minutes)

Enfin, on peut créer une fonction pour réaliser le graphique :

# @df : tableau de données
votes_couleur_ag_plot <- function(df){
  ggplot(data = df, aes(x = date, y = nb, group = couleur, col = couleur)) +
    geom_line() + geom_point() +
    scale_x_datetime(breaks = date_breaks("10 min"),
                     labels = date_format("%H:%M")) +
    xlab("") + ylab("") +
    scale_colour_manual(values = c("blue", "red"))  
}# End of votes_couleur_ag_plot()

p1 <- votes_couleur_ag_plot(votes_couleur_minutes) +
  ggtitle("Nombre de votes par minute pour les couleurs") +
  coord_cartesian(xlim = c(ymd_hms(str_c(date_emission, " 21:00:00 +01")),
                           ymd_hms(str_c(date_emission, " 23:10:00 +01"))))

p1

Entre deux instants

Pendant l’émission, on peut s’amuser à obtenir la tendance rouge/bleu avant que le présentateur la dévoile à l’écran. Voici une petite fonction qui permet de le faire.

# @df : tableau de données
# @debut : date à partir de laquelle considérer les tweets, au format POSIX
# @fin : date à partir de laquelle on ne considère plus les tweets, au format POSIX
#        Si omise, les tweets sont pris en comte jusqu'à la fin de la base
couleur_instants_plot <- function(df, debut, fin){
  if(!missing(fin)){
    ind <- which(df$date_tweet >= debut & df$date_tweet <= fin)

  }else{
    ind <- which(df$date_tweet >= debut)
    fin <- max(df$date_tweet)
  }
  titre <- str_c(str_c(hour(debut), minute(debut), sep = ":"),
                 str_c(hour(fin), minute(fin), sep = ":"), sep = " - ")
  df <- df[ind,]
  
  votes_tmp <- data.frame(couleur = c("rouge", "bleu"), nb = c(sum(df$nsrouge), sum(df$nsbleu)))
  votes_tmp$pct <- round(votes_tmp$nb / sum(votes_tmp$nb), 2)
  print(votes_tmp)
  
  ggplot(data = votes_tmp, aes(x = couleur, y = nb, fill = couleur)) + geom_bar(stat = "identity") +
    scale_fill_manual(values = c("blue", "red")) + xlab("") + ylab("Nombre de Tweets") +
    ggtitle(titre)
}# End of couleur_instants_plot()

Un exemple d’utilisation sur la première prestation de Micka :

couleur_instants_plot(tweets_df, debut = ymd_hms("2015-02-12 21:54:00", tz = "Europe/Paris"),
                      fin = ymd_hms("2015-02-12 21:56:00", tz = "Europe/Paris"))

Votes pour les candidats

Pour connaître les résultats des votes, il faut travailler avec le tableau de données tweets_df_votes, dans lequel les tweets ne respectant pas les règles ont été retirés.

Dans un premier temps, on effectue un peu de nettoyage sur les gazouillis (on retire les smileys, les caractères de passage à la ligne, etc.).

# Un peu de nettoyage du texte dans un premier temps
tweets_df_votes$text_2 <- tweets_df_votes$text
# Pour Maëva, il faut qu'on retire le tréma
tweets_df_votes$text_2 <- gsub("ë", "e", tweets_df_votes$text_2)
tweets_df_votes$text_2 <- gsub("Ë", "E", tweets_df_votes$text_2)
tweets_df_votes$text_2 <- iconv(tweets_df_votes$text_2, to='UTF-8-MAC', sub='byte')
tweets_df_votes$text_2 <- gsub("[[:blank:]]|\r|!|\\?|\\.", " ", tweets_df_votes$text_2)

On s’assure de ne travailler qu’avec des tweets qui contiennent le hashtag “#nsvote”

# Les tweets qui contiennent le #hashtag #nsvote
ind <- grep(pattern="#NSVote", x=tweets_df_votes$text, ignore.case = TRUE)

Pour qu’un vote compte, il faut qu’il mentionne le nom du candidat, ou son compte Twitter.

noms_candidats <- c("Emji", "Maeva", "Martial", "Mathieu", "Micka", "Nelson", "Pauline")
comptes_candidats <- c("@Emji", "@Novastone", "@Martialboboy", "@MatHood",
                       "@MyKeyCover", "@Nelsonblond", "@Popymarie")

candidats <- data.frame(nom = noms_candidats, compte = comptes_candidats)
candidats_2 <- c(noms_candidats, comptes_candidats)

On créé une fonction pour extraire le nom du candidat mentionné en premier dans le tweet :

# Retourne la premiere occurence du nom d'un candidat dans un tweet
# @tweet : un tweet
vote_candidat <- function(tweet){
  mots <- str_split(tweet, pattern = " ")[[1]]
  ind <- which(tolower(mots) %in% tolower(candidats_2))
  if(length(ind)>0){
    tolower(mots[min(ind)])
  }else{
    NA
  }  
}# End of vote_candidat()

Cette fonction est appliquée à chaque tweet :

tweets_df_votes$candidat <- NA
tweets_df_votes$candidat[ind] <- unlist(lapply(tweets_df_votes$text_2[ind], vote_candidat))

Il reste à remplacer les noms de compte par le prénom du candidat :

ind_mention <- which(str_detect(tweets_df_votes$candidat[ind], "@"))
tweets_df_votes$candidat[ind][ind_mention] <- tolower(candidats$nom[match(tweets_df_votes$candidat[ind][ind_mention],
                                                                          tolower(candidats$compte))])

On créé alors un tableau de données contenant chaque tweet concernant un vote, et indiquant à qui ce vote doit être attribué.

votes <- data.frame(candidat = tweets_df_votes$candidat[ind],
                    screen_name = tweets_df_votes$screen_name[ind],
                    user_id_str = tweets_df_votes$user_id_str[ind],
                    text = tweets_df_votes$text[ind])
votes$nb <- 1
a_retirer <- which(is.na(votes$candidat))
if(length(a_retirer > 0)) votes <- votes[-a_retirer,]

Chaque twittos ne peut voter plus de 10 fois pour un candidat. Si le nombre de vote excède 10, on ramène la valeur à 10.

votes <- aggregate(votes[, c("nb")],
                   by = list(candidat = votes$candidat,
                             screen_name = votes$screen_name,
                             user_id_str = votes$user_id_str), FUN = sum)
# Si un twittos a voté plus de 10 fois, il ne faut pas comptabiliser les
# votes au-dessus du 10e
votes$x[which(votes$x > 10)] <- 10
votes <- aggregate(votes[, "x"], by = list(candidat = votes$candidat), FUN = sum)
votes <- arrange(votes, desc(x))
colnames(votes)[which(colnames(votes) == "x")] <- "nb"
# Pourcentages
votes$pct <- round(votes$nb / sum(votes$nb, na.rm=TRUE), 2)
# Etape supplémentaire pour avoir le prénom avec une majuscule au début
votes$candidat <- str_c(toupper(str_sub(votes$candidat, 1, 1)), str_sub(votes$candidat, 2))
votes

La fonction qui suit permet d’afficher les résultats des votes sous forme d’un diagramme en bâton.

# Afficher le graphique des votes
# @df : tableau de données
plot_resultat_votes <- function(df){
  df$candidat <- factor(df$candidat, as.character(df$candidat))
  ggplot(data = df, aes(x = candidat, y = nb, fill = candidat)) +
    geom_bar(stat = "identity") + xlab("") + ylab("") +
    ggtitle("Nombre de votes par candidat (via Twitter)")
}# End of plot_resultat_votes()

plot_resultat_votes(votes)


2 thoughts on “Qui va gagner la Nouvelle Star ? À vos votes Twitter !

  1. Très intéressant ! C’est fou comme on peut s’amuser avec l’API twitter !
    En tout cas, c’est un très bon article, très complet. Et pour couronner le tout, on a même une explication technique sur les scripts utilisés à la fin!
    Je m’en vais donc découvrir la suite de ton blog !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Time limit is exhausted. Please reload CAPTCHA.