Hans Rosling ne fera plus de vidéos

Quand on aime les statistiques et la santé publique, on aime les vidéos d’Hans Rosling, qui vient de mourir d’un cancer du pancréas.

J’ai passé (des extraits de) cette vidéo dans de très nombreux cours. C’est d’ailleurs le seul « TED Talk » que j’ai regardé en entier.

Hans Rosling animait le site Gapminder, qu’il a créé avec son fils (si je me souviens bien), et dont j’ai réutilisé plein de cartes et de graphiques.

Toute la communauté de la « dataviz », dont il était devenu l’une de figures de proue pour son talent et son optimisme de vulgarisateur des statistiques du développement, est en deuil depuis hier. La communauté de « l’open data » est aussi en deuil, Rosling ayant beaucoup oeuvré pour la « libération » des données produites par les Nations Unies et par d’autres institutions.

Complément : cet article de la BBC, avec qui Hans Rosling avait travaillé sur le documentaire « The Joy of Stats« , contient quelques information supplémentaires.

Qualifier et quantifier l’activité parlementaire : demandez le programme

En octobre dernier, vous avez pu lire sur ce blog l’appel à communications de la Section Thématique 38 du Congrès AFSP 2017, « Qualifier et quantifier l’activité parlementaire : données, méthodes et pratiques« .

La sélections des communications qui seront présentées dans la section est à présent terminée, et le programme de la section est désormais disponible sur le site Internet (temporaire) de la section :

st38-prog

Le programme est en anglais car la section aura lieu en anglais, histoire de permettre aux non-francophones de se sentir un peu plus à l’aise sous le soleil montpelliérain.

La sélection et ses suites

Le programme, élaboré avec Olivier Rozenberg, est résolument international, avec des papiers de plusieurs pays francophones mais aussi d’ailleurs. La sélection a été difficile : nous avons reçu 25 propositions d’un peu partout dans le monde1, et parmi elles, beaucoup étaient assez, voire très, pertinentes.

Remarque : trop peu de femmes

Mon seul vrai regret concernant les propositions que nous avons reçues : sur les 44 auteurs listés, on ne trouve que 5 femmes, et qu’une seule femme parmi les papiers retenus2. C’est peu, et probablement en-deçà de la présence des femmes dans les milieux scientifiques qui ont reçu notre appel à communications—du moins souhaitons-le !

Au niveau de l’âge, nous avons reçu un bon mélange de « juniors » et de « seniors » ; mais au niveau du sexe, notre créneau thématique (les études parlementaires) me semble terriblement masculin… Peut-être est-ce aussi la conséquence de la coloration « méthodologique », voire « quantitativiste », de notre thème de section.

Je ne citais pas directement la « ST 38 » dans ce billet, mais vous aurez fait le rapprochement.

À noter également : la « ST 37 »

Pour celles et ceux qui seront à Montpellier, notez également l’existence de la Section Thématique 37, « Dans l’ombre de la loi. Travail au parlement et vie politique », organisée par Sébastien Michon et Étienne Ollion.

See you in Montpellier!

  1. Plus exactement, nous avons reçu des propositions de chercheurs établis dans 13 pays différents, en excluant une proposition totalement hors-sujet (la seule) en provenance des Philippines. []
  2. Toujours si l’on exclut la seule proposition complètement hors-sujet, qui nous a été envoyée par deux jeunes étudiantes. La différence de proportion est non significative, mais cela reste regrettable. []

Qualifier et quantifier l’activité parlementaire : données, méthodes et pratiques

Olivier Rozenberg et moi-même organisons une section thématique au prochain Congrès de l’Association Française de Science Politique. Voici l’appel à communications, qui se termine dans une semaine :

st38

L’appel existe aussi en anglais, et le reste des détails est à trouver sur le site Internet de la section, qui disparaîtra quand elle aura eu lieu—attendez-vous donc à ce que tous les liens de ce billet finissent en erreur 404 dans quelques temps.

Si vous aimez les parlements et les données, envoyez vite votre proposition de communication !

Remerciements

La diffusion de cet appel à communications m’a donné l’occasion de faire le tour des associations professionnelles et groupes de recherche qui travaillent sur les parlements. Outre l’AFSP et l’ANCMSP, voici la liste des groupes qui ont reçu et diffusé l’appel—avec tous mes remerciements à leurs coordinateurs et organisateurs :

La seule société qui n’ait pas diffusé l’appel est la Société Québécoise de Science Politique, mais bon, on ne va pas se fâcher pour si peu.

Remerciements supplémentaires au blog germanophone « Soziologie der Parlamente » (hébergé sur Hypothèses), qui a relayé l’appel de son côté.

Repérages supplémentaires

La liste ci-dessus n’est pas tout à fait exhaustive : pour la zone francophone, le Groupe de Recherche sur les Parlements et les Parlementaires (GRPP) de l’AFSP aurait été pertinent, mais il est apparemment inactif, de même que l’Association de science politique du Luxembourg, LUXPOL, et que les associations qui ont existé en Tunisie et au Cameroun.

De plus, si l’on souhaitait étendre la liste aux groupes d’histoire parlementaire francophones et anglophones, il faudrait aussi inclure les groupes suivants :

  1. Calenda n’a pas encore diffusé l’appel, mais c’est ma faute, j’envoie toujours trop peu à l’avance… Mise à jour : c’est fait, l’équipe de Calenda a été très rapide—merci beaucoup ! []
  2. Et l’IPSA elle-même, qui a aussi diffusé l’appel de son côté. []
  3. Ce groupe est centré sur un autre sujet, mais je n’ai pas trouvé de groupe « parlements » au sein du CES, et ai pris celui-ci en remplacement. []

Enseigner le “quanti”

enseigner-le-quanti Vous l’aviez vue annoncée sur le blog Quanti / Sciences sociales : hier avait lieu la journée d’étude “Enseigner le quanti dans le supérieur”, à l’initiative d’un comité d’organisation qui incluait notamment Pierre Mercklé et Anton Perdoncin, qui s’occupe du Séminaire de quantitativisme réflexif.

Cette journée m’a renvoyé quelques années en arrière : à Édimbourg, en 2008, les enseignants de méthodes quantitatives avaient créé un petit groupe de réflexion de quantitativistes, dont la liste de discussion s’est tarie en 2013. La journée d’étude d’hier avait une toute autre dimension : il devait y avoir 75 enseignants d’un peu partout.

La réflexion portait sur l’enseignement des méthodes quantitatives, assez rarement évoqué sur ce blog de manière frontale, sauf peut-être indirectement par les utilisations de logiciels comme Microsoft Excel (il y a longtemps), Stata (pendant plusieurs années) ou R (depuis quelques années).

La journée était très bien fichue, et je vous conseille vivement de garder un oeil sur le blog Quanti / Sciences sociales pour en récupérer ce qui en ressortira. L’enseignement du « quanti » est un secteur intéressant à plus d’un titre, et ce qui s’y produit en termes de pédagogie vaut peut-être un détour particulier.

De mon côté, j’ai retenu les points suivants :

  • L’enseignement du « quanti » est profondément par le stigmate d’être, au mieux, inintéressant (voire traumatique) pour un public qui conçoit les sciences humaines comme des humanités littéraires.
  • Le premier thème qui revenait systématiquement dans toutes les discussions était toujours celui du support informatique (du logiciel à utiliser). La seule transition qui revient tout le temps est celle vers R.
  • Le second thème qui revenait de manière latente était celui des données : des conditions éthiques et juridiques de l’accès aux données, mais aussi du type d’enquête à employer, et de ce qu’il serait possible d’envisager à l’avenir.

Le dernier point est intéressant, parce qu’il montre bien qu’il y a une forme d’ingéniérie (voire même un style cognitif) du maniement de données, qu’elles soient quantitatives ou pas, d’ailleurs—ce qui ouvre la perspective d’un enseignement du « quanti » assez proche des compétences regroupées sous l’intitulé hybride data science.

La conséquence pour l’enseignement me semble être qu’il faut envisager trois échelles parallèles de progression pédagogique :

  • une échelle d’apprentissage technique, celle de l’outil informatique et du logiciel utilisé, en particulier dès qu’il s’agit de rendre les analyses réplicables ;
  • une échelle d’apprentissage formel, qui consiste, d’une manière ou d’une autre, à faire comprendre ce que l’on mesure, et avec quelle marge d’erreur ; et
  • une échelle d’apprentissage disciplinaire, qui consiste à (faire) comprendre comment les deux apprentissages précédents contribuent à celui de le discipline.

Sur ce dernier point, mais Étienne l’a exprimé mieux que moi, la contribution du « quanti » aux sciences sociales passe en partie par sa capacité à fournir des données d’enquête, mais aussi des données intégralement numériques (initialement produites sur Internet).

Enfin, je profite de ce billet pour citer le blog ElementR, que je ne mentionne pas assez souvent. Le blog est animé par une équipe d’utilisateurs de R venant de plusieurs laboratoires de sciences sociales. À souligner dans leur excellente série de tutoriels, l’ouvrage (gratuit) “R et espace”, pour apprendre la cartographie et l’analyse spatiale avec R.

Mise à jour : les slides des interventions sont en ligne !

Extraire un réseau de coauteurs depuis la base PubMed

La base MEDLINE contient environ 23 millions d’articles scientifiques, accessibles via le moteur de recherche PubMed depuis une vingtaine d’années. Ces articles sont utilisés pour toutes sortes d’analyse, des méta-analyses aux analyses de communautés sémantiques. La base PubMed, c’est très littéralement du big data, et les chercheurs comme les entreprises le savent depuis un bail1.

Le sujet vous donne une idée de ce que je vais faire de mes vacances, mais la phase données devrait être indolore : MEDLINE est une base extrêmement bien entretenue, et les opérations ci-dessous font moins saigner des yeux que, par exemple, au hasard (p < .0001), les fichiers du Ministère de l’Intérieur. De plus, on va travailler sur des requêtes précises plutôt que sur la base intégrale.

Allez découvrir PubMed si vous n’avez jamais fait un tour, c’est un tour de force du point de vue de la science archivistique et documentaire, et un fleuron discret de la médecine scientifique contemporaine, “basée sur les preuves” (id est publiée dans une revue scientifique avec un impact factor aussi élevé que possible ; pour les preuves, la maison demande un délai d’environ quinze années supplémentaires) :

Screen Shot 2014-06-14 at 5.26.38 PM

Télécharger une requête PubMed

Les articles en accès ouvert via PubMed Central (PMC) sont facilement téléchargeables depuis un serveur FTP, mais pour obtenir les résultats d’une requête sur la base intégrale, c’est un peu plus long. Heureusement, grâce à Kristoffer Magnusson, il y a ce bout de code vieux de deux ans, qui méritait un petit remix.

La première étape consiste à envoyer une requête PubMed du même type que celle que l’on rentre dans le moteur de recherche en ligne2, et à récupérer en retour un fichier XML qui contient la requête développée en plusieurs mots-clés, après vérification de leur disponibilité dans les mots-clés du thesaurus MeSH (Medical Subject Headings) de la National Library of Medicine. La requête health (inequalit*) donne ainsi :

("health"[MeSH Terms] OR "health"[All Fields]) AND (inequalites[All Fields] OR inequaliti[All Fields] OR inequalities[All Fields] OR inequalities'[All Fields] OR inequalitiies[All Fields] OR inequalitiy[All Fields] OR inequality[All Fields] OR inequality'[All Fields] OR inequality's[All Fields] OR inequalityin[All Fields] OR inequalitys[All Fields])

Mais vous avez plutôt intérêt à formuler la requête health AND (inequality or inequalities), qui va identifier les mots-clés correspondant à l’entrée MeSH consacrée aux facteurs socio-économiques, le nom donné par PubMed aux recherches sur les inégalités de santé. La requête devient alors, sans l’antislash de formatage3 :

("health"[MeSH Terms] OR "health"[All Fields]) AND \(("socioeconomic factors"[MeSH Terms] OR ("socioeconomic"[All Fields] AND "factors"[All Fields]) OR "socioeconomic factors"[All Fields] OR "inequality"[All Fields]) OR ("socioeconomic factors"[MeSH Terms] OR ("socioeconomic"[All Fields] AND "factors"[All Fields]) OR "socioeconomic factors"[All Fields] OR "inequalities"[All Fields]))

Le nombre total d’articles correspondant à la requête se trouve dans le même fichier XML et ne demande que peu d’efforts pour être récupéré, mais c’est surtout le “numéro unique” de la requête qui va nous intéresser : la variable NCID est une chaîne unique qui permet de récupérer les résultats de notre recherche (métadonnées et résumés des articles) sans se fatiguer, une fois placée dans une boucle récupérant n articles k fois.

C’est la seconde et dernière étape : en quelques lignes, on écrit une boucle de téléchargement qui demande les mille premiers articles PubMed correspondant à la requête, qu’on sauvegarde dans un fichier XML, puis les mille suivants, et ainsi de suite. Un fichier XML, c’est du contenu entouré de balises de marquage sémantique, comme dans cet exemple :

Screen Shot 2014-06-14 at 5.04.11 PM

La boucle de téléchargement écrit un rapport qui contient la datation des fichiers, histoire que vous puissiez la lancer en plusieurs fois si nécessaire sans recommencer au début. Le code, qui fait 300 lignes à tout casser, permet aussi de compter le nombre d’articles par année, par revue, ou les deux, ou par nombre d’auteurs.

Démo : la Convention-cadre OMS FCTC

La démo du code télécharge 236 articles en rapport avec la Convention-cadre de l’OMS pour la lutte antitabac. Quand on jette un coup d’oeil aux auteurs les plus fréquents dans le corpus, on trouve par exemple J. Collin et H. M. Mamudu, des noms connus dans ce segment de la littérature :

> pubmed_names('pubmed_fctc', min = 5)
538 Warren CW    14
30     Asma S    13
169 Glantz SA    13
225  Jones NR    13
414     Raw M     8
479  Sinha DN     8
150   Fong GT     7
316 McNeill A     7
67  Borland R     6
87  Chapman S     6
98   Collin J     6
298 Mamudu HM     6

Si l’on regarde les dates, le plus intéressant est au début : les premiers articles apparaissent trois ans avant l’adoption du texte, dans une revue de l’OMS et sous la plume de chargés de mission affectés à son élaboration. Celui-ci bénéficie ensuite d’une couverture exceptionnelle en 2005, son année d’application, et sa couverture reste élevée dans les années récentes4.

> head(pubmed_years('pubmed_fctc'))
  year count
1 2000     1
2 2001     2
3 2002     3
4 2004     1
5 2005    16
6 2006     3

Faites-vous une idée des articles téléchargés en allant lire le plus ancien, qui évoque la Convention-cadre et surtout les accords du GATT : la perspective d’une remise à plat des règles du commerce mondial offre une fenêtre d’opportunité à l’OMS pour produire son propre corpus de normes, en s’inspirant d’autres conventions comme celle de Basel5.

Screen Shot 2014-06-14 at 7.59.48 PM

Voici à présent le nombre d’articles publiés chaque année en lien avec la Convention-cadre par année. Les couleurs soulignent les revues qui ont le publié le plus d’articles (sans surprise, des revues de santé publique comme Tobacco Control et Addiction), ainsi que le Bulletin de l’OMS, le BMJ et le Lancet (il n’y a pas d’articles NEJM dans le corpus).

example

Comme il n’y a pas trop de données, on peut assez bien voir les petites aberrations du corpus, comme par exemple, ci-dessous en 2005, le numéro spécial d’un institut indépendant. La revue était alors basée à Vanves et publiée majoritairement en français ; elle a changé de nom et est à présent publiée par Sage Publications.

pubmed_fctc_lang

Mais… mais où est le réseau ?

Ah, je suis content que vous posiez la question. Pour les habitués, voici donc le réseau des co-auteurs dans le corpus « Convention-cadre OMS anti-tabac », où l’on retrouve les auteurs cités avec une de leurs collègues, plus des connexions entre chercheurs américains et britanniques, le tout entouré de beaucoup d’isolats.

pubmed_fctc_net

Le code pour créer le réseau produit un réseau non dirigé, où chaque lien indique un article co-signé par les deux auteurs. Le poids du lien est inversement proportionnel au nombre de coauteurs par article, additionné pour chaque paire de coauteurs (méthode “Newman-Fowler” ; appellation non contrôlée)6.

Le code du graphique lui-même, qui utilise ggnet (actuellement en soldes !), tient en dix lignes une fois les dépendances installées (packages devtools pour lire la fonction depuis GitHub sans vous embêter, network, sna et intergraph pour les réseaux, et RColorBrewer et ggplot2 pour le graphe).

source_url("https://raw.githubusercontent.com/briatte/ggnet/master/ggnet.R")
d = pubmed_edges("pubmed_fctc")
n = network(d[, 1:2])
n %e% "w" = d[, 3] / max(d[ , 3])
n %e% "q" = as.numeric(cut(n %e% "w", quantile(n %e% "w"), include.lowest = TRUE)) / 4
ggnet(n, segment.alpha = n %e% "q",
      segment.color = "black", size = 1) + 
  geom_text(label = ifelse(degree(n) > quantile(degree(n), .9),
                           network.vertex.names(n), NA), size = 4)
ggsave("pubmed_fctc_net.pdf", width = 11, height = 11)

Les données sont quasi-exhaustives, si l’on en croit le tests initiaux de 2011-2012. En revanche, le graphe peut éventuellement contenir plusieurs fois le même auteur s’il a été identifié par plusieurs combinaisons d’initiales et/ou de noms de famille (par exemple, “C Marquez” et “CR Marquez”).

Plus tard

On ira plus loin une prochaine fois, en regardant les mots-clés et les auteurs de plus près. La méthode de construction du réseau utilisée dans la demo est très basique : d’une part, elle ne collecte aucun attribut sur les auteurs, d’autre part, elle aplanit un réseau bipartite auteur-article où le mode secondaire (l’article) est très intéressant. À suivre, donc.

  1. L’industrie pharmaceutique , par exemple, a largement investi le champ de l’édition scientifique à des fins de légitimation de ses produits. []
  2. L’opérateur par défaut est AND. Les connecteurs logiques doivent être rentrés en majuscules et en anglais. Le reste des consignes est donné dans l’aide de PubMed. []
  3. L’antislash ne sert qu’à éviter un problème d’affichage avec le moteur de formatage du blog ; il ne doit pas figurer dans le code. []
  4. Il y a eu jusqu’à 44 articles sur le sujet en 2012, année d’adoption d’un protocole supplémentaire. Pour rappel, la recherche initiale n’utilise que les résumés (et les titres) des articles. []
  5. Le problème étant, bien évidemment, que jamais l’OMS n’a pu appliquer le genre de sanctions très dissuasives que l’OMC peut employer sur les marchés mondiaux. []
  6. La méthode Newman-Fowler étant additive, ses liens peuvent donc représenter un ou plusieurs articles co-signés. Le code renvoie aussi la version brute des liens au format CSV. []

Extraire un corpus médiatique sans (trop) saigner des yeux

Vous vous êtes déjà demandé quelle avait la couverture médiatique d’un projet de loi comme le projet de loi DADVSI ? ou, plus connu, le projet de loi HADOPI, qui donna lieu à un feuilleton législatif de plusieurs années ?

J’avais très rapidement mentionné le sujet en évoquant un papier co-écrit avec Pierre Gueydier, présenté à l’AFSP en 2013 et que nous avons commencé à remettre à jour. Comme d’habitude, tout est en ligne.

Le papier portant sur la politisation, une étude préliminaire de la médiatisation des projets de loi peut être un bon moyen de jeter un premier coup d’oeil aux individus, aux institutions et aux organisations mobilisées autour de leur examen.

Quelques essais et 300 lignes de code plus loin, on dispose donc d’un corpus de 6350 articles issus de sept médias français différents1, qui ressemble à ça au fil du temps :

counts

Comment faire

  • Pour chaque média, il y a un moteur de recherche utilisant une pagination des résultats. La première étape consiste donc à parcourir chaque page de résultats, en récupérant les adresses des articles.
  • Ensuite, pour chaque article, on a accès soit à une page donnant accès au texte intégral, soit aux premières lignes du texte dans le cas des articles payants du Figaro et du Monde.
  • Enfin, il faut se donner une syntaxe permettant de sauvegarder le contenu d’un lien HTTP vers un fichier texte, ce qui demande quelques essais-erreurs avec les expressions régulières.

Les techniques servant à récupérer et à nettoyer les données ayant déjà été traitées dans plein d’autres billets (exemple), je ne développe pas sur ce point, mais suis intéressé par tout scraper équivalent pour d’autres sites de médias.

Qu’en tirer

Le raisonnement du texte étant qualitatif, l’exploration du corpus est avant tout une manière de trianguler des décisions de terrain, comme le choix de se focaliser sur certains acteurs plutôt que d’autres.

Histoire de repérer les acteurs, on extrait tous les termes contenant une majuscule initiale, que l’on nettoie ensuite des termes courants. Restent les termes comme « Vivendi Universal » ou « Frédéric Mitterrand ».

On parcourt ensuite les mille termes les plus fréquents, dont on tire une liste de presque 350 entités, allant de la classe politique à Twitter en passant par les DRM et la jurisprudence SABAM.

Voici à quoi ressemble la co-occurrence de ces entités dans les articles publiés entre 2012 et aujourd’hui, représentées sous la forme d’un réseau de termes fréquemment associés à la « mission Lescure-préparant-l’acte-II-de-l’exception culturelle » :

seq3

Le réseau est naturellement très dense (il y a énormément de co-occurrences), mais les liens sont plus ou moins ténus, grâce à une technique de pondération qui tient compte du nombre d’entités identifiées dans chaque article2.

En additionnant ces liens, on obtient un indice plus synthétique, le degré pondéré de centralité. Dans le graphique ci-dessus, la taille des entités est proportionnel à cet indice, qui n’est qu’une mesure possible parmi d’autres.

Voici donc, pour terminer, les quinze premiers scores de centralité sur la totalité des neuf années couvertes. D’autres tableaux et graphiques explorant des segments temporels spécifiques de la période couverte sont disponibles dans l’annexe du papier.

Screen Shot 2014-06-26 at 3.39.09 PM

Je n’ai pas le temps de m’acharner sur les données, mais cette preuve du concept montre qu’il n’est pas difficile de récolter un corpus médiatique, hélas moins riche qu’une base de données comme Factiva ou LexisNexis, mais d’ampleur raisonnable.

Si vous avez des suggestions sur comment modéliser tout ça proprement, à coups de topic models ou autre chose, laissez un commentaire, mais c’est en général à ce stade-là que l’on commence à saigner un peu des yeux.

  1. Libération apparaît dans le corpus Écrans.fr, et les articles des Échos ne sont pas disponibles avant décembre 2011. []
  2. Cette technique permet de mettre sur un même plan les articles en texte intégral et ceux pour lesquels on ne dispose que des deux premiers paragraphes. []

Big Data Fail ?

La base de données GDELT (Global Database of Events, Language, and Tone), déjà mentionnée ici, donne enfin lieu à quelques analyses précises. Les résultats sont sans équivoque : la base, qui contient plusieurs millions d’articles sur toutes sortes d’événements à travers toute la planète, ne sert pas à grand chose pour le moment.

Les problèmes semblent moins venir des données elles-mêmes que de leur classification a posteriori. L’exemple du kidnapping géant par Boko Haram au Nigeria en mai dernier l’illustre très bien : l’événement a été géocodé à une quarantaine d’endroits différents, avec pour conséquence… le comptage d’autant d’événements différents.

Pas étonnant, du coup, que personne ne s’y retrouve, en particulier lorsque l’architecte de la base affirme que les caricatures danoises de Mahomet sont l’événement mondial le plus saillant sur les trente-cinq dernières années. La personnalité de l’architecte en question, qui a fait toutes sortes de déclarations grandiloquentes, y est peut-être aussi pour quelque chose, mais ce n’est qu’une supposition de ma part.

Cela ne condamne pas définitivement les données, mais jette un sérieux doute sur leur exploitation en l’état actuel de la base. On peut imaginer toutes sortes de rectifications (après tout, c’est l’intérêt d’avoir placé la base en accès ouvert), ou imaginer des réformes plus radicales, comme limiter la base à quelques sources bien choisies à l’entrée et espérer en tirer quelque chose de mieux structuré à la sortie—c’est la stratégie suivie par l’outil équivalent que possède le Department of Defense américain.

Mise à jour : les données de GDELT sont en large partie des données volées (sources : PSJR, Phil Schrodt). Le cheminement des données depuis leur vol est inconnu : les deux universitaires liés au projet n’ont jamais vu les données brutes, il est donc impossible de savoir ce qu’elles contiennent vraiment. Au moins une revue a déjà réagi. À ne pas utiliser.

Utiliser les résultats électoraux du ministère de l’intérieur

Toux ceux qui ont eu à utiliser un jour ou l’autre les fichiers de résultats électoraux diffusés par le ministère de l’Intérieur français savent que ceux-ci nécessitent un assez lourd travail de mise en forme afin d’être exploitables, en tout cas pour les élections pour lesquelles l’offre électorale n’est pas homogène sur le territoire (c’est-à-dire toutes sauf les présidentielles). En effet, les fichiers Excel diffusés par le ministère comprennent une ligne par territoire (commune, par exemple), et autant de colonnes que nécessaires pour mettre les résultats de tous les candidats. Il serait pourtant tellement simple de mettre le fichier en format « long », c’est-à-dire une ligne par combinaison territoire/candidat… Mais il faut croire que personne au ministère n’a jamais eu à lire un de leur fichier dans R ou un autre logiciel de statistiques (ou de cartographie). Au passage, on peut regretter que le site data.gouv ne demande ni même ne suggère à ses contributeurs de fournir les données en format tabulaire…

Quoi qu’il en soit, ceux qui ont à utiliser ces données ont généralement créé leurs petites routines pour traiter ces données. Sous Excel, le processus est particulièrement douloureux. Je me rappelle avoir fait planté des ordinateurs en faisant tourner des macros VBA…

Ayant eu à bricoler un script sous R pour importer ce genre de fichiers, j’ai décidé de le diffuser – ce qui a le mérite de m’obliger à le nettoyer un peu, et ce qui permettra, je l’espère, que d’autres l’améliorent. J’ai donc créé un tout petit package (il n’a qu’une fonction !) que j’ai mis sur mon compte Github.

Précision importante : le script, à l’heure actuelle, agrège les résultats en fonction des étiquettes attribuées par le ministère de l’Intérieur. C’est une limite importante, mais qui suffit à la plupart des utilisations courantes.

C’est une version 0.1 mais qui est fonctionnelle. À l’heure actuelle, traiter le fichier de résultat des européennes par communes (36762+ lignes, 227 colonnes) prend de l’ordre de cinq minutes sur un ordinateur de bureau classique. Ce n’est pas dramatique mais c’est un peu long. À l’avenir, je vais essayer d’accélérer cela – a priori en codant le cœur du script en C++, ce qui me forcera à m’y mettre. Mais peut-être d’autres auront-ils d’autres pistes – je ne suis pas sûr que mon algorithme soit optimal.

Sur ma todolist également : construire une application Shiny autour du package, pour que ceux qui n’utilisent pas R puissent quand même l’utiliser pour transformer leurs données.
Autre idée : permettre d’agréger les résultats autrement que par étiquette. C’est techniquement assez trivial, mais ça pose des problèmes de fond, du fait de l’hétérogénéité territoriale de l’offre électorale. Mais on pourrait imaginer la possibilité, par exemple, que l’utilisateur fournisse au script une sorte de « dictionnaire » associant les listes ou candidats à une nomenclature spécifique.

Je suis preneur en tout cas de tous les retours et suggestions des utilisateurs ! Et j’espère que ce sera utile à quelques uns !

Toutes les interventions plénières des eurodéputés, en 100 lignes (de code)

Mise à jour, juin 2015 : si ce billet vous intéresse, allez voir le travail de Derek Greene et James P. Cross, qui ont modélisé les documents décrits ci-dessous de manière plus fine que ce que j’avais codé.

Quelques notes tirées de trois conversations sur les sept derniers jours. C’était plus long à décrire qu’à coder.

Commençons par récupérer la liste des eurodéputés, en trois étapes :

  1. La source : l’index complet est disponible en une seule page, ce qui rend les choses faciles. Le zéro final de l’adresse est le numéro de législature ; il y en a 7 au total, et la dernière possède un index des députés un peu plus détaillé, que l’on utilisera peut-être un autre jour.
  2. La méthode : il y a quatre ans, on m’a fait découvrir XPath, qui est une syntaxe servant à sélectionner des éléments dans un document structuré. XPath, c’est un peu comme les expressions régulières, ou découvrir comment trafiquer un PDF sans laisser de traces dans les métadonnées : ça change la vie1.
  3. La syntaxe : le site Internet du Parlement européen est rédigé en HTML propre (car généré automatiquement), avec des éléments bien imbriqués les uns dans les autres : c’est le cas idéal. La source de l’index, consultable dans tout navigateur, donne la syntaxe exacte des éléments utilisés ci-dessous.

Illustration de l’explication ci-dessus :

Screen Shot 2014-05-19 at 9.26.24 PM

À présent, dans R :

  1. On souhaite juste sauvegarder un « annuaire » minimal des 3 000 et quelques eurodéputés, et le sauvegarder dans un fichier qui servira d’index général où chaque eurodéputé est identifiable par trois éléments : le nom complet, inutilisable car plein d’accents et non unique2, l’URL (l’adresse de sa page personnelle), et dans cette URL, un numéro, 4484 par exemple, qui servira d’identifiant unique plus tard.
  2. La fonction de téléchargement va lire la page HTML, en extraire les éléments pertinents à partir de sa structure, et renvoyer tout ça dans un jeu de données. On sauvegardera les données au format CSV, un format en texte simple qui sauvegardera correctement les accents dans les noms si l’on s’assure que le parser les lit en encodage UTF-8.
  3. Petite nuance : quand vous voulez extraire un lien, la syntaxe XPath vous le permet directement ; mais pour extraire le texte d’un lien, le truc sur lequel on clique pour aller au lien en question, il vous faut la « valeur XML », d’où la fonction xmlValue ci-dessous. Le reste du code demande surtout de se renseigner sur XPath, et ce n’est pas compliqué du tout, surtout si l’on apprend par essai-erreur.

Il va donc vous falloir installer puis charger les librairies (a.k.a packages, extensions, plugins, comme vous voulez) jsonlite, plyr et XML, et 20 lignes plus tard, vous avez tous les eurodéputés dans un fichier CSV.

Plus compliqué, obtenir toutes leurs interventions parlementaires :

  1. Sur la page de chaque eurodéputé (exemple), un lien fournit toutes les interventions en séance plénière (exemple). En lisant encore une fois la source de la page, on trouve le petit bout de Javascript qui génère cette information, et surtout l’URL qui renvoie cette information depuis la base de données utilisée en coulisses du site.
  2. L’information est au format JSON, pour lequel il y a non pas un, ni deux, mais trois packages R qui peuvent assurer la conversion vers le format classique des jeux de données R, data.frame. Jeroen Ooms m’a prouvé en cinq lignes que son package était le meilleur, et j’ai pu vérifier depuis qu’il a entièrement raison3.
  3. Les fonctions conditionnelles de type if else, qui permettent par exemple de ne rien faire si aucune donnée n’a été trouvée, servent à contrôler l’exécution du script. Le code ci-dessous contient deux autres structures apparentées, while et try. Quelques détails chiants si vous ne les utilisez pas fréquemment :
    • while est un itérateur habituellement moins préférable que for (ou, dans R, qu’une vectorisation de type *apply), mais qui marche très bien ici pour lister les interventions de chaque eurodéputé(e)4.
    • try permet de continuer l’exécution même si un problème de connexion Internet empêche ponctuellement de lire une page (erreurs 404, 502, 503… amusez-vous bien)5.

Voilà pour le détail, et 30 lignes plus tard, vous pouvez récupérer les interventions de n’importe quel eurodéputé dans n’importe quelle législature (1 à 7), en utilisant son numéro d’identifiant unique (id)6.

Ça se complique encore un peu mais on y est presque. Le workflow final est le suivant :

  1. Pour chaque eurodéputé dans l’index général, extraire le numéro d’identifiant unique de l’adresse de sa page Internet, puis aller chercher ses interventions publiques dans chacune des 7 législatures parlementaires. La partie « pour chaque député » est purement itérative (for), mais la partie « chacune des législatures » est vectorisée : on va de 1 à 7, et on applique à chaque fois la fonction get_cre de 20 lignes décrite plus haut. Le seul bénéfice avéré de la vectorisation dans ce cas réside dans l’économie d’accolades et de lignes de code à gérer.
  2. Il ne reste que les soucis de format. Le premier est très simple : la partie vectorisée du code renvoie une liste, que l’on va aplatir au format data.frame avec rbind.fill, la fonction la plus utile du monde après paste (si si). Enfin, dernier problème : les fichiers JSON utilisent des listes, mais vos jeux de données sont des tableaux (i.e. des matrices avec des attributs) qui utilisent des cellules. Une liste vide est NULL, alors qu’une cellule vide est NA : welcome to the R Inferno ! Heureusement, une fois le problème détecté, il se règle en une ligne, à appliquer à chaque colonne susceptible de contenir des listes/cellules nulles/vides afin de les « purger » — sinon, pas d’écriture possible au format CSV.
  3. Prévoir, dans quelques heures, environ 1700 fichiers de résultats (car tous les eurodéputés n’interviennent pas, loin de là), pour environ 90 MB d’espace disque. Cet exemple est très « léger » et relativement rapide, mais d’expérience, vous avez vraiment intérêt à toujours penser à la taille des résultats sur disque avant de faire quoi que ce soit — à moins d’avoir la trésorerie pour détruire un disque dur de temps à autre7.

Illustration de l’avertissement ci-dessus, tiré d’un autre projet dont les résultats des modélisations font plusieurs gigaoctets de plus que les données brutes, ce qui est logique quand on utilise des simulations ou, comme ici, un bootstrap :

Screen Shot 2014-05-16 at 1.39.12 PM

On termine en écrivant poliment le nombre d’eurodéputés restants à l’écran, et avec 20 lignes de plus, l’index général est mis à profit pour télécharger, dans un dossier records à créer préalablement, les métadonnées de tout ce que les eurodéputés ont raconté en séance plénière depuis qu’il y a des données disponibles, dans des fichiers nommés UID_cre.csvUID est l’identifiant unique de chaque eurodéputé.

Ça fait 100 lignes en tout, avec quelques trucs en plus.

Le résultat à l’écran ressemble à l’illustration ci-dessous, avec des pseudo-barres de progression quand il y a des fichiers en téléchargement (je montre une exécution avec les résultats déjà présents sur le disque, d’où les « 0 » jamais suivis des « 100, 200, 300… » correspondant au téléchargement de chaque page d’interventions). Le code est exécuté dans TextMate via son plugin R, (qui doit exister pour d’autres éditeurs comme SublimeText).

Screen Shot 2014-05-19 at 9.32.46 PM

Sans avoir regardé en détail, les données intégrales ne semblent concerner que les trois dernières législatures. Le même code peut aussi collecter les opinions prononcées en tant que rapporteur, les motions, les questions écrites etc. avec à peu près autant de facilité, et pour rajouter des variables aux eurodéputés eux-mêmes, il suffit d’extraire plus d’informations de leurs pages personnelles—mais cela dépasserait le temps que je voulais passer sur cet exercice.

Je termine en pensant aux vraies feignasses dans mon genre : le code et les données en une seule archive. Add. : et si ça vous intéresse, j’ai aussi un fichier CSV de 400 MB contenant toutes les interventions orales des eurodéputés au cours des législatures 5–7 (1999–2004, 2004–2009 et 2009-2014).

  1. Les métadonnées, c’est ce que la NSA sait sur vous et sur votre grand-mère. Ça sert aussi à détecter des trucs bizarres dans les copies d’étudiants, ou à savoir qui rédige vraiment les rapports publics que vous trouvez parfois dans la presse en ligne. []
  2. Ce menu détail rend les dernières données de VoteWatch inutiles pour cet exercice, mais voici quand même un guide à leur réutilisation avec R, en trois parties : un, deux, trois. []
  3. La vignette du package explique très bien pourquoi, et en pratique, c’est l’argument flatten = TRUE qui fait la moitié du boulot de virer les listes pour mettre des colonnes, histoire que le résultat ressemble moins à un flux qu’à un tableau de données. L’autre moitié du boulot prend une ligne, lire plus haut. []
  4. La variable idx est lue dans le fichier JSON et correspond à la pagination des interventions publiques, qui sont fournies par tranche de 100 interventions en partant de zéro, parce que Javascript compte à partir de zéro. Elle est égale à 100, 200, 300 ... tant qu’il reste des pages d’interventions publiques dans la pagination du site Internet, -1 quand on se trouve sur la dernière page d’interventions. La variable est directement égale à 0 quand il n’y a aucune intervention publique. []
  5. Vu le grand nombre de pages à couvrir, N eurodéputés * P pages d’environ 100 interventions, le script va nécessairement avoir quelques soucis : il faut le réexécuter quelques fois pour arriver à télécharger tout ce qui est possiblement téléchargeable. Je laisse de côté les fonctions de mise à jour, (il suffit d’effacer les fichiers-cibles en amont). []
  6. Par exemple, le président actuel du Parlement est codé 1911, donc la fonction get_cre(1911, 7) renvoie les interventions (nombreuses, car majoritairement procédurales) de son mandat en cours. []
  7. N’imaginez même pas essayer d’écrire les résultats sur une clé USB : ce n’est pas vraiment un support froid, et je garantis à 200% que tout essai sur une clé USB de plus de 8 GB aura pour seul effet de la rendre complètement et définitivement inutilisable. []

Derniers graphiques avant 2014

En faisant tourner à nouveau les scripts de réseaux législatifs dont j’ai déjà parlé plusieurs fois ici, j’ai pu vérifier les résultats précédents sur des données un peu plus propres (merci Regards Citoyens) et étendues à tous les amendements de l’année qui se termine :

Screen Shot 2013-12-30 at 7.55.26 AM

Mais j’ai aussi pu vérifier (cf. la fin de cette note) que l’Assemblée nationale doit s’apprêter à réorganiser son site Internet : entre juillet et décembre 2013, l’index des amendements déposés sous la 13e législature a diminué de 450 à 250 dossiers, et j’ai vérifié, plusieurs d’entre eux sont tout à fait valides (ce n’est pas une correction attribuable à des problèmes de datation, par exemple).

En attendant que ce mystère s’éclaircisse, voici la tête des données actualisées. Les barres grises comptent les amendements individuels, les barres rouges les amendements co-signés à moins de dix, et les barres bleues les amendements co-signés par plus de dix députés, avec des pics de co-signatures vers 200 sur les lois de finance et autres joyeusetés. Le pic gris monstrueux correspond au mariage pour tous.

amendments_sponsors

Je vous épargne un graphique de réseau en plus. Non, je déconne, voici un dernier réseau législatif de l’année, basé sur presque 40 000 amendements déjà co-signés sur la législature en cours. Il me reste à calculer les mesures de centralité et de modularité en tenant compte de la pondération du réseau — c’est en cours.

network.example

Meilleurs voeux !