Eurovision 2019 – prédictions

Sur le même modèle que l’année dernière (et, nous l’espérons, avec autant de succès !), nous allons tenter de faire nos prédictions pour l’Eurovision 2019, avec toujours un modèle basé sur les statistiques des vidéos publiées sur Youtube (la liste des vidéos en lice cette année est ici).

Les données

Rappel : nous utilisons les informations disponibles sur les vidéos Youtube : nombre de vues, nombre de “Like” et nombre de “Dislike”. Nous récupérons ces informations grâce au package R tuber, qui permet d’aller faire des requêtes par l’API de Youtube et ainsi de récupérer pour chacune des vidéos d’une playlist les informations nécessaires pour le modèle. Ces informations sont ensuite complétées (pour les années 2016, 2017 et 2018) avec le nombre de points obtenus et le rang du classement final.

Par rapport à l’année dernière, on dispose donc d’une année supplémentaire pour l’apprentissage du modèle (pour rappel, les modalités de calcul des points ont changé en 2016, donc on ne peut pas facilement utiliser des éditions antérieures).

Le modèle

L’objectif principal est d’estimer le score que chaque pays va avoir, afin de pouvoir construire le classement final. La méthode utilisée est toujours la régression linéaire sur les variables disponibles (nombre de vues, nombre de “Likes”, nombre de “Dislikes”)

Pour le modèle utilisant uniquement les données 2016 et 2017, calculé l’année dernière, on rappelle que le nombre de vues ne joue pas significativement, le nombre de Likes de façon très mineure et le nombre de Dislikes très nettement, avec un lien positif : plus il y a de pouces baissés, plus le score est important. Ce résultat atypique peut s’expliquer par le fait que la vidéo ukrainienne en 2016, gagnante, a plus de 40 000 pouces baissés.

(Mise à jour : une première version de ce post contenait des erreurs sur le second modèle) Le modèle intégrant les données 2018 (prises quelques semaines avant la finale) en plus change légèrement. Il accorde moins de valeur au nombre de Dislikes (cela peut s’expliquer par le fait que la chanson russe en 2018 avait un nombre de pouces baissés très important, mais n’a pas accédé à la finale, donc n’a pas obtenu un résultat très bon), mais associe désormais positivement le nombre de vues et le score (ce qui n’était pas le cas avant, étonnement).

Ce modèle, construit à partir de plus de données, est celui privilégié ; on comparera tout de même les résultats obtenus par les deux modèles à la fin de cet article !

Les résultats

Voici les prédictions obtenues, en utilisant le modèle comprenant les données de 2016 à 2018 et appliqué aux données Youtube 2019 :

Le grand gagnant serait Malte. Ils ne sont pas dans les favoris des bookmakers : voir ici, par exemple, ou plus largement avec les données des paris ici : à la date d’extraction des données, le 30 avril, Malte était classée 8ème.

Voici la vidéo proposée par Malte pour l’Eurovision 2019 (dont l’artiste Michela Pace illustre cette publication) :

Les Pays-Bas sont seconds dans notre modèle. Ce sont eux les grands favoris pour l’instant, avec “Arcade” :

Et pour la France ? 10ème selon notre modèle, 11ème selon les bookmakers, nous ne serons pas a priori les Rois de la compétition :

Mais, quand on sait que la vidéo de Bilal sur sa chaîne Youtube personnelle enregistre presque 6 millions de vues, peut-on penser qu’il y a un biais à ce niveau-là ? À suivre…

Mise à jour au 7 mai : le modèle avec les nouvelles données Youtube donne des résultats identiques :

Et avec l’autre modèle ?

En utilisant le modèle comprenant les données de 2016 et 2017 uniquement (et donc, sans 2018), on obtient les résultats suivants, avec, en bleu, les pays pour lesquels le score prédit aurait été plus fort, et en rouge ceux pour qui il aurait été plus faible :

Ce modèle conduit à favoriser les Pays-Bas, et renvoie Malte bien plus bas dans le classement ; mais il se base fortement sur les Dislikes, ce qui n’avait pas été pertinent en 2018… À suivre également !

Ranking places with Google to create maps

Today we’re going to use the googleway R package, which allows their user to do requests to the GoogleMaps Places API. The goal is to create maps of specific places (restaurants, museums, etc.) with information from Google Maps rankings (number of stars given by other people). I already discussed this in french here to rank swimming pools in Paris. Let’s start by loading the three libraries I’m going to use : googleway, leaflet to create animated maps, and RColorBrewer for color ranges.

library(googleway)
library(leaflet)
library(RColorBrewer)

First things first. To do API request to Google, we need an API key ; you can ask for one here. We’ll use this key for the rest of the program, so let’s declare a global variable :

api_key <- "YourKeyHereIWontGiveYouMine"

Retrieving Google Data

We’re going to use the google_places function to get a list of places matching a description, called research in my program (for instance : “Restaurant, Paris, France”). The output are multiple, and I’m going to store the place ID and the rating. I’ll also store the research token ; that’ll be explained later.

gmaps_request <- google_places(search_string = research, language = language, key = api_key)
  gmaps_data <- gmaps_request$results
  
  place_id <- gmaps_data$place_id
  rating <- gmaps_data$rating
  
  token <- gmaps_request$next_page_token

This function returns up to 20 places associated to the research by Google. If you want more than 20, you need to use the token previously stored in order to ask the Google Places API to give you the next results, by tweaking the function this way :

gmaps_request <- google_places(search_string = research, language = language, key = api_key, page_token = token)

There are tow caveats to this function. Firstly, the token can be NULL. In this case, there isn’t any further research results you can get. This happens automatically as soon as you reach 60 results. Secondly, the API needs time to refresh the token research (see here) ; that’s why we’re going to make R wait a few seconds, using Sys.sleep(time) between our requests. Our complete function is therefore :

gmaps_request <- google_places(search_string = research, language = language, key = api_key)
  gmaps_data <- gmaps_request$results
  
  place_id <- gmaps_data$place_id
  rating <- gmaps_data$rating
  
token <- gmaps_request$next_page_token
Sys.sleep(5)
continue <- TRUE

  while (continue) {
    
    gmaps_request <- google_places(search_string = research, language = language, key = api_key, page_token = token)
    gmaps_data <- gmaps_request$results
    
    if (!is.null(gmaps_request$next_page_token)) {
      place_id = c(place_id,gmaps_data$place_id)
      rating = c(rating,gmaps_data$rating)
      token <- gmaps_request$next_page_token
      Sys.sleep(5)
    }
    else{continue <- FALSE}
  }

Now we’re going to search for the spatial coordinates of the places we found. To this extent, we’re going to use the google_place_details function of the packages, and retrieve latitude and longitude with these two functions :

get_lat <- function(id, key, language) {
  id <- as.character(id)
  details <- google_place_details(id, language = language, key=key)
  return(details$result$geometry$location$lat)
}

get_lng <- function(id, key, language) { 
  id <- as.character(id)
  details <- google_place_details(id, language = language, key=key)
  return(details$result$geometry$location$lng) 
}

All these blocks add up to build the complete function :

get_gmaps_data <- function(research, api_key, language) {
  
  gmaps_request <- google_places(search_string = research, language = language, key = api_key)
  gmaps_data <- gmaps_request$results
  
  place_id <- gmaps_data$place_id
  rating <- gmaps_data$rating
  
  token <- gmaps_request$next_page_token
  Sys.sleep(5)
  continue <- TRUE
  
  while (continue) {
    
    gmaps_request <- google_places(search_string = research, language = language, key = api_key, page_token = token)
    gmaps_data <- gmaps_request$results
    
    if (!is.null(gmaps_request$next_page_token)) {
      place_id <- c(place_id, gmaps_data$place_id)
      rating <- c(rating, gmaps_data$rating)
      token <- gmaps_request$next_page_token
      Sys.sleep(5)
    }
    else{continue <- FALSE}
  }
  
  lat = sapply(place_id, get_lat, key=api_key, language=language)
  lng = sapply(place_id, get_lng, key=api_key, language=language)
  
  return(data.frame(place_id, rating, lat, lng))
}

Map plot

The next part is more classical. We’re going to order the ratings of the data frame built by the previous function in order to arrange the places in differents groups. Each of the groups will be associated to a color on the data plot. If we want to make number_colors groups with the color scheme color (for instance, “Greens”), we are using the following instructions :

color_pal <- brewer.pal(number_colors, color)
pal <- colorFactor(color_pal, domain = seq(1,number_colors))

plot_data <- gmaps_data
plot_data$ranking <- ceiling(order(gmaps_data$rating)*number_colors/nrow(plot_data))

The definitive function just needs the addition of the leaflet call :

show_map <- function(number_colors, gmaps_data, color="Greens") {
  
color_pal <- brewer.pal(number_colors,color)
pal <- colorFactor(color_pal, domain = seq(1,number_colors))

plot_data <- gmaps_data
plot_data$ranking <- ceiling(order(gmaps_data$rating)*number_colors/nrow(plot_data)) leaflet(plot_data) %>% addTiles() %>%
  addCircleMarkers(
    radius = 6,
    fillColor = ~pal(ranking),
    stroke = FALSE, fillOpacity = 1
  ) %>% addProviderTiles(providers$CartoDB.Positron)
}

Examples

I just need to combine these two functions in one, and then to do some food-related examples !

maps_ranking_from_gmaps <- function(research, api_key, language, number_colors=5, color="Greens") {
  show_map(number_colors, get_gmaps_data(research, api_key, language), color)
}

maps_ranking_from_gmaps("Macaron, Paris, France", api_key, "fr")
maps_ranking_from_gmaps("Macaron, Montreal, Canada", api_key, "fr")

maps_ranking_from_gmaps("Poutine, Montreal, Canada", api_key, "fr", 5, "Blues")
maps_ranking_from_gmaps("Poutine, Paris, France", api_key, "fr", 5, "Blues")

which returns the following maps :

Macaron in Paris, France

Macaron in Montreal, Canada

Poutine in Montreal, Canada

Poutine in Paris, France (I guess French people are not ready for this)

Est-ce que cette piscine est bien notée ?

J’ai pris la (mauvaise ?) habitude d’utiliser Google Maps et son système de notation (chaque utilisateur peut accorder une note de une à cinq étoiles) pour décider d’où je me rend : restaurants, lieux touristiques, etc. Récemment, j’ai déménagé et je me suis intéressé aux piscines environnantes, pour me rendre compte que leur note tournait autour de 3 étoiles. Je me suis alors fait la réflexion que je ne savais pas, si, pour une piscine, il s’agissait d’une bonne ou d’une mauvaise note ! Pour les restaurants et bars, il existe des filtres permettant de se limiter dans sa recherche aux établissements ayant au moins 4 étoiles ; est-ce que cela veut dire que cette piscine est très loin d’être un lieu de qualité ? Pourtant, dès lors qu’on s’intéresse à d’autres types de services comme les services publics, ou les hôpitaux, on se rend compte qu’il peut y avoir de nombreux avis négatifs, et des notes très basses, par exemple :

Pour répondre à cette question, il faudrait connaître les notes qu’ont les autres piscines pour savoir si 3 étoiles est un bon score ou non. Il serait possible de le faire manuellement, mais ce serait laborieux ! Pour éviter cela, nous allons utiliser l’API de GoogleMaps (Places, vu qu’on va s’intéresser à des lieux et non des trajets ou des cartes personnalisées).

API, késako? Une API est un système intégré à un site web permettant d’y accéder avec des requêtes spécifiques. J’avais déjà utilisé une telle API pour accéder aux données sur le nombre de vues, de like, etc. sur Youtube ; il existe aussi des API pour Twitter, pour Wikipedia

Pour utiliser une telle API, il faut souvent s’identifier ; ici, il faut disposer d’une clef API spécifique pour Google Maps qu’on peut demander ici. On peut ensuite utiliser l’API de plusieurs façons : par exemple, faire une recherche de lieux avec une chaîne de caractères, comme ici “Piscine in Paris, France” (avec cette fonction) ; ensuite, une fois que l’on dispose de l’identifiant du lieu, on peut chercher plus de détails, comme sa note, avec cette fonction. De façon pratique, j’ai utilisé le package googleway qui possède deux fonctions qui font ce que je décris juste avant : google_place et google_place_details.

En utilisant ces fonctions, j’ai réussi à récupérer de l’information sur une soixantaine de piscines à Paris et ses environs très proches (je ne sais pas s’il s’agit d’une limite de l’API, mais le nombre ne semblait pas aberrant !). J’ai récupéré les notes et je constate ainsi que la note moyenne est autour de 3.5, ce qui laisse à penser que les piscines à proximité de mon nouvel appartement ne sont pas vraiment les meilleures… De façon plus visuelle, je peux ensuite représenter leur note moyenne (en rouge quand on est en dessous de 2, en vert de plus en plus foncé au fur et à mesure qu’on se rapproche de 5) sur la carte suivante (faite avec Leaflet, en utilisant le très bon package leaflet)

Comparaison avec d’autres lieux

En explorant Google Maps aux alentours, je me suis rendu compte que les agences bancaires du quartier étaient particulièrement mal notées, en particulier pour une banque spécifique (dont je ne citerai pas le nom – mais dont le logo est un petit animal roux). Je peux utiliser la même méthode pour récupérer par l’API des informations sur ces agences (et je constate qu’effectivement, la moyenne des notes est de 2 étoiles), puis les rajouter sur la même carte (les piscines correspondent toujours aux petits cercles ; les agences bancaires sont représentées par des cercles plus grands), en utilisant le même jeu de couleurs que précédemment :

La carte est difficile à lire : on remarque surtout que les petits cercles (les piscines) sont verts et que les grands (les agences bancaires) sont rouges. Or, il pourrait être intéressant de pouvoir comparer entre eux les lieux de même type. Pour cela, nous allons séparer au sein des piscines les 20% les moins bien notées, puis les 20% d’après, etc., et faire de même avec les agences bancaires. On applique ensuite un schéma de couleur qui associe du rouge aux 40% des lieux les pires – relativement (40% des piscines et 40% des agences bancaires), et du vert pour les autres. La carte obtenue est la suivante : elle permet de repérer les endroits de Paris où se trouvent, relativement, les meilleurs piscines et les meilleures agences bancaires en un seul coup d’œil !

Google introduit des modifications aux notes (en particulier quand il y a peu de notes, voir ici (en), mais pas seulement (en)) ; il pourrait être intéressant d’ajouter une fonctionnalité permettant de comparer les notes des différents lieux relativement aux autres de même catégorie !

[Sampling] Présentation à Ottawa – une nouvelle base pour les enquêtes de l’INSEE

Demain (jeudi 8 novembre), je donnerai une présentation au Symposium de méthodologie de Statistiques Canada sur la mise en place du nouveau système d’échantillonnage de l’INSEE pour les enquêtes auprès des ménages et des individus à partir des sources fiscales.

Ce changement de base apporte de nouvelles opportunités (nouvelles variables, nouveaux moyens de contact, meilleure coordination des enquêtes) mais aussi des défis (concordance des concepts, gestion du champ de la base administrative).

Les acétates sont ci-dessous :

Analyse de pronostics pour le Mondial 2018

On est les champions ! Si nous n’avons pas eu le temps de faire un modèle de prédiction pour cette coupe du monde de football 2018 (mais FiveThirtyEight en a fait un très sympa, voir ici), cela ne nous a pas empêché de faire un concours de pronostics entre collègues et ex-collègues statisticiens, sur le site Scorecast. Les résultats obtenus sont les suivants :

JoueurScore
Nic102
Cle100
Ron100
Lud96
Tho90
Lio88
Lis87
Pap86
Mau84
Yan78
Ant78
Lau75
Thi71
Arn56
Oli28
Mar7

Un autre système de points ?

Le système de points utilisé par Scorecast est le suivant : si on a le bon gagnant, on gagne un faible nombre de points ; si en plus du bon gagnant, on a bien prédit l’écart de buts, on gagne un peu plus de points ; et enfin, si on a le score exact, on gagne le nombre maximal de points. Ce nombre maximal de points augmente au fur et à mesure de la compétition : la finale vaut plus de points qu’un match de poules. Ce système ne tient pas compte de cotes préexistantes (comme le fait par exemple Mon petit prono), ou du fait que certains matchs sont bien prédits par tout le monde alors que pour d’autres seule une personne a bien trouvé, voire personne.

Je propose donc ici d’altérer légèrement l’attribution des points, de la façon suivante : on dispose d’un nombre de points équivalent pour chaque match d’une même manche (match de poule, de quart, etc.), qu’on répartit entre les joueurs qui ont bien prédit le score, avec un avantage pour ceux qui ont le bon écart de points ou le bon score exact. Le nombre de points à répartir augmente tout au long de la compétition, de sorte que les phases finales aient plus d’importance dans le classement final.

Pourquoi faire ça ? Pour favoriser les joueurs qui ont fait des paris plus originaux et potentiellement plus risqués, ou en tout cas qui étaient les seuls à avoir la bonne intuition. Voici les résultats :

JoueurScoreScore modifié
Mau84185
Lud96163
Nic102144
Tho90136
Ant78135
Cle100126
Ron100123
Lis87120
Lio88115
Pap86108
Yan78105
Lau75100
Thi7190
Arn5678
Oli2843
Mar710

On constate que le classement évolue sensiblement avec cette nouvelle méthode de points ! Mais peut-être que certains auraient fait d’autres paris si ces règles étaient décidées…

Choix des scores

Une des principales difficultés du pronostic est qu’il ne suffit pas de savoir (ou de penser savoir) qui va gagner le match, mais il faut aussi indiquer le score attendu. Regardons si les prédictions de l’ensemble des parieurs de notre ligue ont été pertinentes par rapport aux vrais scores ! Pour cela, on détermine pour chaque score le pourcentage des matchs qui ont abouti à ce résultat d’une part, et le pourcentage des paris faits avec ce score. On regarde ensuite la différence entre les pourcentages, qu’on va illustrer par la heatmap ci-dessous. Les cases vertes correspondent aux scores des matchs trop rarement prédits ; les cases rouges aux scores très souvent prédits mais qui n’arrivent que peu ou pas.

On constate que l’on a surestimé largement le nombre de 2-1, de 3-0 et de 4-0 (score qui n’est jamais arrivé lors de cette coupe du monde) ; ce sont d’ailleurs les seuls “gros” scores qui ont été surestimés dans les prédictions : tous les autres ont été sous-évalués. Cela peut laisser penser que les paris ont été faits avec une logique conservative et en évitant de tenter des scores absurdes, comme 7-0 pour l’Arabie Saoudite contre la Russie !

Analyse de données et classification

Enfin, une dernière utilisation possible de ce jeu de données est d’en faire l’analyse pour en extraire des classes de parieurs ayant un peu le même profil (ou en tout cas les mêmes réussites), et pour voir ce qui les sépare. Plusieurs méthodes sont possibles pour cela.

Commençons par un grand classique : la Classification Ascendante Hiérarchique (CAH pour les intimes), qui est une méthode qui part de groupes d’une personne, et qui, à chaque étape, regroupe deux groupes de telle façon à ce que l’inertie intra augmente au minimum. De façon moins barbare, cela veut dire qu’on regroupe les deux groupes qui se ressemblent le plus, étape par étape, jusqu’à arriver à la population totale. On représente souvent ce type de méthodes par un dendogramme, qui ressemble un peu à un arbre phylogénétique en biologie de l’évolution, et qui illustre la construction des classes, de bas en haut.

On remarque qu’il y a de nombreux binômes qui sont cohérents, et qui signalent des parieurs avec des profils comparables (par exemple, Mar et Oli, qui correspondent à deux joueurs ayant raté une bonne partie de la compétition, soit en arrêtant les paris, soit en arrivant en cours), et qu’il y a une séparation entre les quatre joueurs de gauche et les autres (eux-mêmes largement séparés entre les 3 les plus à gauche et les autres).

Une autre possibilité est d’utiliser l’Analyse en Composantes Principales, que nous avions déjà utilisé dans un contexte footballistique ici ou ici (en). La logique est ici de chercher à résumer une matrice avec beaucoup d’informations (pour chaque joueur, l’ensemble des points obtenus via ses paris pour chaque match) en un nombre minimal de dimensions, dits d’axes, qui suffisent pour avoir une bonne idée de la logique d’organisation du jeu de données.

Si l’on réalise cette méthode ici, voici ce que l’on obtient sur les premiers axes :

L’axe 1 est souvent victime de ce qu’on appelle l'”effet taille” : on entend par là le fait que les individus ayant de grandes valeurs de certaines variables en ont souvent aussi pour les autres variables, et symétriquement pour les individus qui ont des petites valeurs. En effet, on voit que la variable supplémentaire, le total de points obtenus (avec la méthode Scorecast), en bleu, est proche de l’axe 1. Cela veut dire que les individus à droite de l’axe ont tendance à avoir un score important, tandis que ceux à gauche n’ont pas très bien réussi leurs prédictions.

On constate également que les représentations sur les plans constitués des dimensions 1-2, et 2-3, ont tendance à rapprocher les individus que la classification effectuée plus haut associait en binôme. Cela montre une certaine cohérence, ce qui est toujours rassurant !

Plus dans le détail, on voit que les axes 2 et 3 semblent correspondre aux paris suivants, qui sont donc discriminants entre les différents joueurs :

  • Pour l’axe 2, avoir réussi son pari sur les matchs Pérou-Danemark, Mexique-Suède, Brésil-Suisse, Espagne-Russie et Argentine-Croatie
  • Pour l’axe 3, avoir réussi son pari sur les matchs Japon-Sénégal, Suisse-Costa Rica, Danemark-France ou encore Brésil-Mexique

Difficile de trouver une interprétation de ces axes…

Prédictions Eurovision 2018 – bilan

Pendant que Lisbonne se réveille sous des cris de poulet et des chats maneki-neko suite à la victoire de Netta, la candidate israélienne à l’Eurovision 2018, voici quelques commentaires à chaud sur le modèle de prédictions mis en oeuvre (détaillé ici, et repris ici pour les résultats de la finale)

Ce qu’on a réussi

La prédiction du vainqueur ! Les données Youtube étaient clairement atypiques cette année pour Israël (beaucoup plus de vues qu’une vidéo de l’Eurovision usuelle, et largement plus que les autres pays), mais cela ne prouvait pas que cette information uniquement impliquerait la victoire du pays. À voir ce qui se passera sur une année plus “classique”, mais cela reste une belle première performance.

Ce qu’on a moins bien réussi

À peu près tout le reste ! Le tableau ci-dessous récapitule nos prévisions et celles des bookmakers (arrêtées le soir de la seconde demi-finale), pour les comparer aux vrais résultats ; on calcule à chaque fois l’écart absolu, c’est à dire la différence entre la place prédite et la vraie place sans prendre en compte le signe de cette différence.

PaysModèleBookmakersRéalitéErreur modèleErreur bookmakers
Israël12101
Chypre1312111
Autriche151831215
Allemagne2274183
Italie1110565
République Tchéque311635
Suède56721
Estonie88800
Danemark1016917
Moldavie19141094
Albanie2525111414
Lituanie1441228
France7313610
Bulgarie4914105
Norvège6515910
Irlande12121644
Ukraine18201713
Pays-Bas26211883
Serbie16261937
Australie91920111
Hongrie24152136
Slovénie21242212
Espagne21723216
Royaume-Uni20232441
Finlande231325212
Portugal17222694

L’erreur totale (la somme de ces différences) est de 170 pour notre modèle, contre uniquement 138 pour les bookmakers. Nous sommes donc moins efficaces qu’eux pour l’instant, mais ce sera à charge de revanche l’année prochaine (et leur gagnant était Chypre…).

En particulier, les plus grosses erreurs de notre modèle sont l’Espagne, l’Allemagne et Chypre (même si on avait remarqué leur remontée ici). Les plus grosses erreurs des bookmakers sont la Finlande, la Norvège et la France (sur-estimée !). Enfin, les deux prévisions sont très mauvaises sur l’Autriche et sur l’Albanie, qui ont fait tous les deux un score bien meilleur qu’attendu.

Sur l’Espagne, notre supposé deuxième qui a fini dans les derniers : notre prédiction venait d’un très grand nombre de “like” sur la vidéo espagnole, qui n’est absolument pas corrélé avec le résultat définitif. Il semblerait donc que cette variable ne soit pas forcément pertinente. Ou alors cela vient du fait de la rumeur/question qui se posait sur leur couple ou non (en), qui aurait attiré un autre public plus adepte des likes ? Difficile à savoir.

Et pour l’année prochaine

Une idée : séparer le vote public et le vote des jurys ? A priori, les données Youtube devraient être plus efficaces pour prédire le vote du public. Reste à savoir ce qui peut être utilisé pour prédire le vote du jury…

Il pourrait être intéressant de voir si certains pays ont systématiquement fait mieux ou moins bien que ce que le modèle dit. Cela pourrait donner des pistes pour inclure d’autres facteurs (peut-être liés à la proximité des pays en cliques régionales ?). Il faut de toute façon améliorer le modèle au delà d’une régression linéaire.

Enfin, il sera intéressant d’intégrer le calcul des prévisions à une page qui se mettrait automatiquement à jour, par exemple tous les jours ou tous les quelques heures !

À l’année prochaine pour l’Eurovision 2019 🙂

Finale de l’Eurovision 2018 – prédictions

La finale de l’Eurovision a lieu samedi 12 mai. Voici nos prédictions pour les 26 pays y participant :

PaysScore préditPlace prédite
Israël13771
Espagne9062
République Tchéque2133
Bulgarie1874
Suède1675
Norvège1456
France1347
Estonie1188
Australie1159
Danemark10510
Italie10011
Irlande9912
Chypre9313
Lituanie9214
Autriche9015
Serbie8216
Portugal8117
Ukraine7718
Moldavie7719
Royaume-Uni7520
Slovénie7321
Allemagne7322
Finlande7123
Hongrie7124
Albanie5725
Pays-Bas5326

Eurovision 2018 – prédictions – mise à jour

Un rapide article pour intégrer les données disponibles à une semaine de la finale du concours Eurovision 2018 ! Nous allons reprendre exactement la méthode décrite ici, mais en utilisant les données de Youtube au 5 mai 2018, soit une semaine avant la diffusion de la finale.

Voici le tableau avec les scores mis à jour :

PaysÉvolution au classementScore prédit (un mois avant)Score prédit (une semaine avant)
Israël15851377
Espagne+1375906
Russie-1393372
République Tchéque210213
Bulgarie207187
Suède189167
Norvège150145
France140134
Grèce140125
Estonie130118
Australie129115
Macédoine+2117107
Azerbaïdjan-1118106
Belgique+1119106
Danemark116105
Biélorussie109103
Italie106100
Irlande+110699
Chypre+49593
Lituanie10292
Arménie10092
Autriche9990
Malte-510685
Serbie9182
Portugal8981
Ukraine+18077
Moldavie+18077
Royaume-Uni-28275
Slovénie-28073
Allemagne+27673
Suisse7772
Finlande7471
Hongrie7471
Georgie7469
Roumanie7366
Pologne+16663
Croatie-16762
San Marin6158
Albanie+15757
Montenegro-16056
Pays-Bas-15653
Lettonie+15552
Islande5136

Il n’y a pas énormément de changements, mais il y a tout de même un échange de places entre la Russie (qui a peu de chances de se qualifier en finale selon le modèle, donc qui était déjà un résultat étonnant) et l’Espagne (qui est qualifié automatiquement, donc potentiellement un favori, même si les bookmakers ne les classent que 12èmes aujourd’hui), suite à une augmentation énorme du score prédit de l’Espagne. Pour information, voici la chanson de l’Espagne :

Plus loin dans le classement, on constate des remontées de Chypre (classée 6ème selon les bookmakers) et de la République de Macédoine, dans une moindre mesure. Peut-être des pays à suivre également ? Pour se faire un avis, voici ce que propose Chypre cette année :

Bon Eurovision à tous, et à dans une dizaine de jours pour faire le bilan sur ces prédictions !

Eurovision 2018 – prédictions

Aujourd’hui un rapide article pour donner des premières prédictions pour l’Eurovision 2018, avec un modèle très simplifié basé sur les statistiques des vidéos publiées sur Youtube pour l’intégralité des pays participants, en espérant trouver le temps pour l’améliorer dans les prochaines années !

Les données

Nous allons essayer de prédire les résultats (participation à la finale – ce point avait déjà été discuté sur le blog, puis score obtenu) à partir des informations disponibles sur les vidéos Youtube : nombre de vues, nombre de “Like” (pouces vers le haut, qui indiquent que la vidéo a été appréciée) et nombre de “Dislike” (pareil mais vers le bas, qui indiquent que la vidéo n’a pas été appréciée par le spectateur).

Nous récupérons ces informations grâce au package R tuber, qui permet d’aller faire des requêtes par l’API de Youtube et ainsi de récupérer pour chacune des vidéos d’une playlist les informations nécessaires pour le modèle. Nous récupérons alors les données pour les chansons des concours 2016, 2017 et 2018. Ces informations sont ensuite complétées avec le nombre de points obtenus et le rang du classement final pour les finalistes des éditions 2016 et 2017. Les données sont disponibles ici.

Évidemment, ces données ont leurs limites. Je n’ai pas trouvé comment rechercher des informations sur les vidéos Youtube à une autre date, ce qui fait que l’on va utiliser des données après la diffusion des concours 2016 et 2017 pour évaluer un modèle, que l’on appliquera à des données avant le concours pour 2018. Par ailleurs, le système de notation a évolué en 2016, ce qui explique pourquoi on se limite aux données sur les deux dernières années pour notre modèle. Par ailleurs, pour lisser les effets de taille (1 millions de vues en moyenne pour les vidéos 2018 contre 5 millions pour celles de 2016), nous travaillons sur des données standardisées en divisant par la moyenne du nombre de vues, de likes, etc.

Le modèle

Nous travaillons ensuite sur deux problèmes : estimer la probabilité qu’une chanson soit qualifiée en finale, puis estimer le score qu’elle va obtenir, pour évaluer son classement final. En ce qui concerne la probabilité de qualification en finale, nous réalisons une régression logistique. La seule variable qui ressort est le nombre de Dislike, qui influe légèrement négativement la chance d’être qualifié. C’est assez logique : moins la vidéo est appréciée, moins il y a de chances que le pays soit qualifié en finale.

En ce qui concerne le nombre de points obtenus, nous testons deux approches concurrentes :

  • Une régression linéaire sur les variables : dans ce cas, on observe que le nombre de vues ne joue pas significativement, le nombre de Likes de façon très mineure et le nombre de Dislikes très nettement, avec un lien positif : plus il y a de pouces baissés, plus le score est important. Ce résultat atypique peut s’expliquer par le fait que la vidéo ukrainienne en 2016, gagnante, a plus de 40 000 pouces baissés.
  • Un arbre de régression qui permet de séparer à chaque étape la population en deux et d’évaluer un score moyen. Cette méthode est moins efficace pour prédire le score exact, mais elle permet d’identifier les déterminants du score. L’arbre ci-dessous décrit la partition des vidéos :

Cet arbre se lit de la façon suivante :

  • Si l’on a plus de 2,216 fois le nombre de vues moyen des vidéos de l’année, alors le score prédit par la méthode est 425 (les vidéos populaires ont des scores importants). Sinon, on passe à l’étape suivante
  • Si l’on a moins de 89% du nombre de Likes moyen des vidéos de l’année, alors on part dans le sous-arbre encadré en bleu ; si c’est plus, dans celui encadré en vert.
  • L’opération se répète jusqu’à qu’on arrive à un carré en bas de l’arbre, où l’on lit le score prévu

Les résultats

Voici les prédictions obtenues, en utilisant la méthode de régression linéaire pour le score total :

PaysProba d'aller en finaleScore prédit
Israël99%1585
Russie25%393
Espagne100%375
République Tchéque99%210
Bulgarie99%207
Suède94%189
Norvège74%150
France100%140
Grèce97%140
Estonie71%130
Australie75%129
Belgique74%119
Azerbaïdjan83%118
Macédoine67%117
Danemark85%116
Biélorussie78%109
Italie100%106
Malte79%106
Irlande73%106
Lituanie77%102
Arménie62%100
Autriche70%99
Chypre62%95
Serbie42%91
Portugal100%89
Royaume-Uni100%82
Ukraine38%80
Moldavie29%80
Slovénie19%80
Suisse48%77
Allemagne100%76
Finlande31%74
Hongrie28%74
Georgie15%74
Roumanie31%73
Croatie19%67
Pologne34%66
San Marin10%61
Montenegro16%60
Albanie21%57
Pays-Bas15%56
Lettonie16%55
Islande9%51

Le grand gagnant est Israël, ce qui est plus ou moins la prédiction faite par tout le monde : voir ici ou ici. À noter que l’année dernière, l’Italie était grande favorite (et a fini 6ème), donc rien n’est encore fait… Si vous voulez vous faire une idée :

Un résultat plus étonnant concerne la Russie. Elle est classée deuxième par notre modèle, mais avec une faible chance d’être qualifiée en finale. Cela semble venir d’un très haut nombre de pouces baissés sur la vidéo, qui influencent énormément notre prédiction. La Russie est placée 25ème par les bookmakers, donc à voir si notre modèle a détecté quelque chose ou s’il s’agit d’un cas de surapprentissage. Pareil, pour se faire un avis :

Et enfin, soyons chauvins ! Nous serions dans le top 10 avec Mercy. C’est d’ailleurs cohérent avec les estimations des bookmakers. Tout est donc encore possible 😉

Chance et talent dans le sport

(Ce petit article est une reprise d’un fil twitter fait à l’occasion du Final Four de la NCAA)

Aujourd’hui on propose de prendre un peu de temps pour discuter des notions de “chance” (luck) et de “talent” (skill) dans le domaine du sport, en s’inspirant d’arguments exposés dans The Success Equation: Untangling Skill and Luck in Business, Sports, and Investing, sorti en 2012. La question qui se pose est la suivante : dans les résultats d’une équipe sportive ou d’un athlète, qu’est-ce qui vient de l’habileté et qu’est-ce qui relève uniquement de la chance ? Même si l’on faisait l’hypothèse que le déterminant principal d’un résultat est le talent de l’athlète, certaines sous-performances peuvent arriver.

C’est un sujet assez classique, qui est développé dans la plupart des études statistiques sur le sport. Pour ceux qui préfèrent le format vidéo, voici un résumé rapide de ce qu’explique le livre :

Mathématiquement, on considère que le skill et la chance sont deux variables indépendantes. On peut donc écrire une équation très simple sur leur variance :

Var(observations) = Var(skill) + Var(chance)

Cela nous donne donc une façon d’estimer la contribution du skill dans les résultats, c’est à dire une idée de l’importance du talent de l’athlète :

Var(skill) = Var(observations) – Var(chance)

Plus ce terme est important, plus les résultats obtenus proviennent du fait que le sport récompense les joueurs qui ont du talent. Dans un jeu complètement aléatoire (pile ou face…), c’est uniquement la chance qui amène au résultat final. On imagine alors que chaque sport va plus ou moins s’éloigner de ce modèle.

Nous avions discuté de cette question par rapport au badminton et au tennis ; on constatait alors que, grâce à la règle de l’écart des deux points, il y avait une plus grande stabilité des victoires (et donc une plus faible part de chance) au tennis qu’au badminton. Une même question se posait sur le tir à l’arc, avec le changement des règles qui permet plus facilement de rattraper une flèche ratée.

Comment faire pour estimer cette contribution ? Pour le premier terme, Var(observations), c’est facile. On considère les résultats (d’une saison par exemple) comme une variable aléatoire et on calcule sa variance. On constate que certains sports sont plus variables que d’autres, par exemple le basket par rapport au hockey :

Le seconde terme, Var(chance), est un peu plus complexe à estimer. Dans son son livre, Mauboussin prend chaque match comme une expérience de Bernoulli (avec une probabilité de victoire qui correspond au taux de victoire dans la saison). Il obtient donc, par sport, un pourcentage d’explication du skill dans le résultat final. Par exemple, pour la NBA il obtient 88% et pour la NHL 47%.

Une bonne part de la variance s’explique en fait par le nombre de matches joués, qui correspond dans la logique à la “taille d’échantillon”. La NFL (16 matches / saison) est donc logiquement plus aléatoire que la NBA (82 matches / saison) sur l’axe skill / chance représenté en haut de l’article. On peut aussi appliquer le même concept en considérant chaque “action” comme une expérience aléatoire. Par exemple, chaque possession au basket, comme une chance de marquer avec une certaine probabilité. C’est pour cela l’on s’attendait à ce que l’underdog Loyola-Chicago essaye de jouer le plus lentement possible.

L’idée derrière cette stratégie est que moins de possessions implique plus de variance et donc moins de chances de l’emporter pour le favori ; en effet, plus l’on joue, plus l’aléatoire doit s’équilibrer et donc le talent va s’imposer. La validité de cette stratégie est disputée : certaines analyses statistiques ont montré que les chances de victoires des équipes mal classées (underdogs) contre des équipes réputées bien meilleures n’était pas modifiées par le rythme du match.

Pour conclure, le même genre d’analyse a été appliqué récemment (avec plus ou moins de succès) à l’esport. Yauheni Hladki a présenté à la GDC une analyse dont le résultat situe tous les jeux (oui, tous, même Hearthstone) à la droite des échecs sur l’axe skill / chance. Ce qui signifierait que la chance aurait moins d’impact sur le résultat que dans la plupart des sports. En d’autres termes, qu’une équipe mal classée de CS:GO n’aurait que des chances infimes de remporter un match contre une équipe du top mondial… pas terrible pour le suspense si cela était vrai !

La “clé” derrière ce résultat est que l’auteur considère chaque action effectuée en esport comme une expérience aléatoire. Cela inclut par exemple chacun des tirs effectués dans une partie de CS:GO ! La taille d’échantillon “équivalent” considérée est énorme (la variance obtenue est donc très faible) et c’est ce qui le conduit à placer tous les esports au même endroit sur l’axe. À vous de juger de la pertinence de cette méthode !