Hypothesosphère : le réseau des blogs d’Hypothèses, (presque) cinq ans plus tard

Il y a quelques années (en décembre 2010, pour être précis), Josquin Debaz avait rédigé un billet sur le réseau des blogs de la plateforme Hypothèses, “Hypothesosphère”, où il reconstituait le réseau des blogs indexés par la plateforme à partir des hyperliens entre les articles de ces blogs. Je me suis demandé si ça ne valait pas le coup d’actualiser son analyse, en récoltant des données permettant d’assembler ce réseau à différents points temporels, puis d’identifier les thèmes traités par les communautés qui forment ce réseau.

Le résultat montre qu’environ un tiers des blogs de la plateforme Hypothèses a, au moins une fois, renvoyé ses lecteurs vers un autre blog de la plateforme. Au cours des années 2009 à 2015, la plateforme s’est enrichie de nombreux blogs, ce qui donne, même lorsque l’on se concentre sur un échantillon de ces blogs, comme ci-dessous, un réseau qui contient de nombreuses “sous-communautés” (linguistiques, notamment), et quelques blogs (dont Polit’bistro !) nettement plus centraux que les autres :

hyponet

Cliquer le graphe ci-dessus pour la version PDF plus lisible, où l’on aperçoit clairement le blog des concepteurs de la plateforme (en plein milieu), ainsi que la partie germanophone d’Hypothèses (au sud). Ci-dessous, une longue notice technique, avec une visualisation temporelle du réseau à chaque année d’existence de la plateforme, et une modélisation des thématiques abordées dans les billets de chacune des communautés au fil du temps.

Échantillonnage des données

Depuis le billet de Josquin Debaz, l’index d’Hypothèses s’est beaucoup enrichi, et a aussi certainement changé au niveau du code, car les “vieux” billets (ceux de la page 300, par exemple) n’y sont pas indexés comme les nouveaux. Du coup, pour actualiser l’Hypothesosphère, mieux vaut peut-être passer par le catalogue OpenEdition, qui recense actuellement 1 071 blogs dont on peut ensuite récupérer les articles :

openedition-catalogue

Pour effectuer cette dernière opération, j’ai simplement essayé de lire chaque “page” de chaque blog, de la première à la dernière. Certains blogs, comme celui-ci par exemple, n’utilisent pas de pagination (ce que l’on peut raisonnablement considérer comme un événement survenant de manière aléatoire parmi les blogs de la plateforme), et sont en conséquence exclus de l’échantillon que l’on va constituer1.

Dans un premier temps, il faut donc lister les blogs et essayer de lister tous leurs articles. En une demi-heure d’essais-erreurs avec le code HTML des blogs, qui tournent tous sur WordPress mais pas avec les mêmes gabarits et donc avec des balises HTML différentes, j’en suis arrivé à ce script, qui est certainement plus lent que celui qu’a rédigé Josquin Debaz (en Python), mais qui fonctionne suffisamment bien sur la plateforme Hypothèses actuelle.

Le résultat est un échantillon qui contient 622 blogs, soit 60 % du catalogue total d’OpenEdition, et un total de 77 608 articles, soit 124 articles par blog en moyenne2. Si l’on compare les années de création des blogs du catalogue OpenEdition à celles des blogs contenus dans l’échantillon, les différences de proportion de chaque année à l’intérieur de chaque groupe sont minimes et aléatoires, ce qui est plutôt bon signe pour la qualité de l’échantillon.

Année Catalogue % Échantillon %
2009 76 7 65 10
2010 81 8 61 10
2011 138 13 78 13
2012 282 26 149 24
2013 233 22 118 19
2014 126 12 61 10
2015 133 12 88 14

Construction des réseaux temporels

Dans un second temps, il faut ensuite scanner le contenu des articles des blogs sélectionnés, et en extraire les liens vers des adresses de blogs hébergés sur Hypothèses. Alors que l’opération précédente n’a pas demandé plus de quelques heures, celle-ci risquait de prendre beaucoup plus longtemps, étant donné la quantité de données à parcourir. Du coup, j’ai à nouveau échantillonné dans les données, en ne téléchargeant que 25% des 77 608 articles, soit 19 402 articles3.

Vu que l’on va vouloir observer la manière dont l’Hypothesesosphère a changé au cours du temps, on va ensuite scanner ces articles pour y trouver les inter-citations entre blogs, en notant également la date de parution des articles et le nombre d’inter-citations par article, qui pourra faire office de coefficient de pondération si besoin. Je ne vais pas jusqu’à sous-échantillonner pour limiter le nombre d’articles par blog, mais c’est envisageable4.

Enfin, on va écrire le code de visualisation de l’Hypothesesosphère de chaque année, en mettant des couleurs sur les huit “communautés” de blogs les plus larges, que l’on identifie grâce à un algorithme qui maximise la modularité (le degré de ségrégation) du réseau. Le code ressemble fortement à ce que j’ai déjà décrit dans plusieurs billets précédents, et notamment dans ce petit tutoriel, qui couvre aussi la récupération des données.

Ci-dessous, un exemple de visualisation produit par ce code. Je dis “exemple” car le placement des blogs est en partie aléatoire, comme l’exige n’importe quel algorithme de placement à force dirigée. À noter aussi : la visualisation ne montre pas que le réseau est dirigé, mais il suffit de faire attention à la couleur des liens pour la deviner (lorsque les liens sont plus foncés, c’est qu’ils sont réciproques : les blogs se font mutuellement référence).

hyponet

Pour obtenir un résultat plus exhaustif, il suffit d’augmenter le seuil précité de 25%, ce qui permettra de scanner un plus grand nombre d’articles, et donc potentiellement de rendre l’Hypothesesosphère de chaque année un peu plus dense. Le seuil que j’ai choisi devrait toutefois suffire pour se faire une première idée de ce à quoi ressemble le réseau complet des inter-citations entre les blogs de la plateforme.

Modélisation des communautés

Les réseaux présentés ci-dessus contiennent des blogs, liés entre eux par des articles. Chacun de ces articles contient des mots-clés, ou a minima une catégorie qui correspond, elle-même, à un mot-clé. La plupart des mots-clés sont en français, sauf dans les sous-communautés linguistiques d’Hypothèses, qui utilisent des mots-clés, en allemand, en anglais, en espagnol.

De plus, on a segmenté chaque réseau de manière algorithmique, en communautés optimales. Par conséquent, il est facile de créer des groupes de mots-clés correspondant à une communauté de blogs connectés par leurs inter-citations, ce qui est ici une manière de passer de la forme “réseau” à la forme textuelle en intégrant l’information structurelle du réseau dans la constitution du corpus textuel.

On va donc représenter les données de nos réseaux temporels sous la forme d’un corpus, où chaque document correspond aux mots-clés d’une communauté. Le corpus produit par cette opération contient autant de documents que n’apparaissent de communautés au fil des sept années d’existence de la plateforme, soit un corpus de 127 documents : 3 pour 2009, 7 pour 2010, jusqu’à 29 documents pour 2015.

On peut nettoyer des documents de manière approximative, en nettoyant les termes comme s’ils étaient tous français—ce qui n’est pas très grave : la langue va, quoique l’on fasse, fortement discriminer les communautés de blogs non francophones. Et enfin, on envoie ces documents à un topic model structurel, qui, un peu comme dans cet exemple, prend en compte l’année et la communauté de chaque document5.

Le résultat de cette opération sera un certain nombre de “thèmes” traités par les sous-communautés d’Hypothèses, identifiés à partir de quelque chose qui se rapproche d’un modèle multi-niveaux quant au type d’information qu’on fournit à l’estimateur. Le nombre de thèmes identifiés est arbitraire : j’ai choisi d’en identifier 20, un chiffre proche du nombre moyen de communautés identifiées dans chacun des réseaux (18)6.

Résultats : les thèmes de l’Hypothesesosphère

Dans les résultats ci-dessous, chaque ligne correspond à un regroupement thématique, ordonné du plus au moins fréquent dans le corpus, et représenté par ses trois premiers mots-clés (sans les suffixes, qui ont sauté au nettoyage). On aperçoit les thèmes constitués autour des billets en langue allemande, ou ceux créés autour de zones géographiques (“chin” ou “arab”) :

hypotopics

On aperçoit aussi, dans les thèmes, certains sujets bien précis : “polit” et “scienc”, par exemple, dans le thème n°2, correspond au séminaire “Politique des Sciences” de l’EHESS. Ce dernier constat est un peu embêtant : concrètement, le modèle que l’on a utilisé a “sur-identifié” certains sujets, plutôt que d’identifier des thèmes réellement transverses au corpus.

Le modèle fournit une probabilité d’occurrence de chaque thème dans chaque document, ce qui permet de connecter les thèmes entre eux en corrélant ces probabilités. On obtient ainsi, pour terminer, le réseau de thèmes suivants, où les couleurs correspondent à nouveau aux communautés optimales, et où l’on aperçoit distinctement l’espace thématique germanophone de la plateforme Hypothèses, de même que les thèmes les plus génériques (“actualités”, “lectures”, “colloques”, …) :

hyponet_topics

Pour améliorer cette visualisation, il faudrait déjà envisager d’augmenter l’échantillon des articles au-delà des 25% précités. Ensuite, il faudrait réfléchir à un découpage temporel plus intelligent que celui proposé ici. En effet, segmenter l’Hypothesesosphère par année civile n’est probablement pas très pertinent : on pourrait essayer d’utiliser plutôt les années universitaires, ou même un découpage plus fin se rapprochant des semestres.

Enfin, et surtout, une modélisation plus robuste des thèmes de l’Hypothesesosphère nécessiterait d’affiner trois des paramètres de la modélisation proposée ci-dessus : (1) le nettoyage des mots-clés en fonction de leur langue, (2) le nombre de thèmes à identifier, et (3) l’identification des thèmes, de manière à jouer à la fois sur la prévalence et le contenu des termes du corpus, comme l’explique la documentation du package stm :

stm-metadata

Ces améliorations demanderaient de passer plus de temps sur la collecte des données et sur le calibrage du modèle. Avis aux intéressé(e)s !

Pour aller plus loin

Ce billet explique comment actualiser les données initialement imaginées par Josquin Debaz, et suggère de modéliser ces données à mi-chemin entre l’analyse de réseaux et l’analyse textuelle. Ce croisement méthodologique est assez fréquent : voir, par exemple, ce papier récemment présenté au Congrès de l’AFSP, qui étudie la “web-sphère” créée autour du hashtag #CharlieHebdo sur Twitter.

Quelques liens, donc, pour terminer.

Pour reproduire l’analyse, allez voir ce dossier, qui inclut la liste des blogs à partir de laquelle on a constitué l’échantillon, et l’exemple de corpus sur lequel on a travaillé pour ce billet. Le code n’est pas particulièrement compliqué, et il est facilement amendable (on pourrait, par exemple, étudier le réseau bipartite des blogs d’Hypothèses citant des articles publiés sur revues.org).

Pour analyser du texte, la méthode que j’ai employée (et que j’avais déjà évoquée ici et , notamment) n’est pas la plus simple, ni même la plus conclusive. Pour des alternatives aux topic models, cf. notamment les méthodes de classification hiérarchiques implémentées par Iramuteq, ainsi que ce billet d’Étienne, qui explique clairement ce qu’est un topic model et qui recense d’autres autres méthodes disponibles.

Pour visualiser des réseaux, je passe systématiquement par la fonction ggnet (voir le billet de présentation et d’autres exemples), mais vous voudrez peut-être passer par igraph (qui vient de passer en version 1.0.0 ! et le bouquin a l’air génial), ou par une librairie permettant de visualiser le réseau par périodes. Dans ces deux cas, jetez un coup d’oeil à cet excellent tutoriel de visualisation réseau, par Katherine Ognyanova.

Pour illustrer ce que l’on peut apprendre en lisant le tutoriel ci-dessus, voici un dernier graphe, qui montre la croissance cumulée de l’Hypothesesosphère, de janvier 2009 à juin 2015. Si vous utilisez Google Chrome, vous pouvez également jouer avec la version interactive, réalisée avec le package (encore très expérimental) ndtv, que j’ai découvert grâce au tutoriel.

hypodyn

Contrairement aux autres graphes du billet, ces deux animations utilisent un échantillon beaucoup plus large de presque 85 000 billets publiés sur la plateforme, au fil desquels 340 blogs ont renvoyé leurs lecteurs vers 484 blogs, pour un total de 605 blogs différents actuellement présents dans l’Hypothesesosphère.

  1. Le meilleur moyen de travailler sur l’intégralité de la base serait bien sûr de l’obtenir auprès de la plateforme (à laquelle je contribue très épisodiquement), mais le texte intégral pèse certainement trop lourd pour pouvoir être facilement transféré. De plus, la base intégrale doit contenir les brouillons des articles des blogs, ou ceux publiés de manière privée. Pour ne pas rentrer dans ces problèmes, je n’ai accédé qu’aux données publiques de la plateforme. []
  2. En relançant le script plusieurs fois pour pallier aux erreurs réseau, je suis arrivé jusqu’à 885 blogs et 104 844 articles, soit 118 articles par blog en moyenne. []
  3. Il est fortement recommandé, à ce stade, de laisser une seconde entre chaque téléchargement, pour ne pas stresser la plateforme. []
  4. Cette étape serait nécessaire si l’on souhaitait contrôler (éliminer) les différences de volume de publication d’une année sur l’autre, de manière comparer des probabilités d’occurrence (ou plutôt, des écarts par rapport à une hypothèse d’équiprobabilité, qui peut s’estimer de différentes manières) dans chacun des réseaux temporels. []
  5. Très grossièrement, un topic model structurel est un topic model (soit une technique de regroupement de termes discriminants en thèmes, ou topics) qui peut prendre en compte de l’information supplémentaire sur les documents (des “méta-données”, comme ici l’année de “parution” du document formé par les mots-clés, et la communauté qui a “produit” ce document cette année-là, au fil de ses billets de blogs). Pour des exemples de topic models, cf. cette synthèse, cet article, et ce projet, sur le même thème que ce billet. []
  6. À noter : il y a de plusieurs manières d’identifier le nombre de thèmes à rechercher dans un corpus. Certaines d’entre elles sont expliquées dans les documents cités dans la note précédente. []

Les “unes” de Charlie Hebdo : quelques réseaux de plus

Le 6e Congrès de l’Association Française de Sociologie commence après-demain. Le Réseau Thématique 37 “Sociologie des médias” y organise une réunion autour des événements “Charlie Hebdo”, à laquelle Gaël devait participer, sans finalement pouvoir s’y rendre. Sur son invitation, je le remplacerai pour évoquer cette petite note, qui reprend une partie de ce que vous avez pu lire sur ce blog au sujet des “unes” de Charlie Hebdo et de l’analyse des associations thématiques qu’elles contiennent.

La note ne procède pas tout à fait de la même manière que les billets du blog. J’ai retiré tout ce qui avait trait aux ERGM pour utiliser quelque chose d’un peu moins sophistiqué mais de tout aussi parlant. Dans un premier temps, j’ai affiné les catégories thématiques dans lesquelles j’ai regroupé les mots-clés utilisés par le blog Strips Journal pour coder les “unes” de Charlie Hebdo. L’échantillon reste très réduit : le blog ne couvre que les années 2009 à 2015, soit un peu plus de 300 “unes”.

J’ai ensuite fait figurer ces “unes” dans des réseaux bipartites où apparaissent à la fois les “unes” et leurs catégories thématiques. Voici par exemple le réseau des “unes” et de leurs thèmes pour l’année 2011 (cliquer sur le réseau pour le voir en plus grand) :

themes_network_2011

La topologie du réseau renvoie aux deux grands pôles thématiques traités par Charlie Hebdo dans ses “unes”, avec l’actualité politique nationale d’un côté (catégories en bleu), et tous les autres thèmes de l’autre, dont l’actualité internationale et la religion. Cette représentation permet d’effectuer des calculs de distance pondérée, à partir il est facile de repérer les catégories thématiques “proches” ou “éloignées” dans le réseau tissé par les “unes”. Voici les distances entre les catégories thématiques de l’année 2011 (cliquer…) :

distance_matrix_2011

La matrice de distance traduit la même information que le réseau : les catégories les plus “proches” de la catégorie “Religion” sont les catégories “Violence” et “International”, dans cet ordre. La note systématise cette grille de lecture à toutes les catégories sur toutes les années de 2009 à 2015, où il apparaît clairement que la catégorie “Religion” est régulièrement associée à la catégorie “Violence”, sans entretenir toutefois de lien privilégié avec cette catégorie, qui est également associée à d’autres thématiques que la religion.

Bref, je ne sais toujours pas si Charlie Hebdo est “obsédé” par l’islam, si tant est que cela veuille dire quelque chose1. En revanche, je pense qu’on peut établir, au moyen de ses “unes”, que Charlie Hebdo ne réserve pas ses critiques qu’à la seule institution religieuse—sur la période étudiée, le personnel politique en prend au moins autant, sinon plus, pour son grade—,et qu’en plus, sa critique de la religion en “une” survient au sein d’une “triade thématique”, où elle se retrouve liée, sans grande surprise, à l’actualité internationale.

Si vous êtes à l’UVSQ après-demain, j’aurai quelques minutes pour expliquer tout ça. Et comme je n’ai jamais mis les pieds dans un Congrès AFS, ce sera l’occasion de voir à quoi ça ressemble.

Dernière petite chose. Dans le billet précédent, je terminais en mentionnant le blog elementR, pour apprendre à utiliser R dans un contexte de recherche en sciences sociales. En ce qui concerne les réseaux, il faut cette fois-ci mentionner l’excellent blog du groupe fmr (“flux, matrices, réseaux”), qui publie depuis longtemps de très bonnes ressources pour apprendre l’analyse de réseaux, avec R ou d’autres logiciels (voir, par exemple, ce texte sur les ERGM, que j’aurais dû citer dans plusieurs billets précédents sur les “unes” de Charlie Hebdo).

  1. Comme Gaël, et comme les auteurs de cette tribune, j’aurais plutôt tendance à penser que non, même si la “une” me semble être un bon dispositif de mesure des orientations stratégiques que peut prendre la direction d’un hebdomadaire. Il faudrait néanmoins avoir accès à d’autres données (qualitatives), ainsi qu’à un échantillon de “unes” s’étalant sur une période plus longue, pour pouvoir étudier cette question, un peu sur le modèle de ce qu’a fait Nicolas Hubé sur la presse allemande et française. []

Comment ne pas parler des livres que l’on n’a pas lus

Écouter France Culture est un régal quotidien, et s’il ne fallait garder qu’une émission, ce serait évidemment Les pieds sur terre. Mais parfois, on y entend aussi des choses comme ça, dans la bouche de Vincent Ricordeau, co-fondateur de la plateforme collaborative KissKissBankBank :

Aujourd’hui après avoir encensé Piketty, on massacre Piketty, puisqu’il y a des étudiants, certains très jeunes, qui ont prouvé que ses bases de données, la façon dont il gérait les data, arrivait à des résultats qui étaient erronés.

Derrière Piketty, ce n’est pas ses formules mathématiques qui comptent pour arriver à prouver une chose. Il a montré assez clairement, et on a besoin de ça, que le système dans lequel on vit aujourd’hui, c’est-à-dire vers une maximisation du profit et une individualisation du profit, fait que ça crée des inégalités tellement dingues qu’on est revenu au même niveau qu’au XIXe siècle, et que potentiellement notre civilisation disparaîtra à cause de ça.

Donc du coup les mille pages de Piketty, qui sont très difficiles à lire d’ailleurs, n’ont de valeur pour moi que parce qu’elles montrent une direction. Si vous prenez Rifkin, également, […]

Les passages en gras sont de mon fait. S’ensuit le même style d’argument sur Rifkin. Allez écouter par vous-même, à la 21e minute environ du podcast de la dernière émission du sinon excellent Grain à moudre d’Hervé Gardette, qui conclut l’intervention de Vincent Ricordeau par ce propos laconique :

En général, quand on est critiqué, c’est aussi peut-être un signe de succès.

Avant de continuer, full disclosure : je ne connais aucun des protagonistes cités dans ce billet, et je n’ai pas lu le dernier ouvrage de Piketty. En revanche, j’ai pas mal manipulé les données Piketty/Saez, que j’ai souvent utilisées en cours, et j’ai lu quelques-uns des articles où elles apparaissent.

Enfin, il y a plusieurs années, j’ai écrit à Thomas Piketty pour lui demander quelques-unes de ses séries temporelles supplémentaires. Voici sa réponse (qui ne trahit rien de personnel : l’adresse email apparaissait sur son site Internet) :

piketty-email

Sur la forme, l’email ci-dessus n’est pas vraiment le genre d’email que l’on reçoit de la part de quelqu’un qui ne saurait pas “gérer ses data” ; c’est même plutôt l’inverse, Thomas Piketty étant l’un des rares chercheurs à diffuser publiquement et gratuitement la quasi-intégralité de ses données.

Mais sur le fond, il y a plein d’autres inepties dans le propos de Vincent Ricordeau, qui fait au passage la même erreur que de très nombreux commentateurs de Piketty, en lui attribuant la paternité intégrale des données utilisées dans Le capital au XXIe siècle. En réalité, comme l’indiquent plusieurs notes de bas-de-page, certaines sections de l’ouvrage utilisent les données WTID/WWID, qui ont mobilisé des dizaines de chercheurs1.

Histoire d’illustrer le fait que Piketty ne fait vraiment pas secret de la production collective des données présentées dans son ouvrage, écoutez les dix premières minutes de cette présentation, qui ne fait pas exception (j’ai trouvé plein d’autres podcasts où Piketty raconte strictement la même chose sur la nature collective des données de l’ouvrage, en citant d’ailleurs toujours les mêmes collègues, dans le même ordre) :

Le début du propos est peut-être le plus censé : effectivement, l’ouvrage de Piketty a été critiqué, notamment par un jeune économiste de 26 ans. Sauf que la critique en question ne porte à aucun moment sur la manière dont Piketty “gère ses data”, qui s’en sortent parfaitement indemnes2.

À ma connaissance, la seule critique de Piketty qui a porté directement sur les données est celle de Chris Giles (du Financial Times), et qui s’est à mon sens complètement trompé, alors qu’il avait correctement diagnostiqué les problèmes d’un modèle publié par le FMI dans un rapport de 2012.

Le plus drôle dans l’intervention de Ricordeau, c’est évidemment l’énorme “smoking gun” que j’ai grassé dans le dernier paragraphe : apparemment, dans la bouche de quelqu’un qui parle comme s’il avait lu l’ouvrage, les “mille pages” du Capital au XXIe sont “très difficiles à lire”.

Notez que juste avant, le même intervenant parle de formules mathématiques. Voici l’index de l’entrée “équations” dans l’édition américaine de l’ouvrage, avec les équations soulignées :

piketty-equations

L’équation la plus compliquée étant un produit, on peut supposer que ce n’est pas la formalisation mathématique de Piketty qui lui vaut ici le qualificatif de “très difficile à lire”. Ce doit donc être le texte lui-même. Voici donc un extrait pris au hasard dans l’édition française de l’ouvrage :

piketty-bouquin-1

Pas convaincu ? J’ai arbitrairement sélectionné cet extrait ? L’intervention de Vincent Ricordeau se situant à environ 21:30 du podcast de l’émission, voici la page 231 de la version électronique de l’ouvrage :

piketty-bouquin-2

Si vous avez déjà lu de l’économie, ne serait-ce qu’un papier NBER, le contraste devrait être saisissant. Et si vous n’en avez jamais lu, le texte devrait quand même vous indiquer quelque chose que presque tous les compte-rendus de lecture de Piketty indiquent par ailleurs : c’est très bien, et surtout très simplement, écrit3.

De mon point de vue, le seul obstacle sérieux à la lecture du dernier ouvrage Piketty est la longueur du manuscrit, qui est un peu plus court en langue anglaise (dans une traduction sublime d’Arthur Goldhammer), mais qui reste long.

Sur tous les autres points soulevés par Vincent Ricordeau, j’ai surtout eu l’impression qu’il avait autant lu l’ouvrage que moi, qui l’ai acheté mais pas lu, et j’imagine qu’une partie des auditeurs de l’émission a dû se dire exactement la même chose. Peut-être ferait-il mieux de se tourner vers un ouvrage plus court.

  1. L’équipe WTID/WWID inclut notamment Tony Atkinson. []
  2. La critique de Rognlie consiste, en gros, à rajouter un diviseur sur certaines mesures centrales, et à décomposer certains résultats. Il obtient, comme d’autres, des effets parfois plus faibles que ceux rapportés par Piketty, et un effet majeur du secteur immobilier, dont il tire une critique que je n’ai pas la compétence d’évaluer. Piketty a répondu à ce type de critiques dans plusieurs revues ; pour un excellent numéro spécial dans ce style, cf. celui-ci, en sociologie. []
  3. Piketty a expliqué plusieurs fois avoir écrit son livre pour un large public, en insistant sur le fait qu’il se sent moins économiste que chercheurs en sciences sociales, et que du coup. Si j’ai bien compris son parcours, qui passe par le MIT, il doit bien maîtriser les équations DGSE, mais écrire des modèles complètement abstraits ne l’intéresse pas. Une partie des réactions à l’ouvrage de Piketty s’explique d’ailleurs à mon sens par cette distance à la formalisation, mais il y a d’autres facteurs à considérer. []

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 !

Un modèle spatial de l’espace partisan sur Twitter

Note : ce billet est une version modifiée du billet publié le 17 avril. Les résultats sont à jour de la présentation que nous en avons fait, avec Ewen, à la journée d’étude “Science Po Quanti” qui s’est tenue hier. Si le fond du truc vous intéresse et/ou que vous avez un accès à l’API REST de Twitter dont vous ne vous servez pas, faîtes signe dans les commentaires, ou envoyez un tweet à @phnk ou @3wen (ou les deux).

Rappel des faits

Fin mars, j’ai rapidement expliqué comment utiliser les “followers” des comptes Twitter de la classe politique pour en positionner les différentes personnalités les unes par rapport aux autres. En partant du principe que Marine Le Pen va avoir plusieurs “followers” en commun avec Éric Ciotti, quelques-uns avec Valérie Pécresse, mais beaucoup moins avec François Hollande et encore moins avec Pierre Larrouturou, on peut reconstituer l’équivalent d’un spectre gauche-droite où la seule information de départ est la liste des “followers” de chaque personnalité, et où le résultat final est un positionnement sur une échelle unidimensionnelle allant de gauche à droite1.

Cette méthodologie, dite d’estimation de positions idéales, est bien connue en science politique : il s’agit, fondamentalement, d’identifier la dimension principale d’un espace latent, à partir d’une variable binaire comme un vote positif ou négatif. Cette méthode est généralement appliquée aux parlementaires à partir de leurs votes sur les scrutins publics, mais il y a plusieurs autres applications connues : à partir du moment où l’on dispose de votes publics, on peut par exemple s’en servir sur les décisions des juges de la Cour Suprême, ou sur les votes des pays membres des Nations Unies.

L’originalité de l’approche de Barberá (version gratuite), que j’ai déjà cité abondamment dans le billet précédent, est d’avoir transposé cette méthodologie à Twitter2, et de l’avoir appliquée avec succès aux États-Unis et à cinq pays européens. En regardant son fil Twitter récent, j’ai pu constater que sa méthodologie fonctionne également assez bien sur des personnalités politiques brésiliennes, et plusieurs papiers publiés (version gratuite) ou en cours de publication s’apprêtent à montrer que cela marche bien aussi dans d’autres contextes, y compris au-delà des frontières nationales (à suivre…).

Qu’en est-il des personnalités politiques françaises ?

Bon, notez bien que tout ce qui suit est un résultat préliminaire, car le modèle n’a pas fini de converger, malgré la très bonne machine sur laquelle Ewen est en train de le faire tourner. Vous avez bien noté la nature préliminaire des résultats ? Go :

ideal_points_parties

Le graphique ci-dessus correspond au modèle #1 de Barberá, appliqué à 418 personnalités politiques françaises, qui correspondent aux “n” en bas du graphique. Les barres verticales indiquent les positions minimales et maximales pour chaque parti, et le cercle indique la moyenne. Pour le moment, l’échantillon de “followers informatifs” est légèrement inférieur à 18 000. Pour revoir le tout premier résultat obtenu sur un échantillon encore plus petit, cliquer ici, et pour les résultats finaux sur 721 personnalités politiques, attendez encore quelques semaines. Le code de réplication (en cours d’amélioration) et la liste complète des personnalités politiques sont déjà en ligne3.

Sur le graphique, les petites croix correspondent aux scores gauche-droite des partis selon la moyenne établie par ParlGov, ce qui permet de comparer nos résultats aux mesures conventionnelles du positionnement de ces partis. Comme on peut déjà le voir, ça commence bien : “l’ordre” des partis politiques est presque celui attendu. En d’autres termes, les individus qui suivent les personnalités politiques françaises sur Twitter permettent de reconstituer l’espace partisan gauche-droite de ces personnalités de manière quasi-identique à ce que produisent des enquêtes d’experts comme la Chapel Hill Expert Survey, qui va néanmoins plus loin que cette seule dimension.

Vers quoi se dirige-t-on ?

Ce billet ne fait que résumer à très grands traits la méthode que nous sommes en train d’appliquer avec Ewen pour obtenir des estimations de points idéaux à partir de données issues de Twitter. Le point de départ de cette entreprise était un défi d’ordre strictement méthodologique : peut-on faire pareil, avec nos propres données, sur une matrice (d’adjacence) plus large, et en comprenant, à peu près, ce que l’on fait subir à cette pauvre matrice, par l’intermédiaire d’une modélisation assez compliquée ?

Les résultats finaux sont en cours de calcul, mais les résultats intermédiaires ont encourageants, et le code nous a d’ores et déjà permis de produire toutes sortes de résultats supplémentaires assez originaux. Le graphique présenté ci-dessus n’est que le point de départ de ces résultats : toute une batterie de tests montre des corrélations intéressantes au niveau géographique, par exemple. Voici un exemple de ces corrélations, qui se situent toutes entre 0.4 et 0.5 :

map_vote

Le panel de gauche montre le point idéal moyen des départements, calculé à partir des “followers informatifs” que l’on a réussi à localiser au niveau départemental ou municipal. Le panel de droite donne la carte du vote Sarkozy au second tour de la présidentielle de 2012. La corrélation est à 0.5, ce qui permet simplement de constater que les positions idéales générées par le modèle ne sont pas complètement décorrélées des comportement électoraux au niveau géographique.

Vous l’avez compris en lisant le paragraphe précédent : le modèle que l’on utilise n’estime pas des points idéaux que pour les seules personnalités politiques, mais aussi pour les “followers informatifs” que l’on y inclut (ce que ne produit pas vraiment une estimation “classique” de points idéaux à partir de données comme les votes parlementaires). Je n’ai pas évoqué cette spécificité du modèle jusqu’à présent, mais cela vous donne une petite idée de ce vers quoi se dirige l’analyse.

  1. Concrètement, la seule hypothèse nécessaire est celle d’une homophilie entre les personnalités politiques et leurs “followers”, ce qui s’établit sans difficulté quand on parle de plusieurs milliers de “followers” par personnalité. La raison pour laquelle on tombe sur un axe gauche/droite est qu’il s’agit de la dimension principale la plus forte (le clivage le plus fort). []
  2. Je comprends cette transposition comme un renversement de la proposition habituelle des modèles existants : en termes strictement utilitaristes, au lieu de considérer les votes comme “l’offre” et les personnalités politiques comme “la demande”, on considère les comptes Twitter de personnalités politiques comme constituant “l’offre”, et la liste des “followers” comme “la demande”. []
  3. Comme l’indiquent les différents totaux cités, le modèle repose sur une stratégie de sous-échantillonnage assez difficile à résumer en quelques mots. Pour indication, le nombre de “followers informatifs” sur lequel tourne actuellement le modèle final est légèrement supérieur à 44 000, après application de tous les critères cités dans le papier de Barberá. []

Les réseaux de cosignatures législatives de quinze pays européens

Si la série de billets “Charlie Hebdo” vous a plu, voici quelques réseaux en plus. Add. Et si ce billet vous a plu, la base de données et les visualisations interactives comptent désormais 24 chambres parlementaires de 18 pays européens (les trois nouveaux pays sont l’Irlande, le Portugal et la Slovakie).

Vous vous souvenez peut-être de ce premier travail, dont j’avais parlé courant 2014, sur les réseaux des cosignatures de propositions de loi et d’amendements à l’Assemblée nationale. L’idée venait de Baptiste Coulmont.

La présentation de ce travail en conférence était plutôt bien passée. À cette époque, j’avais déjà rajouté les réseaux de cosignatures du Sénat, très faciles à construire grâce à son portail open data.

À l’occasion d’une summer school avec piscine et sauna (si si), j’ai ensuite élargi l’assiette empirique à six pays européens. Puis j’ai fait le tour de tous les pays membres de l’Union européenne et de l’AELE1.

Ce qui m’amène à la base de données actuelle : j’ai fini par assembler 100 réseaux de cosignatures législatives dans 19 chambres parlementaires de 15 pays européens. Voici un texte qui les présente rapidement2.

Les réseaux sont limités aux propositions de loi, mais cette limite permet de remonter plus loin dans le temps, sur une base plus comparable. Le code est aussi beaucoup moins dégueulasse que le code initial pour la France.

Voici par exemple l’exemple l’Islande actuelle :

net_is2013-2017

Ou encore l’Italie actuelle (chambre basse) :

net_it_ca17

Ou encore la République tchèque actuelle :

net_cz7

Et enfin, voici un tableau récapitulatif des pays et des chambres parlementaires couvertes. Les liens “plots” amènent aux représentations graphiques statiques, les liens “viz” aux visualisations interactives. Amusez-vous bien.

Pays / Chambre
Austria (chambre basse) code plots viz
Belgium (deux chambres) code plots viz
Bulgarie code plots viz
République tchèque (chambre basse) code plots viz
Danemark code plots viz
Finlande code plots viz
France (deux chambres) code plots viz
Hongrie code plots viz
Islande code plots viz
Italie (deux chambres) code plots viz
Lithuanie code plots viz
Norvège code plots viz
Roumanie (deux chambres) code plots viz
Suède code plots viz
Suisse (chambre basse) code plots viz

Le code contient des fonctions facilement réutilisables pour construire d’autres réseaux, et certains pays peuvent encore être rajoutés, à condition de trouver un moyen de récupérer les données (ce qui est parfois assez compliqué).

Si vous vous demandez à quoi peuvent servir ces réseaux, jetez un coup d’oeil au texte précité, ou au papier de Justin H. Kirkland sur la structure collaborative des chambres parlementaires, ou à ce papier sur la segmentation partisane.

Si vous souhaitez participer à l’amélioration, l’élargissement ou l’analyse de la base, je suis preneur : il y a beaucoup, beaucoup de données dans ces graphes (environ 195 000 propositions de loi et 13 000 parlementaires).

Dernier truc : j’ai publié un billet similaire à celui-ci sur la plateforme OpeningParliament.org, qui rassemble des organisations mobilisées autour de la thématique de l’open data dans le domaine législatif.

  1. À l’exception des micro-États, comme Andorre. []
  2. Le texte contient aussi un modèle très simple de la segmentation partisane des réseaux. []

Quelques séries télévisées britanniques à regarder

Ayant eu récemment l’occasion de m’amuser à regarder quelques séries télévisées pour un cours sur la politique (comparée) au prisme des fictions du petit écran, j’en profite pour faire un peu de publicité à ces séries en partageant mes slides :

Le cours faisait intervenir plein de monde, avec des présentations sur The Wire, désormais incontournable, The West Wing, Mad Men, et j’en oublie.

Les lecteurs de ce blog connaissent déjà la plupart d’entre elles, mais je souhaite quand même en recommander deux : Boss, d’un cynisme (américain, glacial) effroyable mais pas nécessairement irréaliste (la double négation est justifiée…), et The Thick of It, d’une vulgarité et d’un humour (britannique, absurde) à hurler de rire, surtout si vous adorez l’accent écossais de Peter “Doctor Who” Capaldi.

Je ne sais pas combien de temps je garderai les extraits vidéo mentionnés sur mon disque dur, mais dans l’immédiat, essayez ce lien.

Notice technique, illustrée par la communication officielle du Front national

Suite aux séries de billets sur les “unes” de Charlie Hebdo, les revues de la sociologie française et les réseaux législatifs, j’ai reçu quelques emails – merci ! – me demandant de réexpliquer “la base” du truc :

  • comment est-ce que l’on fait pour récupérer les données ?
  • comment est-ce que l’on fait pour en sortir un réseau ?

Je vais prendre un petit exemple facile pour illustrer le principe : comment récupérer la communication officielle du Front national à partir de son site Internet, et comment en extraire un réseau de co-occurrences.

Pour cet exemple, je suppose que vous connaissez un minimum de langage HTML. Si ce n’est pas le cas, vous aurez besoin d’une semaine au maximum pour apprendre tout ce qu’il faut savoir. Le langage HTML servant à “écrire Internet”, c’est aussi le langage le mieux documenté sur Internet : commencez ici, par exemple.

Les outils

Commençons par la base.

Il vous faudra une bonne connexion Internet : idéalement de la fibre optique, mais plus généralement, une connexion qui ne va pas tomber en rade et rajouter des erreurs de téléchargement dans une procédure qui risque déjà d’en générer par elle-même. Votre connexion Ethernet universitaire, qui est probablement filtrée d’une manière ou d’une autre, n’est peut-être pas la candidate idéale ; le wifi de votre université, encore moins.

Ensuite, il vous faut un peu d’espace disque. Utiliser un disque externe pour télécharger des centaines de fichiers est une très mauvaise idée : la moindre erreur d’écriture peut envoyer l’intégralité du disque dans les Limbes. L’idéal est d’utiliser une clé USB pas chère mais de bonne qualité, histoire que le disque dur ne soit jamais menacé. Si votre disque dur est un SSD, le risque de le foutre en l’air est toutefois minime.

Enfin, il vous faut un langage de programmation, et si possible, un langage qui va vous permettre d’enchaîner les opérations (téléchargement, visualisation, modélisation) de manière fluide. J’utilise R, mais Python est un autre bon candidat. R est bien documenté, bien illustré, la communauté répond vite et bien aux questions, et les toutes dernières techniques de modélisation y sont très bien représentées.

Il est vivement conseillé d’utiliser RStudio pour coder en R. Il vous faudra aussi un navigateur Internet avec une interface de développement intégrée, pour visualiser le code source des pages HTML que vous voulez récupérer : Chrome, Firefox, Opera ou Safari feront l’affaire.

Les packages

Quel que soit votre choix de langage, vous allez devoir vous servir d’extensions pour accomplir les différentes opérations dont vous avez besoin. Pour ce petit exemple, on va utiliser les cinq packages R suivants :

  • rvest, pour récupérer les données
  • lubridate, pour en convertir les dates
  • stringr, pour manipuler les données textuelles
  • dplyr, pour manipuler les données
  • ggplot2, pour visualiser les données

Incidemment, tous ces packages ont été développés par la même personne, avec l’aide de plusieurs autres.

On rajoutera quelques packages quand on en arrivera à l’étape “réseaux”.

La source

Toutes les donnés que l’on va récupérer proviennent de la section “Actualités” du site Internet frontnational.com. La structure de l’information qui s’y trouve est régulière : la section contient une suite d’articles qui appartiennent à une ou plusieurs catégories, avec parfois un ou plusieurs mots-clés supplémentaires. Chaque article possède un titre, qui renvoie à une page individuelle, et une date, exprimée en français :

Screen Shot 2015-03-15 at 12.58.52

Jetez à présent un coup d’oeil à la source HTML de la page “Actualités” avec les Developer Tools de votre navigateur (j’utilise ceux de Chrome) : en quelques clics et recherches par mots-clés, vous allez y trouver le code HTML qui structure l’information. Ici, les articles de la page se trouvent dans le diviseur #pk_content, les titres des articles sont codés comme des titres de niveau 3 de classe .pk_entry_title, et chaque titre fait l’objet d’un lien a :

Screen Shot 2015-03-15 at 13.06.58

Vous savez à présent ce que vous allez chercher dans chaque page. Dernière étape : combien de pages va-t-on récupérer ? Le système de pagination du site est ultra-simple à identifier :

Screen Shot 2015-03-15 at 13.19.13

Chaque page est numérotée de 2 à X, l’adresse étant de type /actualites/page/4, par exemple. La page finale est identifiable par essai-erreur : si vous essayez d’accéder à la page /actualites/page/200, vous obtenez une erreur. Cherchez un peu, et vous allez trouver qu’à l’heure actuelle, il y a 179 pages qui vous ramènent jusqu’à l’actualité du Front national en avril 2013—soit presque deux ans de données.

Le code

Pour récupérer les titres, liens, dates, catégories et mots-clés de tous les articles de la section “Actualités” du site Internet du Front national :

  1. On crée une boucle qui va de 179 à 1 ;
  2. On télécharge la page correspondant à cette valeur ; et
  3. On extrait ces informations de la page.

La base du truc ressemble à ça :

for(i in 179:1) {

  # l'adresse de la page sur le site Internet
  p = paste0("http://www.frontnational.com/actualites/page/", i)

  # le nom de fichier de la page téléchargée
  f = paste0("page", i, ".html")

  # télécharger la page si le fichier est absent
  if(!file.exists(f))
    download.file(p, f, mode = "wb", quiet = TRUE)

}

La condition if(!file.exists(f)) permet de relancer le code en cas d’erreur—mais il n’y en aura pas dans cet exemple : le site ne pose pas de souci, et ma connexion Internet n’en a pas posé non plus.

On dispose à présent de toutes les pages HTML de la section “Actualités”, et à chaque itération, l’adresse du fichier de la page est stocké dans la variable f. Pour extraire les informations de cette page :

# lire la page
h = html(f)

# extraire le lien de chaque article
url = html_nodes(h, "#pk_content h3.pk_entry_title a") %>% 
  html_attr("href")

# extraire le titre de chaque article
title = html_nodes(h, "#pk_content h3.pk_entry_title a") %>% 
  html_text()

# extraire les dates, catégories et mots-clés
meta = html_nodes(h, ".pk_entry_meta p") %>% 
  html_text()

On utilise ici les fonctions du package rvest. Rapide explication de texte :

  • Les deux premiers appels de la fonction html_nodes extraient les titres ;
  • html_attr("href") en extrait le lien individuel, html_text() en extrait le titre; et
  • l’opérateur %>% permet d’enchaîner les opérations de manière lisible

Cette syntaxe est une simplification de la syntaxe XPath, qui sert à parcourir les documents XML, dont font partie les documents HTML. Le package XML permet de faire la même chose, mais de manière moins lisible.

On obtient trois différentes variables textuelles à partir de ces opérations :

  • La variable url va contenir des liens de ce type :
    [1] "http://www.frontnational.com/2015/03/lettre-ouverte-de-marine-le-pen-aux-acteurs-des-politiques-du-handicap/"                              
    [2] "http://www.frontnational.com/2015/03/document-de-campagne-departementales-22-et-29-mars-2015/"                                             
    [3] "http://www.frontnational.com/2015/03/lettre-de-marine-le-pen-a-lattention-de-monsieur-olivier-schrameck-president-du-csa/"
  • La variable title va contenir des titres :
    [1] "Lettre ouverte de Marine Le Pen aux acteurs des politiques du handicap"                                
    [2] "Document de campagne départementales 22 et 29 mars 2015"                                               
    [3] "Lettre de Marine Le Pen à l’attention de Monsieur Olivier Schrameck, Président du CSA"
  • La variable meta va contenir le reste :
    [1] "13 mars 2015/Tribunes libres/Mots-clefs: Handicap"                          
    [2] "12 mars 2015/Annonces/Mots-clefs: Départementales 2015"                     
    [3] "12 mars 2015/Tribunes libres/Mots-clefs: CSA, Injures"

La dernière variable contient plusieurs informations, il va donc falloir un peu plus de code pour la séparer dans ses différents éléments :

  • On commence par extraire le texte de la date à partir d’une expression régulière qui en repère l’année (élément \\d{4}, qui cherche quatre chiffres consécutifs), puis on la convertit du format français “jour mois année” vers un format générique :
    date = str_extract(meta, "(.*)\\d{4}/")
    date = parse_date_time(str_sub(date, end = -2), 
                           "%d %B %Y", locale = "FR_fr")
    date = as.Date(date)
  • On extrait ensuite la ou les catégorie(s), qui se situent toujours après le premier caractère / de la variable meta (c’est-à-dire après la date). Pour ce faire, on utilise le caractère / pour diviser la variable en plusieurs petits bouts de texte, et l’on sélectionne le second :
    category = sapply(str_split(meta, "/"), function(x) x[2])
  • Enfin, on répète l’opération pour le bloc de texte correspondant aux mots-clés, en prenant soin de virer le texte dont on n’a pas besoin au passage. Il n’y pas toujours de mots-clés : on se prémunit donc contre cette possibilité en prévoyant la possibilité d’une variable manquante NA.
    tags = sapply(str_split(meta, "/"), function(x) {
      x = x[ grepl("Mots-clefs", x) ]
      x = gsub("Mots-clefs: ", "", x)
      ifelse(length(x), x, NA)
    })

En mettant toutes ces opérations à la chaîne, et en stockant les informations que l’on extrait dans un jeu de données, on arrive à 42 lignes de code qui collectent 3 581 liens et titres d’articles de la source. Tous les articles sont catégorisés, mais 728 d’entre eux n’ont pas de mots-clés.

Visualisation hyper-basique

Cherchons à visualiser un aspect très simple du corpus : qui parle au nom du Front national auprès des médias, et dans quelles proportions ?

Pour cela, on retient les 977 articles qui appartiennent à la catégorie “Médias”, et l’on extrait les noms des intervenants, encore une fois à l’aide d’une expression régulière1. L’expression en question est élaborée en jetant un rapide coup d’oeil aux titres des articles, et en rassemblant leurs intervenants dans une même expression un peu longue :

"Marine (L|l)e Pen|Marion( |-)Maréchal|Nicolas Bay|Gollnisch|F(l)?(orian|\\.) (P|p)hilippot|Louis Aliot|Steeve Briois|Sébastien Chenu|Stéphane Ravier|Thibault de la Tocnaye|Wallerand de Saint( |-)Just|Marie-Christine Arnautu|Bousquet-Cassagne|Gilbert Collard|Julien Sanchez|Julien Rochedy|Jean-Marie Le Pen|Lacoste-Lareymondie|Philippe Murer|Sophie Montel|Laurent Lopez|Gaëtan Dussausaye|David Rachline|Bernard Monot|Aymeric Chauprade|Michel Guiniot|Edouard Cavin|Jean-Claude Otto-Bruc|Dominique Martin"

Cette expression repère tous les intervenants, et ne laisse que 16 articles sans intervenants de côté.

Il ne reste plus qu’à visualiser la quantité d’articles produites par le Front national pour sa catégorie “Médias” entre avril 2013 et aujourd’hui, en coloriant les articles par les noms des intervenants, et après avoir regroupé les intervenants avec moins de 10 articles (seuil arbitraire) dans une catégorie résiduelle. Ce qui nous donne :

fn_medias_bars

Florian Philippot est en brun, et Marine Le Pen est en bleu (clair). Je vous promets que je n’ai pas choisi les couleurs : il s’agit des couleurs par défaut de l’excellent ggplot2.

Un dernier petit coup d’oeil, pour terminer, aux mois qui ont donné le plus d’articles, et aux intervenants de ces articles. Cette fois-ci, on utilise les fonctions du package dplyr pour agréger le corpus (objet m) par mois (variable ym) et par intervenant (variable who2), puis pour compter “leurs” articles, puis pour voir les dix premiers mois classés par nombre d’articles :

filter(m, who2 != "(autres)") %>% 
  group_by(who2, ym) %>% 
  summarise(n = n()) %>% 
  group_by() %>% 
  arrange(-n)

Ce qui nous donne Florian Philippot et Marine Le Pen en tête, et très loin devant le reste du peloton. Leurs mois d’activité médiatique les plus intenses correspondent aux élections municipales de mars 2014 et à la formation du premier gouvernement Valls :

1  florian philippot  2014-5 27
2      marine le pen  2014-3 23
3  florian philippot 2013-10 21
4  florian philippot  2015-2 20
5  florian philippot 2014-11 19
6  florian philippot  2013-6 18
7  florian philippot  2015-1 18
8  florian philippot 2014-12 17
9      marine le pen  2013-9 17
10 florian philippot 2013-12 16

Enfin, si l’on répète l’opération avec la catégorie “Interventions”, on trouve les députés Gilbert Collard et Marion Maréchal-Le Pen en tête de cortège, suivis des eurodéputés frontistes, mais sur des quantités moindres (il n’y a que 336 articles, soit trois fois moins de données) et plus irrégulières :

fn_interventions_bars

Pour reproduire ces résultats, allez voir le code, il y en a pour même pas 100 lignes.

Visualisation en réseau

Revenons sur la totalité du corpus. Ce corpus contient 3 581 articles constituant les “actualités” du Front national, et 80% des articles possèdent des mots-clés. Il y a 699 mots-clés différents dans le corpus. Voici les premiers d’entre eux, qui apparaissent plus de 100 fois dans le corpus, c’est-à-dire dans plus de 3% des articles possédant des mots-clés :

Européennes 2014 118
Immigration      133
Insécurité       102
Islam radical    111
Municipales 2014 261
Paris            150
Valls            122

Aucune surprise. Voyons à présent quelles associations de mots-clés reviennent fréquemment dans ce corpus.

Première étape : créer un jeu de données à deux colonnes, où chaque ligne contient une association de deux mots-clés conjointement présents sur un même article. En langage réseau, ça s’appelle une edge list non dirigée, et en langage R, ça peut se construire comme ça, à partir de la variable b$tags contenant les mots-clés de chaque article :

# associations de mots-clés dans chaque article
e = lapply(b$tags, function(x) {
  
  y = unique(unlist(strsplit(x, ",\\s?")))
  y = expand.grid(i = y, j = y, stringsAsFactors = FALSE)
  y = filter(y, i != j)
  y = apply(y, 1, function(x) paste0(sort(x), collapse = "///"))
  y = unique(y)
  data.frame(i = gsub("(.*)///(.*)", "\\1", y),
             j = gsub("(.*)///(.*)", "\\2", y),
             stringsAsFactors = FALSE)
  
})

# assemblage des associations en une seule liste
e = bind_rows(e)

# pondération de chaque association par sa fréquence
e = group_by(e, i, j) %>% summarise(n = n())

Pour la suite, il va nous falloir utiliser le package network pour convertir cette liste en objet “réseau”, auquel on va rajouter la pondération de chaque association de mots-clés, c’est-à-dire la fréquence de chacune de ces associations dans le corpus, que l’on a calculée à la toute fin du bloc de code précédent :

n = network(e[, 1:2 ], directed = FALSE)
set.edge.attribute(n, "weight", e[, 3])

Bon, à ce stade, on a le réseau complet des co-occurrences de mots-clés dans les articles “Actualités” du site du Front national, d’avril 2013 à aujourd’hui. Ça fait beaucoup, ce dont on peut se rendre compte en visualisant le réseau à l’état brut. On produit cette visualisation avec la fonction ggnet, dont on a déjà parlé :

fn_network_0

L’épaisseur des liens entre deux mots-clés est ici proportionnelle à leur fréquence d’apparition dans le corpus, simplifiée en cinq catégories correspondant à des fréquences d’associations de 1 (co-occurrence unique), 2, 3, 4 et 5 ou plus. Le code de visualisation ressemble à ça :

# diviser les co-occurrences en 5 catégories : 1, 2, 3, 4 et 5+
w = as.numeric(cut(e[, 3], c(0, 1, 2, 3, 4, Inf)))
w = w / max(w)
# visualiser le réseau complet en faisant varier l'épaisseur des liens
ggnet(n, size = 1,
  segment.color = "black",
  segment.alpha = .5,
  segment.size = w)

Ce que l’on voit au centre, ce sont les associations de mots-clés qui reviennent fréquemment ; ce que l’on voit en périphérie, ce sont les associations de mots-clés beaucoup moins fréquentes. Concentrons-nous sur le centre en ne retenant que les associations de mots-clés apparaissant au moins cinq fois dans le corpus :

# sous-réseau des co-occurrences de fréquence 5+
nn = n
delete.edges(nn, which(w < 1))
delete.vertices(nn, isolates(nn))

ggnet(nn, size = 1,
      segment.alpha = .5, segment.color = "black",
      label.nodes = TRUE,
      label.size = 3 * as.numeric(cut(degree(nn), unique(quantile(degree(n))), 
                                      include.lowest = TRUE)))

On a ici rajouté le nécessaire pour faire apparaître les mots-clés en question, et pour leur donner une taille proportionnelle au nombre d’associations dans lesquelles ils apparaissent. Le résultat ne va pas non plus vous étonner :

fn_network_5

Visualisation animée

On introduit à présent un dernier package, animation, qui va nous permettre de montrer le réseau de co-occurrences de mots-clés à chaque étape de l’affinage entre le réseau complet, qui montre toutes les co-occurrences, jusqu’à la dernière, c’est-à-dire la co-occurrence de mots-clés la plus fréquente du corpus.

Le code ressemble à ce que l’on a déjà vu, mais dans une boucle qui élimine progressivement les associations de mots-clés les moins fréquentes :

# animation
saveGIF({
  
  w = sort(unique(e[, 3]))
  for(i in w[ -length(w) ]) {
    
    nn = n
    delete.edges(nn, which(e[, 3] <= i))
    delete.vertices(nn, isolates(nn))
    
    g = ggnet(nn, size = 0,
              segment.alpha = .5, segment.color = "black",
              label.nodes = TRUE,
              label.size = 3 * as.numeric(cut(degree(nn), 
                                              unique(quantile(degree(n))),
                                              include.lowest = TRUE))) +
      ggtitle(paste("Associations apparaissant au moins", i, "fois"))
    
    print(g)
    
  }
}, movie.name = "fn_network.gif", interval = 1)

Ce qui nous donne une suite de réseaux de plus en plus “vides”, où les mots-clés “Taubira” et “Paris” ont une assez longue durée de vie, et où les mots-clés “Paris” et “insécurité” survivent jusqu’en fin de chaîne :

fn_network

Voici le code complet de la partie “réseaux”.

Bilan technique

Dans ce billet, on a utilisé :

  • R et tout plein de packages R
  • Un navigateur Internet
  • De la syntaxe HTML et XPath
  • Des expressions régulières2
  • Un tout petit peu d’analyse de réseaux

Toutes ces technologies sont gratuites et bien documentées.

Le corpus “Actualités du Front national” a servi d’exemple parce qu’il ne présentait que des difficultés minimales, qu’il ne m’a fallu que quatre minutes pour le télécharger, et que je ne comptais en présenter que des aspects très simples. Je n’ai même pas téléchargé les articles complets, par exemple, ni envisagé leur analyse textuelle.

Les exemples que je montre sur ce blog sont souvent plus larges : le corpus des revues et articles de la plateforme Cairn.info, par exemple, que j’ai utilisé pour parler des revues de sociologie, contient plus de 400 revues et à peu près 20 000 articles. Mais la logique de base reste proche de celle détaillée ci-dessus.

  1. Attention, celle-ci n’extrait que le premier intervenant : s’il y en a plusieurs, le deuxième passe à la trappe. Il n’y a que cinq articles où le problème se pose. []
  2. Alexandre fait remarquer qu’on devrait les appeler “expressions rationnelles”. S’il vous faut d’autres exemples, en voici quelques-uns. []

Twitter permet-il de reconstituer l’espace partisan français ?

Note #1 : ce billet a été mis à jour pour refléter les données que nous avons produites avec Ewen. Voir cet autre billet pour les premiers résultats du modèle cité en fin de texte (les résultats finaux ne seront pas disponibles avant plusieurs mois, vu la lenteur de l’estimation ; je n’ai réactualisé ces deux billets qu’avec des résultats intermédiaires).

Note #2 : et pour augmenter ce réseau d’une centaine de points supplémentaires, il suffit de rajouter les données de Regards Citoyens, basées sur les listes de comptes Twitter publiées par les deux chambres parlementaires. Le réseau qui en ressort est très, très similaire à celui présenté ci-dessous.

Tout comme le dernier billet en date, une bonne partie des billets de ce blog porte sur les réseaux législatifs, où j’utilise les cosignatures de propositions de loi pour faire émerger un espace politique à deux dimensions. Dans cet espace, les parlementaires s’agrègent (se rapprochent ou s’éloignent) en fonction de différentes affinités, au premier rang desquelles l’affiliation partisane.

Peut-on retrouver cet espace partisan à partir de données complètement différentes ? Pablo Barberá s’est posé la question en partant de Twitter : si l’on regarde qui suit qui sur Twitter, est-ce que les connexions créées par les “followers” permettent de reconstituer l’espace partisan de la même manière que, par exemple, les votes ou les cosignatures ?

De quoi parle-t-on au juste ?

Quand on dispose des votes des parlementaires, on peut établir le degré de similarité de ces votes d’un parlementaire à l’autre. Quand il y a deux partis en compétition, comme aux États-Unis, les parlementaires qui votent le plus souvent avec leur parti se retrouvent à chaque extrémité du spectre (que l’on va qualifier de spectre “idéologique”), et ceux qui votent parfois avec le parti adverse se retrouvent au centre.

Toujours aux États-Unis, ce genre d’analyse peut donner un truc comme ça (via), quand on se donne deux dimensions principales pour représenter l’espace partisan à partir des votes des parlementaires :

On appelle ça des “estimations de positions idéales” (estimated ideal points). Faîtes un tour sur quelques blogs américains, et vous allez trouver plein d’exemples de ces calculs. Si vous avez le temps de lire quelques articles, cherchez les articles les plus cités de Simon Jackman. Et si tout cela vous rappelle vos cours de Master sur Anthony Downs, ça tombe bien, parce que c’est à peu près ça.

… Et le rapport avec Twitter ?

Une bonne partie de la classe politique (aux États-Unis, en France, ailleurs) est sur Twitter. Un compte Twitter peut avoir des “amis”, sélectionnés par le titulaire du compte, mais aussi des “followers”, sur lesquels le titulaire du compte n’a pas de contrôle. L’hypothèse de base : les “followers” sont plus enclins à suivre les comptes Twitter des hommes politiques qu’ils apprécient que l’inverse1.

Prenons désormais tous les “followers” de toute la classe politique française. Certains d’entre eux vont suivre un ou plusieurs comptes Twitter d’hommes politiques de gauche : Hollande, Valls, quelques députés PS, etc. D’autres vont suivre les députés UDI / MODEM, et/ou Nicolas Sarkozy. D’autres, Marine Le Pen et les eurodéputés FN. Et ainsi de suite. Et d’autres vont faire des mélanges.

Vous avez compris le principe : les “followers” peuvent être compris comme une forme de signal politique. Les “followers” de Dominique Voynet, par exemple, sont plutôt susceptibles d’être aussi les “followers” d’autres personnalités politiques EELV, ou de la “gauche plurielle” (PS, PRG, PCF) ; en revanche, ils sont peu susceptibles de faire partie des “followers” de Jean-Marie Le Pen ou d’Éric Ciotti.

Est-ce que ce qu’on peut tirer des positions idéales de ces similarités et contrastes entre “followers” sur Twitter ? Pablo Barberá montre que, pour les États-Unis et pour plusieurs pays européens, la réponse est oui. Voici par exemple, pour les États-Unis, la corrélation entre les positions idéales estimées à partir des votes (scores DW-NOMINATE, axe vertical) et celles estimées à partir des “followers” sur Twitter :

barbera

Plutôt encourageant, non ? Allez lire le reste du papier, c’est vraiment très bien fichu, et même si les résultats pour les pays européens sont un peu plus bordéliques, contexte multi-partisan oblige, ils sont quand même très pertinents.

… Et ça marche pour la France ?

Pablo Barberá n’a pas traité la France, mais on peut supposer que cela va marcher au moins aussi bien que pour les pays européens. C’est une hypothèse que l’on peut facilement mettre à l’épreuve des faits. Pour ça, il nous faut :

  • une liste des comptes Twitter de plein de personnalités politiques françaises (députés, maires, conseillers locaux…) : ça tombe bien, le site Élus 2.0 de la société Idéose en liste 800 ;
  • une manière de récupérer leurs “followers” : ça tombe bien, Pablo Barberá a publié le code pour aller taper dans l’API REST de Twitter via R ;
  • et enfin, un ou plusieurs comptes Twitter personnels, pour pouvoir récupérer toutes les données en quelques jours : et ça tombe bien, j’ai les droits nécessaires sur deux comptes, @phnk et @politbistro.

Bilan : après quelques adaptations du code de Barberá et trois jours de requêtes dans l’API, on obtient la liste des “followers” de 795 1 008 comptes Twitter d’élus, dont “l’audience Twitter” est de 3 115 538 3.16 million de “followers” différents2.

Quels sont les élus dont les comptes Twitter sont les plus suivis ? La tête du peloton n’est pas très surprenante :

> select(d, twitter, followers)
Source: local data frame [1,008 x 2]

          twitter followers
1       fhollande    949862
2  nicolassarkozy    719424
3    mlp_officiel    554177
4     jlmelenchon    424239
5            nk_m    389409
6    anne_hidalgo    338536
7         najatvb    332141
8          bayrou    279149
9      montebourg    275652
10   cecileduflot    274962
..            ...       ...

Il va désormais falloir nettoyer un peu ces listes, pour ne retenir que les “followers” les plus informatifs, au sens bayésien du terme : ceux qui produisent l’information de meilleure qualité sur l’espace latent que l’on cherche à identifie. Dans son papier, Barberá utilise plusieurs critères à cet effet :

barbera-subset1

barbera-subset2

Au stade purement exploratoire, on ne va appliquer que le critère n°5, en ne retenant pour la suite que les “followers” qui suivent au moins quatre comptes Twitter d’élus. Ce seuil légèrement plus élevé que celui de Barberá correspond au nombre moyen de comptes Twitter d’élus suivis par l’ensemble des “followers”. Ce critère nous donne 694 846 environ 725 000 “followers informatifs”3.

… Et en images, ça donne quoi ?

Voyons désormais ce que les données produisent comme espace partisan, en exploitant leur nature relationnelle. Construisons une énorme matrice d’adjacence, de dimension 795 x 694 846 1 008 x 725 390, avec les élus en lignes et leurs “followers informatifs” en colonne, puis convertissons cette matrice en une edge list de cette forme :

> head(e)
              i            j  n
1 _davidlefevre    a_leboeuf  7
2 _davidlefevre   a_suguenot 10
3 _davidlefevre    abachelay 57
4 _davidlefevre adefressenel 55
5 _davidlefevre    adegermay 17
6 _davidlefevre adelinehazan  8

Indication de lecture : 7 des “followers informatifs” du compte Twitter @_davidlefevre (élu local MODEM) suivent également le compte Twitter @a_leboeuf (député UMP). La matrice d’adjacence est asymmétrique, et la liste est donc dirigée : le nombre de “followers informatifs” du compte Twitter @a_leboeuf qui suivent aussi le compte Twitter @_davidlefevre est potentiellement différent.

Normalisons, pour terminer, le nombre de “followers informatifs” partagés par deux comptes Twitter d’élus. Il se trouve que le compte Twitter @_davidlefevre est suivi par 476 “followers informatifs” : or, seulement 7 d’entre eux suivent aussi le compte Twitter @a_leboeuf. Cette fraction nous donne, pour chaque paire (dyade) dirigée de comptes Twitter d’élus, la propensité à partager des “followers informatifs”, qui sera nécessairement comprise entre 0 et 14 :

> head(e)
              i            j  n          w
1 _davidlefevre    a_leboeuf  7 0.01470588
2 _davidlefevre   a_suguenot 10 0.02100840
3 _davidlefevre    abachelay 57 0.11974790
4 _davidlefevre adefressenel 55 0.11554622
5 _davidlefevre    adegermay 17 0.03571429
6 _davidlefevre adelinehazan  8 0.01680672

Indication de lecture : environ 1.4% des “followers informatifs” du compte Twitter @_davidlefevre suivent également le compte Twitter @a_leboeuf. Cette propensité permet de repérer des affinités très fortes : par exemple, parmi les comptes Twitter d’élus du Front National, plus de 90% des “followers informatifs” des comptes Twitter @mcaucouturier, @mireilledornano et @steevebriois suivent aussi @mlp_officiel.

Cette liste peut être représentée sous forme de réseau, en filtrant la liste des liens d’intensité située au-delà d’un seuil arbitraire. Lorsque l’on visualise le réseau des liens d’intensité 0.5, par exemple, il suffit que deux élus partagent plus de 50% de “followers informatifs” pour être connectés, ce qui crée un réseau assez dense où plusieurs formations partisanes sont proches les unes des autres :

network_0.5_paper

La méthode de pondération donne parfois une position centrale à des acteurs politiques périphériques, mais ce n’est pas la préoccupation ici : on cherchait juste à vérifier, en première approche, que les liens formés entre les comptes Twitter par leurs “followers informatifs” renvoient bien à un espace partisan latent qui ressemble à l’espace partisan réel — ce qui a l’air d’être le cas.

Le réseau permet notamment de repérer la position structurellement remarquable du Front National, qui fait figure d’outsider, et celle de Marine Le Pen, qui est presque la seule au FN à partager plus de 50% de ses “followers informatifs” (qui sont un peu plus de 200 000) avec d’autres élus que les élus FN :

> filter(e, w > .5, i == "mlp_officiel")
             i              j      n         w
1 mlp_officiel         bayrou 113166 0.5100187
2 mlp_officiel      fhollande 115244 0.5193838
3 mlp_officiel    jlmelenchon 124640 0.5617299
4 mlp_officiel nicolassarkozy 112203 0.5056786

… Et la suite ?

La suite implique de faire tourner un modèle spatial hyper-lourd qui met des plombes à converger. Comme je n’ai pas encore réussi à faire tourner le truc sur ma machine de bureau, je vais m’en tenir à l’approche exploratoire. Mais si vous avez un processeur hyper-puissant sous la main et quelques connaissances en R, laissez un commentaire, je suis très preneur ! C’est en cours : voir ce billet.

  1. L’homophilie conduisant à l’exposition sélective, vous pouvez rédiger cette hypothèse de plusieurs manières pour finir au même endroit. []
  2. Quelques comptes sont inaccessibles parce que la liste des comptes n’est pas parfaitement à jour. En creusant plus loin avec Ewen, nous avons mis la liste à jour et rajouté environ 200 comptes. []
  3. Ici aussi, le chiffre est à jour de la collecte des données effectuée avec Ewen un peu après des élections départementales de 2015 []
  4. Ce schéma de pondération pénalise les comptes Twitter les plus suivis et, à l’inverse, avantage les comptes avec peu de “followers”, mais il suffit à des fins exploratoires []

Récupérer les tweets des élections départementales

Au cas où un lecteur ait à disposition une machine qui puisse tourner sans s’arrêter sur les quinze prochains jours, histoire d’avoir une bonne fenêtre de tir…

1. Il vous faut un compte Twitter

À partir de votre compte Twitter, créez une application en vous rendant à cette adresse. Le compte en question doit être lié à un numéro de téléphone. Les autres informations à fournir ne sont pas importantes : donnez n’importe quel nom et description à l’application, cochez la case en dessous des conditions d’utilisation, et vous allez vous retrouver sur une page qui permet de récupérer ces deux informations :

Screen Shot 2015-03-21 at 18.13.58

Il vous faut l’information apparaissant sous les deux barres rouges.

2. Il vous faut le package R ROAuth

Dans R, installez le package ROAuth, puis insérez vos deux codes dans les commandes suivantes :

# install.packages("ROAuth")
library(ROAuth)

requestURL = "https://api.twitter.com/oauth/request_token"
accessURL = "https://api.twitter.com/oauth/access_token"
authURL = "https://api.twitter.com/oauth/authorize"
consumerKey = ""
consumerSecret = ""
my_oauth = OAuthFactory$new(consumerKey = consumerKey,
                            consumerSecret = consumerSecret,
                            requestURL = requestURL,
                            accessURL = accessURL,
                            authURL = authURL)

Une fois ces commandes exécutées, exécutez celle-ci :

my_oauth$handshake(cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl"))

Votre navigateur va s’ouvrir et vous offrir un code PIN à rentrer dans R :

Screen Shot 2015-03-21 at 18.19.02

Une fois que c’est fait, sauvegardez le résultat :

save(my_oauth, file = "oauth.rda")

Et vous y êtes presque.

3. Il vous faut le package R streamR

Le petit bout de code expliqué ci-dessus traînait sur mon disque dur. Je ne me souviens pas de la source exacte, mais c’était sans doute un tutoriel de Pablo Barbera. Le même a écrit le package streamR, qui va vous permettre de récupérer une sélection de tweets identifiés par les mots-clés et hashtags des élections départementales. Installez le package, puis lancez cette boucle :

# install.packages("streamR")
library(streamR)

# load credentials
load("my_oauth.Rdata")

# scrape for 15 days
for(i in (15 * 24 * 2):1) {

  n = sprintf("%03.0f", i)
  f = paste0("tweets", n, ".json")

  cat(n, "scraping to", f, "...\n")
  filterStream(f, track = c("départementales", "departementales",
                            "#departementales2015", "#departementales",
                            "#départementales2015", "#départementales",
                            "#dep2015"),
               timeout = 60 * 25, oauth = my_oauth)

  # leave five minutes out
  Sys.sleep(60 * 5)

}

La boucle produit un fichier toutes les 25 minutes et ignore dix minutes d’information par heure, histoire de laisser l’API de Twitter souffler un peu. Les résultats ne sont pas limités aux tweets en français, mais vous aurez tout le loisir de faire le tri plus tard.

Un petit test effectué ce samedi m’a renvoyé un peu plus de 4 600 résultats de bonne qualité (dont 4 100 en français) en moins de six heures. Il est très facile d’explorer ce genre de données en utilisant, par exemple, environ 700 comptes Twitter d’élus et de partis politiques français, afin de voir s’ils sont souvent retweetés :

Rplot

Le codage ci-dessus est très incomplet : je n’ai codé que les comptes Twitter des médias les plus évidents (presse quotidienne, chaînes de télévision et quelques médias en ligne), et n’ai inclus dans la catégorie “Officiels” que le seul compte Twitter du Ministère de l’Intérieur. Récoltez les données demain et les jours suivants, et vous aurez un bon matériau pour faire beaucoup mieux.