Catégories
Wikidata

Croiser des données avec OpenRefine

On vient de me poser une question intéressante sur Twitter :

« Question pour les experts Wikidata qui causent SPARQL : vous pourriez m’aider à faire une requête du genre « villes des États-Unis entre 100 000 et 600 000 habitants situées dans un comté ayant majoritairement voté pour Clinton en 2016 » ? »

Le problème ici est que les données électorales détaillées ne sont pas sur Wikidata (et à mon avis n’y ont pas leur place, elles seraient mieux sur Commons sous forme de données tabulaires).

En revanche, il est possible d’extraire via une requête SPARQL la liste des villes des États-Unis entre 100 000 et 600 000 habitants, puis de la croiser par le biais d’OpenRefine avec un tableau des résultats des élections.

Données électorales

La première étape est de chercher un fichier open data contenant les données de l’élection présidentielle américaine de 2016 par comté, idéalement sous la forme d’un CSV à télécharger. Ça tombe bien, il y en a un sur OpenDataSoft.

Plus qu’à l’importer dans OpenRefine. Si vous ne connaissez pas, c’est un outil d’alignement et de croisement de données, qui se définit lui-même comme un « Excel sous stéroïdes ». Il était développé à la base par Google pour Freebase, mais il a depuis été libéré et le développeur principal actuel est un contributeur à Wikidata. Il y a de bons tutoriels pour l’utiliser pour récupérer des données de Wikidata ou y importer de nouvelles données après alignement avec les données existantes, mais on ne va ici faire ni l’un ni l’autre.

Dans OpenRefine, il faut faire CreateProject → from this computer et choisir le CSV téléchargé, puis cliquer sur Next.

La prévisualisation semble correcte, et le nom du projet proposé (celui du fichier) également : je clique donc sur Create project.

Les informations qui vont être importantes pour la suite sont : le nom du projet, le nom de la colonne servant à aligner les données (la colonne « County », qui est du format « <County>, <State> ») et celui de la ou des colonnes avec les données à récupérer (ici, uniquement la colonne « Democrats 2016 ») Le jeu de données est déjà bon pour ce que je veux en faire, je n’ai pas de manipulations supplémentaires à faire.

Liste des villes

La seconde étape est d’extraire la liste des villes correspondant à la demande. Je ne vais pas détailler la requête, mais en regardant quelques entrées de villes US sur Wikidata, je vois qu’elles ont pour nature « city aux États-Unis » (Q1093829), qu’elles ont des chiffres de population pour 2010, le comté entré comme « localisation administrative » (je vais quand même vérifier qu’il a s’agit bien d’un comté américain et pas directement de l’état ou d’un autre type de division administrative. Apparemment tous ont pour nature « comté de <tel état> », qui sont eux-mêmes des sous-classes de « comté des États-Unis »)

Je vais aussi avoir besoin de l’état et, tant qu’à faire, je récupère aussi les coordonnées. Voici donc la requête :

#Cities of the United States between 100,000 and 600,000 inhabitants with the counties and states they are located in
SELECT DISTINCT ?city ?cityLabel ?county ?countyLabel ?state ?stateLabel ?pop ?coord
WHERE
{
?city wdt:P31 wd:Q1093829 .
?city wdt:P1082 ?pop .
FILTER (?pop >= 100000 && ?pop <= 600000)
?city wdt:P131 ?county .
?county wdt:P31/wdt:P279 wd:Q47168 .
?county wdt:P131 ?state .
?state wdt:P31 wd:Q35657 .
?city wdt:P625 ?coord .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
} ORDER BY ?stateLabel ?countyLabel ?cityLabel

La requête renvoie 247 résultats alors qu’il y a 213 villes correspondant à la requête, parce que certaines villes s’étalent sur plusieurs comtés et qu’il y a parfois plusieurs chiffres de population ou plusieurs coordonnées géographiques entrés sur certains éléments de ville.

Je télécharge donc le résultat de la requête en CSV, que je vais également importer dans un projet OpenRefine que je nomme « US Cities between 100000 and 600000 hab. that voted democrat in the 2016 Presidential election » ce qui est… long.

Aligner les données

L’idée est d’enrichir ce nouveau projet avec les informations électorales de celui créé plus haut. On va donc créer une nouvelle colonne contenant le nom des comtés sous le même format « <County>, <State> »

Pour cela, je commence par dupliquer la colonne StateLabel en cliquant sur la flèche à côté du nom de la colonne, puis Edit column → Add column based on this column. Je nomme la nouvelle colonne « county state » et je vérifie que l’expression est simplement « value » (ce qui va donc juste copier la valeur actuelle)

Sur la nouvelle colonne county state, je fais Edit column → Join columns avec les paramètres suivants :

Attention, il y a une espace après la virgule dans le champ Separator. Une fois cela fait, on peut enfin aligner avec l’autre projet et récupérer les résultats des démocrates en 2016. Là encore, on crée une nouvelle colonne « Democrats 2016 » basée sur la colonne « county state », avec l’expression suivante :

toNumber(cell.cross("usa 2016 presidential election by county csv", "County").cells['Democrats 2016'].value[0])

Pour détailler : cell.cross("usa 2016 presidential election by county csv", "County") indique le nom du projet avec lequel on aligne et celui de la colonne pivot dans ce projet, cells['Democrats 2016'].value[0] récupère la valeur de la colonne Democrats 2016 et enfin la fonction toNumber(...) transforme cette valeur en nombre (sinon c’est une chaîne de caractères)

On peut maintenant filtrer les villes où les démocrates étaient majoritaires en 2016 ! Dans OpenRefine, cela se fait avec une facette. Sur la colonne Democrats 2016, Facet → Numeric Facet fait apparaître une glissière très pratique. Il suffit de déplacer la borne de gauche sur 50 et voilà, on a le résultat qu’on cherchait au début.

Affichage dans uMap

On pourrait directement exporter ce résultat en CSV mais je veux l’afficher dans uMap, il reste donc quelques manips à faire pour correspondre au format attendu :

  • Renommer (ou dupliquer) la colonne cityLabel en name
  • Scinder la longitude et la latitude dans deux colonnes séparées et nommées comme ça. Il faut pour cela créer deux colonnes à partir de la colonne coord.

Pour la colonne longitude, l’expression (en jython) est :

import re
match = re.match(r'Point(([0-9,-.]+) ', value)
return match.group(1)

Et pour la colonne latitude :

import re
match = re.match(r'Point([0-9-.]+ ([0-9-.]+))', value)
return match.group(1)

On peut donc ensuite exporter le projet en CSV (Export → Comma separated values) puis l’importer dans une nouvelle carte sur uMap, et voici le résultat :

Image d’en-tête : I´m ready for Hillary par Rafael Robles, CC-BY 2.0

Catégories
Projets Wikimédia

Convent(ion)s

J’ai eu la chance cette année de participer à quatre événements internationaux du mouvement Wikimédia : le hackathon européen à Vienne du 19 au 21 mai, Wikimania 2017 à Montréal du 9 au 13 août, la Wikiconvention francophone à Strasbourg du 19 au 21 octobre et la WikidataCon à Berlin les 28 et 29 octobre. Si je ne me trompe pas, je n’ai jamais participé à autant la même année.

À part pour la Wikiconvention, j’ai assisté à tous ces événements sur mon temps bénévole, avec une bourse de Wikimédia France pour le hackathon, une (partielle) de Wikimedia Foundation pour Wikimania, et une de Wikimedia Deutschland pour la WikidataCon: merci à ces organisations pour leur soutien.

Participer à de tels événements est toujours un moment intense, car on passe plusieurs jours en compagnie de personnes passionnées et passionnantes, qui viennent pour partager les trucs formidables qu’ils font sur les projets Wikimedia ou pour ceux-ci : c’est très motivant, c’est idées qui fusent dans tous les sens, des discussions intéressantes jusqu’à pas d’heure. Ça donne envie de se lancer dans plein de choses et on se prépare un bon gros con drop pour la semaine suivante.

Je vais ici essayer de faire le point sur comment se passe chaque événement et ce qui me motive à y aller, plutôt qu’essayer de faire un résumé de confs qui sont maintenant pour la plupart filmées et diffusées en ligne.

Hackathon Wikimedia

Photo de groupe du Hackathon Wikimedia 2017 – CC-BY-SA 4.0 Manfred Werner (Tsui)

Le hackathon Wikimedia rassemble chaque année, dans une ville européenne((Ou proche : en 2016 c’était à Jérusalem.)) environ 200 développeurs bénévoles du mouvement le temps d’un week-end. C’est intense : l’événement se déroule en continu et il est possible d’accéder aux salles pour hacker à toute heure, même si les organisateurs prévoient généralement des événements pour les soirées.

Contrairement aux hackathons institutionnels, durant lesquels des personnes ne se connaissant pas bossent ensemble le temps d’un week-end sur un projet qui partira aux oubliettes, beaucoup des gens présents travaillent ensemble toute l’année sur des outils et profitent de ce moment pour le faire en présentiel. D’autres travaillent séparément sur des outils développés au cous du week-end, mais profitent d’avoir sous la main des experts connaissant parfaitement Mediawiki et les différentes librairies et APIs dédiées et pouvant donner de précieux conseils. C’est ainsi que j’ai pu, pour ma part, créer un outil qui avait été demandé par Antoine Courtin quelques semaines avant.

J’en profite pour signaler que même si vous n’êtes pas dev, votre présence peut être utile, par exemple pour aider sur la documentation.

Wikimania 2017

Photo de groupe de Wikimania 2017 – CC-BY-SA 4.0 VGrigas (WMF)

Wikimania est le grand rassemblement mondial du mouvement Wikimedia, rassemblant chaque année des centaines de personnes.

Wikimania commence toujours par des pré-conférences, dont un hackathon qui se déroule comme le hackathon européen. Comme à Vienne, j’ai profité d’avoir des gens plus compétents que moi en JavaScript pour m’aider (en particulier, merci Tpt ;)) à finir mon premier gadget sur Wikidata : DataDrainer 2.0.((Ah, et je nie toute connaissance sur ces histoires de boucs. Quelles histoires de boucs, d’abord ? 🐐))

La conférence abordait, comme chaque année, tous les sujets liés au mouvement avec des présentations sur des actions de grande envergure et d’autres plus confidentielles. J’ai remarqué un changement cette année cependant : j’ai la très nette impression qu’on est passés de « Wikipédia et ses projets-frères » à « Wikidata et ses projets-frères », en témoignent le nombre de présentations liées à ce projet et le fait que celles-ci soient systématiquement pleines à craquer((D’un autre côté, j’ai trouvé les salles dédiées aux confs Wikidata sous-dimensionnées.))

Dernier point concernant cette Wikimania : Pyb et moi avons présenté un poster au sujet de Wikicheese((Euh, je veux dire Wikifromage ;). Et oui, il y avait du fromage de chèvre. 🐐)), et organisé une dégustation dans la suite de Wikimedia Canada.

Dégustation de fromage à Wikicheese – CC-BY-SA 4.0 Ahmed Houamel

Wikiconvention francophone 2017

Photo de groupe de Wikimania 2017 – CC-BY-SA 4.0 Habib M’henni

Avance rapide de quelques mois pour la deuxième édition de la Wikiconvention francophone, qui a eu lieu à Strasbourg en octobre. C’est une déclinaison de ce qui se fait déjà depuis des années chez les germanophones et les néerlandophones : rassembler les contributeurs et contributrices de tous les pays parlant une même langue. Les problématiques concernant les projets déclinés par langue sont ainsi beaucoup plus pertinentes : les problèmes de la Wikipédia en français ne sont pas forcément ceux de la version anglophone.

Étant là sur mon temps de travail, je me suis concentré sur les présentations les plus techniques, notamment une table ronde sur les besoins tech de la Wikipédia en français, qui devrait aboutir sur un pré-hackathon dans le sud de la France le mois précédant le prochain hackathon européen à Barcelone. Stay tuned 😉

La prochaine édition de la Wikiconvention elle-même aura a priori lieu à Grenoble en août prochain.

WikidataCon 2017

Photo de groupe de Wikimania 2017 – CC-BY-SA 3.0 Rama

Dernier événement, une semaine plus tard : la WikidataCon. Il s’agit ici de rassembler les contributeurs et contributrices de Wikidata au moment du 5e anniversaire du projet. C’est la première édition de cet événement et elle est très prometteuse, notamment grâce au soin apporté aux détails lors de l’organisation. Ainsi, au delà des efforts d’accessibilité qui sont devenus standards dans les événements Wikimédiens,  on peut noter l’insistance sur le respect de la friendly space policy, la précaution de mettre des toilettes gender-neutral ou un espace isolé pour les gens qui auraient besoin de récupérer, le soin particulier apporté à la restauration (clairement la meilleure cette année, et pourtant Wikimania avait mis la barre haut) et au fait qu’elle ait été pensée pour que tout le monde y trouve son compte.

La prochaine édition aura lieu à Berlin dans deux ans, mais en attendant Wikimedia Deutschland nous incite à organiser des événements de moindre ampleur vers la fin octobre prochain. Peut-être en France ?

Et l’an prochain ?

Comme je l’annonce plus haut, plusieurs événements d’envergure sont à prévoir en France dans l’année à venir : je vais essayer d’y être et je vous invite à venir aussi. Je vais aussi essayer d’aller au FOSDEM (à Bruxelles) et au Hackathon Wikimedia. Par contre, je pense que je vais passer mon tour pour Wikimania, même si l’Afrique du Sud est une destination tentante.

Image d’en-tête : The Convent, or The Great He-Goat 🐐, par Francisco de Goya y Lucientes (domaine public)

Catégories
Wikidata

Œuvres emblématiques

À

la base, c’était un fil reddit sur les œuvres les plus emblématiques de chaque pays d’Europe. Une chouette idée : pour chaque pays, déterminer quelle œuvre est la plus représentative et la placer sur un fond de carte[1]. On y trouve à peu près tout ce à quoi on s’attend : La Joconde, Le Cri, La Jeune Fille à la perle, etc. C’est extrêmement cool.

Une carte d'Europe avec en fond pour chaque pays une œuvre qui en serait emblématique
La carte en question

Évidemment, après, on se demande si on ne pourrait pas être un peu plus rigoureux. Déjà, ça mélange les peintures et les sculptures (et ces dernières rendent moins bien sur la carte). Et puis ça veut dire quoi, exactement, « l’œuvre la plus emblématique » ? halfabluesky, l’auteur de la carte, ne cache pas avoir œuvré de façon subjective, les recensant avec ce qu’il connaissait et avec Google pour le reste. Et puis la correspondance par pays n’est pas très stricte (surtout vers l’est de l’Europe, là où les frontières ont pas mal bougé depuis deux siècles[2]). Est-ce qu’on ne pourrait pas aller plus loin, toutefois ?

Comment mesurer l’importance d’une œuvre ? Je me suis souvenu d’une approche détaillée il y a quelques années pour déterminer les œuvres les plus influentes du 20e siècle : compter le nombre de fois que leur reproduction apparaît dans les manuels scolaires publiés entre 1995 et 2005. Eh, c’est une approche qui vaut ce qui vaut, certainement contestable, statistiquement contestable. Mais après tout, ça donne un résultat et il n’est pas totalement délirant. Pourquoi pas, après tout. C’est une idée.

Considérons, pour les besoins de ce billet de blog, qu’une œuvre est d’autant plus importante qu’elle existe sur de nombreuses versions de Wikipedia (et donc potentiellement connue tout autour du globe). Limitons-nous aux peintures[3] : grâce à la magie de Wikidata, il est possible de récupérer les œuvres peintes au siècle précédent et qui comptent un article sur au moins 5 Wikipedias (ici, la requête SPARQL). À l’heure où j’écris ces lignes, on en compte 189. Sur le podium, Guernica de Picasso, La Persistance de la mémoire de Dalí et Le Baiser de Klimt. Ça semble cohérent. L’approche semble valable.

Revenons à notre carte. Comment lier une œuvre à un pays, alors qu’il n’est même pas sûr que celui-ci existait déjà à l’époque où l’œuvre a été créée[4] ? Allons au plus simple : considérons le lieu de naissance de l’artiste et contentons-nous de regarder dans quels pays actuels il est situé. Bref, il nous faut une requête qui :

  1. considère les peintures ayant un auteur de renseigné[5]
  2. regarde son lieu de naissance[6]
  3. détermine dans quel pays celui-ci se situe
  4. calcule, pour ce pays, quelle peinture à le plus d’entrées en différentes langues sur Wikipédia

Ça tombe bien : c’est totalement faisable[7].

Arrivé là, je me suis dit qu’on pourrait aller plus loin et générer automatiquement une carte similaire à celle du début. Mon approche : prendre une carte du monde au format svg, récupérer les données de Wikidata et utiliser les images comme motif pour les pays appropriés. Au final, j’en ai fait un mini-site. C’est pas bien rapide, c’est lourd, c’est du brutal, mais ça marche[8] !

Une carte du monde présentant, pour les pays où c'est possible, la peinture qui a un article dans le plus de langues sur Wikipédia.
Un monde de peintures

Du coup, quelques remarques :

  • Si on se fie à cette carte, la peinture serait essentiellement un art de l’Europe du 19e siècle.
  • Il faut des entrées sur Wikipédia pour apparaître. La pauvreté du traitement des pays africains est un réel problème[9].
  • De même, si votre pays a traditionnellement privilégié d’autres modes d’expression que la peinture, ou si le concept d’auteur a pu y être moins important, il ne sera pas présent. Aucun résultat en Thaïlande ou en Corée, vraiment ?
  • Sur 115 entrées (un pays peut avoir plusieurs entrées ex-aequo), 30 n’existent que sur une seule Wikipédia : 15 pays ne sont donc représentés que par des peintures présentes dans une seule langue. 82 entrées (47 pays sur 78) n’existent qu’en 5 langues ou moins. Difficile dans ce cas de parler de tableaux « connus » ou « emblématiques »…
  • Lier le lieu de naissance de l’artiste au pays n’est pas forcément bien probant. L’île Maurice est représentée par Henri Le Sidaner, peintre français né à Port-Louis avant d’être ramené en métropole. Pour l’Égypte, c’est le peintre grec Konstantinos Parthenis qui s’y colle.
  • La représentation des données sur Wikidata est importante. Russie et Ukraine sont représentée par le même tableau : La Neuvième Vague. Ivan Aïvazovski est né en Crimée, une région actuellement indiquée comme appartenant en même temps à la Russie et à l’Ukraine sur Wikidata…

(Image d’en-tête : détail de La Liberté guidant le peuple, par Eugène Delacroix (domaine public).)


Notes :

  1. Ce billet comporte des notes de bas de page. Tout le monde aime les notes de bas de page, non ?
  2. De toute façon, si on habite l’ouest de l’Europe, on n’y connait rien à l’art est-européen (« Des icônes, c’est ça ? »). L’Europe de l’Est nous en veut pas mal, d’ailleurs.
  3. Si on voit large et qu’on prend en compte l’intégralité des œuvres d’art (Q838948 sur Wikidata), on se retrouve avec en tête Bambi, Dumbo et la statue du Christ Rédempteur à Rio. En restraignant aux seuls arts visuels (Q4502142) : Guernica, Peanuts et La Bille bleue, la photo de la Terre prise par l’équipage d’Apollo 17. Éclectique.
  4. Ou alors, le pays existait, mais le lieu a changé de main. Ou le concept de pays n’était même pas pertinent. Mais nous sommes sur un simple billet de blog et notre idée de départ – les œuvres emblématiques d’un pays – est déjà passablement peu précise. Bref.
  5. Tu es une œuvre anonyme ultra connue ? Désolé, tu n’apparaîtras pas ici. Je sais, c’est pas super inclusif, j’y peux rien, c’est ma méthodo, pas toi.
  6. On ignore où tu es né ? Même punition.
  7. Merci, Shonagon.
  8. Je suis sûr qu’on pourrait utiliser un fond de carte OpenStreetMap à la place d’un fichier svg. Une idée à creuser.
  9. Assez surpris de l’absence totale de peinture islandaise sur Wikipedia, en passant.
Catégories
Projets Wikimédia Wikidata

Bon anniversaire, Wikidata !

Wikidata a quatre ans aujourd’hui, et il me semble que c’est le bon moment pour faire un petit retour sur mon expérience avec ce projet((Et puis, Auregann m’a demandé de le faire ;).)).

Wikidata est un projet qui m’intéresse vivement depuis bien longtemps avant sa création effective. Si j’avais lu le nom ici et là sur le bistro de Wikipédia depuis que j’ai commencé à contribuer en 2005, la première fois qu’il a retenu mon attention, pour autant que je m’en souvienne, est cette discussion  en novembre 2006((Au passage, en cherchant à la retrouver, je suis tombé sur la plus ancienne mention de Wikidata que j’aie vu sur la Wikipédia en français, qui remonte quand même à août 2004!)) : un dépôt commun pour les données, fonctionnant de la même façon que Commons, c’était exactement ce qui manquait à Wikipédia !

Et je n’étais apparemment pas le seul à avoir cet avis : c’était à l’époque l’opinion générale sur le bistro. Un autre avantage qui y était mentionné à l’époque, c’était que cela pourrait remplacer avantageusement le système de catégories foireux de l’époque (enfin… l’actuel quoi.) Une fonctionnalité que je suis toujours impatient de voir arriver.

Avec le temps, je suis devenu de plus en plus impliqué dans la communauté, et pour finir j’ai sauté dans le wiki-train pour Gdańsk en 2010 pour participer à ma première Wikimania.

1280px-wiki-train_poznan_dinner
*Record scratch* Yup, that’s me. You’re probably wondering how I ended up in this situation.

Là, l’une des présentations dont je me souviens le plus((Enfin à part celles avec de l’alcool.)) était celle d’un système centralisé pour la gestion des liens interwiki. Cette présentation ne faisait à l’époque aucune mention d’autre (méta-)données que les interwikis et éventuellement des libellés lisibles dans plusieurs langues, et ne parlait pas du tout de Wikidata. Pourtant, ces deux choses sont ce qui est devenu la « phase l » du développement de Wikidata le 29 octobre 2012. Quand j’ai commencé à y contribuer, le 17 décembre de la même année, le projet était encore naissant et ne permettait toujours de faire que ces deux choses : gérer les interwikis de Wikipédia, et mettre des libellés. C’est donc ce que j’ai fait : J’ai créé un nouvel élément, lui ai donné une paire de libellés et ait déplacé les liens externes depuis Wikipédia.

capture-du-2016-10-28-01-26-15
Ta-da !

Je me suis arrêté là à l’époque. Il n’y avait alors aucun moyen d’ajouter des déclarations plus utiles, et n’ayant pas la passion de la gestion des interwikis, j’ai laissé cette tâche aux robots et à leurs dresseurs. Pendant longtemps après ça, j’ai simplement fait des modifications par-ci par-là, mais sans m’atteler à un gros projet. J’avais cependant envie de passer au cran supérieur, et je me suis donc demandé à quoi m’atteler… En 2006 ou 2007, j’avais refait entièrement la liste des empereurs du Japon sur Wikipédia, et je me suis dit que ça pourrait être une bonne idée d’avoir les mêmes données de base (c’est-à-dire noms, dates de naissance/règne/mort, lieux de naissance et de mort, etc.) sur Wikidata également.

À l’époque, j’utilisais très peu d’outils ou de gadgets, et ça a donc été assez long et fastidieux (et sans l’outil missingprops.js de Magnus((Personnalisé pour mes besoins)), ça l’aurait été encore plus), mais j’ai fini par en voir le bout.

capture-du-2016-10-28-21-33-36

Mon pic d’activité suivant a eu lieu quelques temps plus tard, quand j’ai décidé de créer chaque corps céleste de l’univers de Serenity/Firefly((Oui, pour info, je suis un Browncoat.)). Le faire uniquement avec l’interface de Wikidata aurait relevé de la folie pure, et j’ai donc utilisé un autre outil de Magnus : QuickStatements. Si vous vous en êtes déjà servi, vous savez qu’une simple textarea où coller un blob de tab separated values n’est pas l’interface la plus pratique du monde… Du coup, j’ai décidé à l’époque de créer un outil moi-même pour résoudre le problème  : un  convertisseur CSV vers QuickStatements convertor qui permet de travailler avec un tableur organisé de façon plus traditionnelle.

Après ça, parmi d’autres choses, j’ai décidé d’importer tous les épisodes d’xkcd, et également aidé Harmonia Amanda dans son travail avec les courses de chiens de traîneaux puis les écoles d’art dramatique. Cela m’a incité à me plonger plus avant dans Python et écrire des scripts pour récupérer et traiter les données.

I know you all are xkcd fans.
Je sais que vous êtes tous fans d’xkcd.

 

Dans l’intervalle, j’ai également suivi la première édition du MOOC d’Inria sur le web sémantique, durant lequel j’ai appris plein de choses, et en particulier le langage SPARQL. Et là, c’est vraiment parti en roue libre : quand le point d’accès SPARQL pour Wikidata a été mis à disposition, j’ai écrit un billet ici à ce sujet. Des gens ont commencé à me poser des questions dessus, ou à me demander d’écrire des requêtes pour eux, et cet article est devenu le premier d’une longue série qui continue encore avec les #SundayQuery.

En résumé, en quatre ans :

  • J’ai commencé à coder des outils et les mettre à disposition de la communauté
  • J’ai écrit des scripts d’extraction et conversion de données en Python
  • J’ai beaucoup appris sur le web sémantique
  • Je suis devenu un ninja du SPARQL.

Et tout ça à cause de Wikidata. Et j’espère bien que ça va continuer sur cette lancée !

Image d’en-tête: Wikidata Birthday Cake par Jason Krüger (CC-BY-SA 4.0)

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Catégories
Projets Wikimédia Wikidata

Sunday Query : où meurent les Bretons ?

Cette #SundayQuery part d’une question de @belett sur Twitter : comment afficher des points de différentes couleurs sur une carte générée sur le point d’accès SPARQL de Wikidata ?

Première requête

En l’occurrence, il cherchait à afficher le lieu de mort des personnes nées à Rennes ou à Brest, avec une couleur différente selon leur lieu de naissance. À ma connaissance, on ne peut pas spécifier directement la couleur des points d’une carte avec un paramètre ?rgb comme on peut le faire avec un graphe. En revanche, si la requête comporte un paramètre ?layer, la carte l’utilisera pour gérer des couches avec des points de couleurs différentes et, encore mieux, qu’on peut afficher et masquer à volonté.

Voici donc ma première réponse, en donnant à mes couches le nom de la ville via la fonction BIND, qui permet de définir à la main le contenu d’une variable :

#defaultView:Map
SELECT ?coord ?layer WHERE {
  {
    ?item wdt:P31 wd:Q5 ; # On cherche, pour des êtres humains
          wdt:P19 wd:Q647 ; # nés à Rennes
          wdt:P20 ?place . # leur lieu de décès
    ?place wdt:P625 ?coord . # enfin ses oordonnées
    BIND("Rennes" AS ?layer) . # On met manuellement "Rennes" comme valeur de ?layer
  } UNION {
    ?item wdt:P31 wd:Q5 ;  # Idem avec Brest
          wdt:P19 wd:Q12193 ;
          wdt:P20 ?place .
    ?place wdt:P625 ?coord .
    BIND("Brest" AS ?layer) .
  }

  SERVICE wikibase:label { bd:serviceParam wikibase:language "en" . }
}

http://tinyurl.com/jyzaa9o

Carte d'Europe, avec des points surtouts concentrés sur l'Ouest de la France
Carte avec deux couches, une pour Rennes et une pour Brest, et montrant le sélecteur.

Avec VALUES

Mais je ne suis pas fan des UNION quand je peux les éviter, ou de mettre le nom des ?layer à la main avec un BIND : tout ça est so SPARQL 1.0 ! Heureusement, SPARQL 1.1 apporte un mot-clef pratique pour définir une liste de valeurs autorisées pour une variable((Ou plusieurs d’ailleurs.)) : VALUES. Voici la requête améliorée pour l’utiliser, et au passage chercher les gens nés à Nantes, tant qu’à y être :

#defaultView:Map
SELECT ?item ?itemLabel ?placeOfBirth ?placeOfBirthLabel ?placeOfDeath ?placeOfDeathLabel ?image ?coord ?layer  WHERE {
  ?item wdt:P31 wd:Q5 ; # On cherche des êtres humains
        wdt:P19 ?placeOfBirth ; # Leur lieu de naissance
        wdt:P20 ?placeOfDeath . # Leur lieu de décès
  ?placeOfDeath wdt:P625 ?coord . # les coordonnées de celui-ci
  
  VALUES ?placeOfBirth { # Si le lieu de naissance est dans cette liste :
    wd:Q647    # Rennes
    wd:Q12193  # Brest
    wd:Q12191  # Nantes
  }
  
  ?placeOfBirth rdfs:label ?layer . # On définit un calque par lieu de naissance
  FILTER(LANG(?layer) = "fr") .  # en ne gardant que les noms de lieu de naissance en français
  
  OPTIONAL { ?item wdt:P18 ?image . } # S'il y a une image, on l'affiche
  
  SERVICE wikibase:label { bd:serviceParam wikibase:language "fr,en" . }
}

http://tinyurl.com/zgr6lle

Carte d'Europe, avec des points surtouts concentrés sur l'Ouest de la France
Les points de Rennes et Brest sont toujours là, Nantes est venue s’y rajouter

J’en ai profité pour ajouter l’image si elle existe, qu’on voit en cliquant sur un point.

Dans toute la Bretagne

Mais pourquoi s’arrêter à quelques villes ? Autant y aller carrément avec toutes les personnes nées en Bretagne, par lieu de naissance.

#defaultView:Map
SELECT ?item ?itemLabel ?placeOfBirth ?placeOfBirthLabel ?placeOfDeath ?placeOfDeathLabel ?image ?coord ?layer WHERE {
  ?item wdt:P31 wd:Q5 ; # On cherche des êtres humains
        wdt:P19 ?placeOfBirth ; # Leur lieu de naissance
        wdt:P20 ?placeOfDeath . # Leur lieu de décès
  ?placeOfDeath wdt:P625 ?coord . # les coordonnées de celui-ci
  
  ?placeOfBirth (wdt:P131|wdt:P706|wdt:P276)* wd:Q12130 . # nés dans un lieu situé en Bretagne administrative
  
  ?placeOfBirth rdfs:label ?layer . # On définit un calque par lieu de naissance
  FILTER(LANG(?layer) = "fr") . # en ne gardant que les noms de lieu de naissance en français
  
  OPTIONAL { ?item wdt:P18 ?image . } # S'il y a une image, on l'affiche
  
  SERVICE wikibase:label { bd:serviceParam wikibase:language "fr,en" . }
}

http://tinyurl.com/zx7rww7

Il suffit de remplacer la liste de valeurs autorisées par la propriété disant que le lieu est situé en Bretagne((Administrative sur cette requête.))… Seulement, suivant les éléments, plusieurs propriétés peuvent être utilisées : localisation administrative (P131), localisation géographique (P706), ou tout simplement lieu (P276)… Heureusement, SPARQL permet d’interroger toutes ces propriétés à la fois, en les séparant par des « | ». Les parenthèses sont optionnelles, on aurait aussi bien pu écrire   ?placeOfBirth wdt:P131*|wdt:P706*|wdt:P276* wd:Q12130 .  qui donne les mêmes résultats. Notez au passage qu’il faut alors mettre l’étoile au niveau de chaque propriété. Cette étoile sert à dire qu’il faut si besoin remonter plusieurs niveaux de résultats jusqu’à atterrir sur Q12130.

Carte d'Europe, avec de nombreux points de toutes les couleurs
Tiens, un sapin de Noël.

Oups : comme il y a une couche par lieu de naissance, ça fait beaucoup de calques, ce qui fait que la carte devient illisible… Et que le sélecteur de calques ne peut pas tout afficher à l’écran.

Optimisation

Heureusement, il est possible d’arranger ça facilement: il suffit de demander au passage le département de naissance((Il y a les cinq départements cette fois, puisque la requête porte sur la Bretagne historique cette fois.)) et l’utiliser comme ?layer à la place du lieu. Histoire de rester concis, je profite du fait qu’on peut utiliser la virgule pour plusieurs valeurs partageant le même sujet et la même propriété, de la même façon qu’on peut utiliser le point virgule pour des couples propriété-valeur ayant le même sujet.

#defaultView:Map
SELECT ?item ?itemLabel ?placeOfBirth ?placeOfBirthLabel ?placeOfDeath ?placeOfDeathLabel ?image ?coord ?layer WHERE {
  ?item wdt:P31 wd:Q5 ; # On cherche des êtres humains
        wdt:P19 ?placeOfBirth ; # Leur lieu de naissance
        wdt:P20 ?placeOfDeath . # Leur lieu de décès
  ?placeOfDeath wdt:P625 ?coord . # les coordonnées de celui-ci
  
  ?placeOfBirth (wdt:P131|wdt:P706|wdt:P276)* wd:Q327, # Nés en Bretagne
                                              ?departement . # Dans un lieu...
  ?departement wdt:P31 wd:Q6465 . # Qui est un département français
  
  ?departement rdfs:label ?layer . # On définit ce département comme calque
  FILTER(LANG(?layer) = "fr") . # en ne gardant que les noms de département en français
  
  OPTIONAL { ?item wdt:P18 ?image . } # S'il y a une image, on l'affiche
  
  SERVICE wikibase:label { bd:serviceParam wikibase:language "fr,en" . }
}

http://tinyurl.com/z3cttt3

Résultat final

capture-du-2016-10-09-13-54-30

La carte montre deux résultats intéressants : beaucoup de gens meurent dans leur département de naissance et encore plus meurent à Paris((Le gros tas de points autour de la gare Montparnasse.)).

Ces deux remarques rappellent la question de savoir quelle est la distance moyenne entre le lieu de naissance et celui de décès des gens. Plusieurs études se sont plongées dessus, notamment celle-ci, publiée dans Science en 2014 et qui se base sur Freebase((Ainsi que sur deux bases d’artistes célèbres, non nommées dans l’article du Boston Globe.)), qui a depuis été intégrée dans Wikidata, et a des caractéristiques similaires, notamment le biais de sélection inhérent((Il faut être notoire pour une raison ou une autre pour être dans la base.)).

De fait, l’étude ne visait pas tant à mesurer la distance moyenne globale pour l’ensemble de l’humanité((Je n’arrive pas à retrouver les chiffres, mais il me semble me souvenir que la majeure partie de la population mondiale vit et meurt à moins de 30 km de son lieu de naissance… Le livre The Limits to Travel de David Metz ne donne pas de chiffres pour les décès mais note que de nos jours, l’écart moyen entre les lieux de naissance de deux mariés britanniques est d’un peu plus de 50 mi.)), mais à s’appuyer sur ce biais de sélection pour identifier des « attracteurs de mort », c’est à dire des lieux où il meurt plus de gens notables qu’il n’en naît, et par ricochet identifier des capitales culturelles. C’est le cas de Paris, où Wikidata recense 18 532 naissances contre 22 205 décès.

Ils constataient cependant qu’au cours du temps, la distance moyenne entre le lieu de naissance et celui de décès des personnes étudiées augmentait, passant de 215 km au 14e siècle à 380 km au 21e. Les Bretons présents sur Wikidata, toutes époques confondues, semblent encore plus voyageurs, avec une distance moyenne de 473 km, mais pas mal de variation entre les départements : cela va de 420 km pour les Morbihannais⋅e⋅s à 510 pour les Brétilien⋅ne⋅s.

Image d’en-tête : Les Merveilles de la nuit de Noël / Burzudou Nedellek (détail), par Émile Souvestre, 1844.

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Catégories
Wikidata

Sunday Query : utiliser SPARQL et Python pour corriger des coquilles sur Wikidata

À mon tour de faire une #SundayQuery! Comme Harmonia Amanda l’a dit dans son propre billet, j’envisageais de faire un article expliquant comment créer un script Python permettant de corriger les résultats de sa requête.. Finalement, j’ai préféré en faire un autre, au fonctionnement similaire mais plus court et plus simple à comprendre. Le script pour Harmonia est cependant disponible en ligne ici.

Jeudi, j’ai publié un article au sujet des  batailles du Moyen Âge, et depuis, j’ai commencé à corriger les éléments correspondants sur Wikidata

L’une des corrections les plus répétitives était la capitalisation des libellés en français : comme ils ont été importés de Wikipédia, ils ont une majuscule inutile au début ( « Bataille de Saint-Pouilleux en Binouze » instead of « bataille de Saint-Pouilleux en Binouze »…)

La requête

Commençons par trouver tous les éléments présentant cette coquille.

SELECT ?item ?label WHERE {
  ?item wdt:P31/wdt:P279* wd:Q178561 .
  ?item rdfs:label ?label . FILTER(LANG(?label) = "fr") .
  FILTER(STRSTARTS(?label, "Bataille ")) .
}

http://tinyurl.com/jljf6xr

Quelques explications de base :

  • ?item wdt:P31/wdt:P279* wd:Q178561 .  cherche les éléments qui sont des batailles ou des sous-classes de batailles, pour être bien sûr que je ne vais pas virer sa majucule à un bouquin intitulé  « Bataille de Perpète-les-Olivettes »…
  • Sue la ligne suivante, je demande les libellés pour les éléments en question  ?item rdfs:label ?label .  et les filtre pour ne garder que ceux en français FILTER(LANG(?label) = « fr ») . . Comme j’ai besoin d’utiliser le libellé dans la requête et pas juste de l’afficher (et comme Harmonia Amanda l’a expliqué dans son billet de dimanche), je ne peux pas utiliser le servicce wikibase:label, et je me rabats donc sur le standard du web sémantique rdfs:label.
  • La dernière ligne est un FILTER  (filtre), qui ne garde que les résultats qui répondent à la fonction à l’intérieur. Ici, STRSTARTS  vérifie si ?label  commence avec « Bataille «  .

Au moment où j’ai écrit la version anglaise de ce texte, la requête renvoyait 3521 résultats. Beaucoup trop pour les corriger à la main, et je ne connais aucun outil déjà existant qui pourrait faire ça pour moi… Je suppose qu’il est temps de dégainer Python, du coup !

Le script Python

J’aime Python. J’adore carrément Python, même. Ce langage est génial pour créer une une application utile en une poignée de minutes, facile à lire (pour peu qu’on lise l’anglais) et pas constellé de séries d’accolades ou de points-virgules, et a des libs géniales pour les choses que je fais le plus avec : récupérer le contenus de pages web, trier des données, vérifier des ISBNs ((J’espère pouvoir bientôt quelque chose ici sur ce sujet.)) et faire des sites web. Oh, et pour faire des requêtes SPARQL et traiter les résultats ((En plus, les exemples dans la doc officielle sont basés sur Firefly. Yes sir, Captain Tightpants.)).

Deux charmeurs de serpent avec un python et deux cobras.
Et puis le nom du langage a un petit côté « charmeur de serpents » 😉

Premières remarques

Si vous ne connaissez pas du tout le Python, cet article n’est pas le bon endroit pour ça, mais il y a de nombreuses ressources disponibles en ligne ((Par exemple, https://www.codecademy.com/learn/python ou https://docs.python.org/3.5/tutorial/.)). Assurez-vous juste qu’elles sont à jour et pensées pour Python 3. La suite de cet article part du principe que vous avez une connaissance basique de Python (indentation, variables, chaînes de caractères, listes, dictionnaires, imports et boucles for.), et que Python 3 et pip sont installés sur votre machine.

Pourquoi Python 3 ? Parce que nous allons manipuler des chaînes qui viennent de Wikidata et sont donc encodées en UTF-8 et que Python 2 n’est pas hyper pratique pour ça. Et puis mince, on est en 2016, par Belenos !

Pourquoi pip ? Parce qu’on a besoin d’une libraire non-standard pour faire des requêtes SPARQL, appelée SPARQLwrapper, et que cette commande est le moyen le plus simple de l’installer :

pip install sparqlwrapper

Allez, on commence à scripter !

Pour commencer, un script qui fait une requête Sparql retournant la liste des sièges à corriger ((Oui, les sièges, j’ai déjà corrigé les batailles avant d’écrire le billet 😉 )):

#!/usr/bin/env python3

from SPARQLWrapper import SPARQLWrapper, JSON
from pprint import pprint

endpoint = "https://query.wikidata.org/bigdata/namespace/wdq/sparql"

sparql = SPARQLWrapper(endpoint)
sparql.setQuery("""
SELECT ?item ?label WHERE {{
  ?item wdt:P31/wdt:P279* wd:Q178561 .
  ?item rdfs:label ?label . FILTER(LANG(?label) = "fr") .
  FILTER(STRSTARTS(?label, "Siège ")) .
}}
""")  # Link to query: http://tinyurl.com/z8bd26h

sparql.setReturnFormat(JSON)

results = sparql.query().convert()

pprint(results)

Ça fait un bon petit paquet de lignes, mais que font-elles ? Comme on va le voir, la plupart vont en fait être incluses à l’identique dans tout script qui fait une requête  SPARQL.

  • Pour commencer, on importe deux choses du module  SPARQLWrapper : la classe SPARQLWrapper elle-même et la constante « JSON » qu’elle va utiliser plus tard (pas d’inquiétude, on n’aura pas à manipuler du json directement.)
  • On import aussi le module « Pretty printer » pour afficher les résultats de manière plus lisible.
  • Ensuite, on crée une variable qu’on nomme « endpoint », qui contient l’URL complète vers le point d’accès SPARQL de Wikidata ((Et non son accès web qui est simplement « https://query.wikidata.org/ »)).
  • Ensuite, on crée une instance de la classe SPARQLWrapper qui utilisera ce point d’accès pour faire des requêtes, et on les met dans une variable simplement appelée  « sparql ».
  • On applique à cette variable la fonction setQuery, qui est l’endroit où l’on rentre la requête de tout à l’heure. Attention, il faut doublonner les accolades (remplacer { et } par {{ et }}, car elles sont des caractères réservés dans les chaînes Python.
  • sparql.setReturnFormat(JSON)  dit au script que le résultat sera retourné en json.
  • results = sparql.query().convert() , enfin, fait la requête elle-même et convertit la réponse dans un dictionnaire Python appelé  « results ».
  • Et pour l’instant, on va juste afficher le résultat à l’écran pour voir ce qu’on obtient.

Ouvrons un terminal et lançons le script :

$ python3 fix-battle-labels.py 
{'head': {'vars': ['item', 'label']},
 'results': {'bindings': [{'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q815196'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Pskov',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q815207'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Silistra',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q815233'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Tyr',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q608163'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Cracovie',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q1098377'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Narbonne',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q2065069'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Hloukhiv',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q4087405'},
                           'label': {'type': 'literal',
                                     'value': "Siège d'Avaricum",
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q2284279'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Fort Pulaski',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q4337397'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Liakhavitchy',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q4337448'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Smolensk',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q701067'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Rhodes',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q7510162'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Cracovie',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q23013145'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Péronne',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q10428014'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Pskov',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q3090571'},
                           'label': {'type': 'literal',
                                     'value': 'Siège du Hōjūjidono',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q3485893'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Fukuryūji',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q4118683'},
                           'label': {'type': 'literal',
                                     'value': "Siège d'Algésiras",
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q5036985'},
                           'label': {'type': 'literal',
                                     'value': 'Siège de Berwick',
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q17627724'},
                           'label': {'type': 'literal',
                                     'value': "Siège d'Ilovaïsk",
                                     'xml:lang': 'fr'}},
                          {'item': {'type': 'uri',
                                    'value': 'http://www.wikidata.org/entity/Q815112'},
                           'label': {'type': 'literal',
                                     'value': "Siège d'Antioche",
                                     'xml:lang': 'fr'}}]}}

C’est un gros paquet de résultats mais on peut voir que c’est un dictionnaire qui contient deux entrées :

  • « head », qui contient les noms des deux variables renvoyées par la requête,
  • et « results », qui contient lui-même un autre dictionnaire avec la clef « bindings », associée avec la liste des résultats eux-mêmes, chacun d’entre eux étant lui-même un dictionnaire  Python. Pfiou…

Examinons un desdits résultats :

{'item': {'type': 'uri',
          'value': 'http://www.wikidata.org/entity/Q17627724'},
 'label': {'type': 'literal', 
           'value': "Siège d'Ilovaïsk",
           'xml:lang': 'fr'}}

C’est un dictionnaire avec deux clefs (label et item), chacune ayant pour valeur un autre dictionnaire qui à son tour a une clef « value » associée avec, cette fois, la valeur qu’on veut au final. Enfin !

Parcourir les résultats

Parcourons la liste « bindings » avec une boucle « for » de Python, pour pouvoir en extraire les résultats.

for result in results["results"]["bindings"]:
    qid = result['item']['value'].split('/')[-1]
    label = result['label']['value']

    print(qid, label)

Rapide explication sur la ligne  qid = result[‘item’][‘value’].split(‘/’)[-1]  : comme l’identifiant de l’élément est en fait stocké sous la forme d’une URL complète (« https://www.wikidata.org/entity/Q17627724 » et pas juste « Q17627724 »), il nous faut séparer cette chaîne à chaque caractère ‘/’, ce qu’on fait à l’aide de la fonction « split()« , qui transforme la chaîne en une liste Python contenant ceci :

['https:', '', 'www.wikidata.org', 'entity', 'Q17627724']

Nous ne voulons que le dernier élément de cette liste. En Python, c’est celui avec l’index -1, d’où le [-1] à la fin de la ligne. Enfin, nous stockons cette valeur dans la variable qid.

Lançons le script ainsi modifié :

$ python3 fix-battle-labels.py 
Q815196 Siège de Pskov
Q815207 Siège de Silistra
Q815233 Siège de Tyr
Q608163 Siège de Cracovie
Q1098377 Siège de Narbonne
Q2065069 Siège de Hloukhiv
Q4087405 Siège d'Avaricum
Q2284279 Siège de Fort Pulaski
Q4337397 Siège de Liakhavitchy
Q4337448 Siège de Smolensk
Q701067 Siège de Rhodes
Q7510162 Siège de Cracovie
Q23013145 Siège de Péronne
Q10428014 Siège de Pskov
Q3090571 Siège du Hōjūjidono
Q3485893 Siège de Fukuryūji
Q4118683 Siège d'Algésiras
Q5036985 Siège de Berwick
Q17627724 Siège d'Ilovaïsk
Q815112 Siège d'Antioche

Corriger le problème

On y est presque ! Maintenant, il reste à remplacer cet orgueilleux « S » majuscule par un plus modeste « s » minuscule :

label = label[:1].lower() + label[1:]

Que se passe-t-il ici ? Une chaîne Python fonctionne comme une liste, on peut donc lui demander de prendre la partie située entre le début de la chaîne « label » et la position qui suit le premier caractère (« label[:1] ») et forcer celui-ci en bas-de-casse (« .lower() »). Ensuite, on y concatène le reste de la chaîne (de la position 1 à la fin, donc « label[1:] ») et on réassigne ce résultat à la variable « label ».

Dernière chose, formater le résultat de manière compatible à QuickStatements:

out = "{}\tLfr\t{}".format(qid, label)
print(out)

Cette ligne semble barbare ? Elle est en fait assez simple : « {}\tLfr\t{} »  est une chaîne qui contient un premier emplacement pour le résultat d’une variable (« {} »), puis une tabulation, (« \t »), puis le mot-clef Quickstatements pour le libellé français (« Lfr »), une autre tabulation et enfin le second emplacement pour une variable. Ensuite, la fonction « format() » se charge de mettre le contenu des variables « qid » et « label » dedans. Le script final devrait ressembler à ça :

#!/usr/bin/env python3

from SPARQLWrapper import SPARQLWrapper, JSON

endpoint = "https://query.wikidata.org/bigdata/namespace/wdq/sparql"

sparql = SPARQLWrapper(endpoint)
sparql.setQuery("""
SELECT ?item ?label WHERE {{
  ?item wdt:P31/wdt:P279* wd:Q178561 .
  ?item rdfs:label ?label . FILTER(LANG(?label) = "fr") .
  FILTER(STRSTARTS(?label, "Siège ")) .
}}
""")  # Link to query: http://tinyurl.com/z8bd26h

sparql.setReturnFormat(JSON)

results = sparql.query().convert()

for result in results["results"]["bindings"]:
    qid = result['item']['value'].split('/')[-1]
    label = result['label']['value']

    label = label[:1].lower() + label[1:]

    out = "{}\tLfr\t{}".format(qid, label)
    print(out)

C’est parti :

$ python3 fix-battle-labels.py 
Q815196	Lfr	siège de Pskov
Q815207	Lfr	siège de Silistra
Q815233	Lfr	siège de Tyr
Q2065069	Lfr	siège de Hloukhiv
Q2284279	Lfr	siège de Fort Pulaski
Q1098377	Lfr	siège de Narbonne
Q608163	Lfr	siège de Cracovie
Q4087405	Lfr	siège d'Avaricum
Q4337397	Lfr	siège de Liakhavitchy
Q4337448	Lfr	siège de Smolensk
Q701067	Lfr	siège de Rhodes
Q10428014	Lfr	siège de Pskov
Q17627724	Lfr	siège d'Ilovaïsk
Q23013145	Lfr	siège de Péronne
Q815112	Lfr	siège d'Antioche
Q3090571	Lfr	siège du Hōjūjidono
Q3485893	Lfr	siège de Fukuryūji
Q4118683	Lfr	siège d'Algésiras
Q5036985	Lfr	siège de Berwick

On est bons ! Il ne reste plus qu’à copier-coller le résultat dans QuickStatements et attendre qu’il fasse le boulot tout seul.

Image à la une : Photographie de fontes de caractères par Andreas Praefcke (domaine public)

Enregistrer

Enregistrer

Catégories
Wikidata

De la classification sur Wikidata

Quand on classe des trucs, on a grosso-modo deux approches possibles : des cases hyper-pointues allant aussi loin que possible dans le détail, ou au contraire des cases très larges en laissant à l’utilisa⋅teur⋅trice le soin de croiser pour trouver ce qui l’intéresse. Wikimedia Commons a grosso-modo choisi la première approche, avec des catégories comme « [[Category:Castles in Andalusia at night]] ((Je suis déçu : il n’y a pas de sous-catégorie [[Category:Castles in Andalusia at night facing left]].)) », alors que Wikidata a plutôt choisi l’approche inverse, avec un grand nombre de propriétés que l’on peut croiser par le biais de requêtes SPARQL (entre autres), ce qui donne pour l’Alhambra de Grenade : « Nature de l’élément (P31) → château fort (Q23413) » et « Pays (P17) → Espagne (Q29) » et tout un tas d’autres déclarations ((Wikipédia, quant à elle, hésite entre ces deux approches, selon les catégories.)).

Un château en Espagne (allégorie)
Un château en Espagne (satire)

Je dis « plutôt choisi » parce qu’il arrive qu’on tombe sur des cas où une classe tente de mélanger plusieurs axes, et qui suffisent généralement à démontrer pourquoi cette approche est une mauvaise idée. En l’espèce, je vais me pencher sur l’élément « bataille du Moyen Âge (Q15991159) » : ça tombe bien, c’est un domaine qui me botte.

Le problème des classes aux limites arbitraires

Le premier problème qui vient à l’esprit, c’est les limites de la classe : si on se fie à sa description en français, la seule présente lors de sa création, cette classe est censée contenir des « bataille[s] ayant eu lieu pendant la période du moyen âge, en occident ». Bon, la description précise explicitement l’Occident qui n’était qu’implicitement défini par le fait que le Moyen Âge est une notion d’historiographie occidentale, mais les limites restent assez floues.

  • Bataille en soi est discutable (on peut se poser la question d’y inclure ou non les sièges, par exemple), mais partons du principe que l’on a la même définition que pour l’élément « bataille (Q178561) » tout court qu’il remplace en tant que nature de l’élément (P31).
  • Par contre, « la période du moyen âge », c’est largement plus subjectif. Les dates varient pas mal. Si la plupart des historiens s’accordent à situer le début à l’année 476 ((En revanche, la culture populaire a tendance à ignorer complètement le haut Moyen Âge. Tous les jeux de stratégie médiévale que je connais commencent en 1066 avec l’expédition de Guillaume le Conquérant. Si la période précédente est abordée, c’est dans des extensions, comme Crusader Kings II avec Charlemagne.)), la fin est plus floue. Même en ignorant le « long Moyen Âge » de Jacques Le Goff qui s’étend en gros de Justinien à la Révolution française, les dates généralement admises varient par pays mais sont situées dans la seconde moitié du XVe siècle.
  • Enfin, comme dit plus haut, le Moyen Âge est un concept occidental, ce qui recouvre une zone aux contours flous, aussi bien à l’époque actuelle que si on se limite au Moyen Âge : au début de la période, c’est l’Empire romain d’Occident, celui qui vient de s’effondrer sous les coups des barbares assoiffés de sang qui, etc., vous connaissez le roman national. À la fin, c’est, pour faire simple, la Chrétienté ((enfin pas l’Éthiopie non plus, faut pas déconner.)), ce qui pose d’autres questions : à partir de quand peut-on inclure les batailles dans les pays orthodoxes ? Et dans les pays scandinaves/germaniques/nordiques ? Et les batailles impliquant des forces européennes mais se passant ailleurs, comme les Croisades, on les compte ? Autrement dit pour ce dernier cas, on définit « Occident » par le lieu de l’action ou par l’origine des belligérants ?

Par comparaison, l’approche standard de Wikidata (en utilisant « nature de l’élément (P31)bataille (Q178561) », date (P585) ((ou « date de début (P580) » et « date de fin (P582) » si besoin.)), « lieu (P276) » et « participant (P710) » pour les cas abordés dans la liste ci-dessus) se révèle à la fois plus souple (on peut être très précis⋅e sur la date comme sur le lieu) et moins subjective que l’apposition de la classe bataille du moyen Âge…

Les données réelles

Du coup, avec des définitions aussi floues, on peut se demander comment les données sont utilisées…

Cherchons donc ça.

# Batailles du moyen-âge
SELECT ?item ?itemLabel ?lieuLabel ?date ?coords WHERE {
  ?item wdt:P31 wd:Q15991159 .
  
  OPTIONAL{ ?item wdt:P276 ?lieu . }
  OPTIONAL{ ?item wdt:P585 ?date . }
  OPTIONAL{ ?item wdt:P625 ?coords . }
  
  SERVICE wikibase:label { bd:serviceParam wikibase:language "fr,en" }
} ORDER BY ?itemLabel

On a donc 687 éléments ayant cette nature, dont voici la liste par ordre alphabétique.

Répartition géographique

Plaçons donc les résultats sur une carte :

bataillesmoyenagecarte

http://tinyurl.com/jf4kvzw

Ouch, ça pique. Je veux bien admettre qu’on compte les batailles au Proche Orient, probablement liées aux Croisades, mais des chevaliers médiévaux dans le Golfe de Guinée ? au Mexique ? au Japon ? Il semblerait que la limitation de la classe à l’Occident ne soit pas une évidence pour tout le monde. Argh. Mais on est au moins raccord sur la période alors ?

Répartition temporelle

bataillesmoyenagefrisehttp://tinyurl.com/hkb6cqf

Si on place les résultats sur une frise, c’est nettement meilleur que sur la carte, avec seulement deux résultats manifestement erronés : la bataille d’Andrinople en 378 et celle de Szikszó en 1588 (vous ne devriez pas les voir ressurgir dans les résultats, j’ai corrigé ça.) Reste que la limite de fin reste arbitraire, contrairement à une requête normale où l’on peut choisir celle qui nous intéresse, que ça soit 1453 ((Quand les Bretons sont venus sauver le cul des Français une énième fois à la bataille de Castillon. Ou alors c’est pour l’invention de l’imprimerie mobile par Gutenberg, ou la chute de Constantinople, allez savoir.)), 1492 ((Quand les Français, ingrats (cf. note précédente), s’emparent de « la ville de Rennes et la fille qui est dedans », à moins que ça n’ait trait à la fin de la Reconquista et à l’expédition de Christophe Colomb…)), ou n’importe quelle autre.

Si on résume, l’arbitraire des choix impliqués par une classe croisant de multiples critères la rend inutilisable en pratique, tout en compliquant la recherche des batailles « normales » puisque qu’on doit du coup inclure les sous-classes, juste pour récupérer les batailles ayant eu lieu en Europe (ou pas) entre 476 et 1453, ou 1492, ou 1500 (enfin on l’espère).

Ma conclusion ? Comme disait Jeanne la Flamme au siège d’Hennebont, foutez-y-moi le feu.

jeanne_flamme
Jeanne la Flamme, par Jeanne Malivel (1926)

Image d’en-tête : Le Combat des Trente (détail), par Pierre Le Baud (1480-1482)

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Enregistrer

Catégories
Wikidata

Prototypage rapide d’entités Wikidata

Wikidata est un projet puissant, mais pour pouvoir en profiter, il faut le remplir. Bien sûr, il est possible d’ajouter des données à la main directement sur le site : ça fonctionne sans souci mais que faire quand on a plusieurs dizaines d’entrées ? Plusieurs centaines ? Avec le temps, quelques outils ont vu le jour permettant d’automatiser un peu ce processus, comme l’indispensable QuickStatements ; là encore, il faut bien lui fournir les données qu’il mange et tout ceci est parfois bien fastidieux. Est-ce qu’on ne peut pas aller plus loin ?

Une entrée wikidatienne sur un être humain, par exemple, possède des champs plus ou moins codifiés :

  • Une nature de l’élément égal à Q5, « être humain »
  • Un genre (masculin, féminin, etc.)
  • Une date et un lieu de naissance
  • Une date et un lieu de décès
  • Un pays de nationalité
  • Une occupation
  • Un prénom et un nom de famille

Toutes ces propriétés ne se rencontrent pas à chaque fois et on peut en rajouter d’autres, mais est-ce que ça ne serait pas intéressant d’avoir une sorte de formulaire où on se contenterait de remplir les cases correspondantes, histoire de créer rapidement un squelette d’entité Wikidata ? Pour voir, j’ai codé l’utilitaire « human » : vous mettez ce qu’il faut dans les champs, vous appuyez sur le bouton et il produit le code à destination de QuickStatements. J’ai le sentiment qu’on peut ainsi gagner du temps et on n’oublie rien.

Histoire d’aller un peu plus loin, je me suis penché sur la base Joconde, qui a le goût d’être remplie avec pas mal de soin. J’en ai sorti un autre utilitaire, baptisé Joconde parce que je suis un gars avec une imagination débordante. Sa fonction : parser une fiche Joconde, en retirer les champs qui vont bien (titre, auteur, sujets représentés, etc.) et présenter le résultat dans un formulaire pour correction avant envoi à QuickStatements. Les champs corrigés sont stockés en base, histoire que si l’utilitaire puisse ressortir la correction s’il retombe dessus (comme ça, « MONET Claude » est automatiquement corrigé en « Claude Monet, peintre français, Q296 »). On y gagne du temps.

Personnellement, je pense que cette idée de formulaires pré-remplis est à creuser, pour Wikidata. Qu’en pensez-vous ?

PS : j’imagine que mon outil pour Joconde doit enfreindre des milliers de lois, de licences et de copyrights. Je laisse le soin aux Wikimédiens que ça intéresse de discuter de la chose et de décider s’il faut supprimer toutes mes contributions. Prévenez-moi juste du résultat final.

(Image d’en-tête : détail de La Joconde, par Léonard de Vinci (domaine public))

Mise à jour du 28 septembre 2016 : j’ai placé le code des outils en question sur GitHub : https://github.com/PoulpyFR. Bien sûr, c’est codé n’importe comment et pas commenté. 🙂

Catégories
Wikidata

Ben Whishaw, Broadway, la RADA et Wikidata

(English version here)

Bonjour tout le monde, ici Harmonia Amanda squattant le blog d’Ash_Crow. Il m’a été suggéré de faire un billet de blog pour vous raconter tout ce que je fais en ce moment en rapport avec la RADA (Royal Academy of Dramatic Art) sur Wikidata. Pour m’assurer que personne ne le lira, j’ai donc écrit un truc long, bourré de notes de bas de page et avec même des vrais bouts de SPARQL dedans. Ne me remerciez pas.

Comment ça commence : The Hollow Crown

Tout est de la faute de Ben Whishaw. Je regardais tranquillement les adaptations de Shakespeare par la BBC (et pour celleux qui ne connaissent pas The Hollow Crown, je conseille) et je me disais que l’acteur qui joue Richard II méritait une récompense pour ce rôle, parce qu’il est simplement extraordinaire ((Il n’est pas le seul, Rory Kinnear est excellent aussi en Bolingbroke (et Patrick Stewart ♥) mais Bolingbroke est intéressant dans la pièce de Shakespeare, alors que Richard II, c’est le type qui se tape de longues tirades sans qu’il ne soit ni clairement un gentil auquel s’attacher, ni clairement un méchant qu’on pourrait détester. Dans mon expérience, selon les adaptations, c’est soit un personnage saoulant, soit un personnage tellement mal joué qu’il en devient ridicule. Il ne commence à acquérir une certaine dimension qu’à l’acte IV ce qui est un peu tard, avouez-le. Sauf que Whishaw en enfant-roi-devenu-adulte-mais-pas-vraiment, tour à tour capricieux et christique, m’a rendu ce personnage vivant bien avant ce fameux Acte IV. Je pourrais faire un billet de blog entier sur The Hollow Crown, acteurs, costumes et décors (et la cinématographie ! une des grandes réussites aussi) mais il paraît que je suis là pour vous parler de Wikidata et de la RADA et vous verrez que ce sera bien assez long à venir comme ça).)) ((En fait il a eu un BAFTA pour ce rôle, comme quoi mon opinion a été quelque peu partagée.)). Je suis donc allée traîner sur sa page Wikipédia et en bonne Wikimédienne, j’ai décidé de l’améliorer un peu : pour le moment ((Oui, j’ai vaguement commencé à récupérer des sources pour rédiger correctement l’article mais 1. je n’ai jamais écrit d’article sur une personne vivante 2. j’ai été un peu occupée depuis, comme vous allez le voir dans le reste de l’article.)) j’ai surtout nettoyé le code et arrangé un peu l’accessibilité pour les lecteurs d’écran. À défaut de le labelliser tout de suite, je me suis dit que ce serait sympa de compléter correctement son entrée Wikidata. C’était le début. Comme je le disais, tout est de la faute de Ben Whishaw.

Ben_Whishaw
Ben Whishaw en 2008 par KikeValencia – CC-BY-SA

Wikidata : petites modifications

Au début, ça avait l’air simple, il fallait juste mettre des occupations plus précises (il n’est pas juste « acteur », mais acteur de théâtre, de télévision, de cinéma…). Il a reçu un paquet de récompenses, qu’il importait de lister (P166), et pour chacune d’entre elles ajouter l’année où il l’a reçue (P585) ainsi que l’œuvre concernée (P1686), voire avec qui il a partagé la récompense (P1706). Et on peut faire pareil pour celles pour lesquelles il a juste été nommé (P1411) mais n’a pas gagné. Et on peut aussi lister tous ses rôles, ce qui ne se fait pas sur son entrée Wikidata à lui mais en utilisant P161 « distribution » avec la valeur « Ben Whishaw (Q342617) » sur les entrées des œuvres en question. Parfois on peut même qualifier l’information en utilisant P453 (rôle) quand le personnage lui-même a une entrée Wikidata (par exemple Q dans James Bond ((Oui, parce qu’il joue aussi dans James Bond et y a d’ailleurs un nombre impressionnant d’actrices/eurs shakespearien⋅ne⋅s dans les derniers James Bond.))).

Jusque-là, rien que de très facile. Bon, le truc, c’est que Whishaw au départ, c’est un acteur de théâtre. Je veux dire, il s’est fait connaître vers 23 ans en jouant Hamlet ((Parce que Richard II n’était pas son premier rôle shakespearien, ni même son deuxième, vu qu’il a aussi joué Ariel dans l’adaptation de La Tempête avec Helen Mirren en Prosper(a).)) à l’Old Vic. C’est un peu étrange de voir ainsi listés tous ses rôles télévisuels et pas ses performances théâtrales (Mojo, Bakkhai…). Donc j’ai commencé à creuser un peu côté théâtre et laissez-moi vous dire que le théâtre sur Wikidata… ben c’est au moins autant le bazar que sur Wikipédia. C’est dire.

Old_Vic_Theatre
Old Vic Theatre par MrsEllacott – CC-BY-SA 3.0.

Ce serait l’endroit idéal dans ce billet pour vous parler des ontologies, du web sémantique et des questions d’organisation du savoir mais le consensus parmi les gens ayant relu ce billet est qu’il est déjà bien assez long et que je ferais mieux de me concentrer sur la RADA (qui se fait attendre) et de parler de ça une autre fois.

L’Internet Broadway Database

Pendant que j’étais donc en train de réfléchir aux relations entre « art », « œuvre », « genre » et « performance », j’ai appris que Whishaw était en ce moment à Broadway où il joue John Proctor dans The Crucible d’Arthur Miller dans une mise en scène d’Ivo van Hove ((Vous vous en fichez peut-être, mais là, j’ai juste envie d’aller à Broadway. Bref.)). Or Broadway a une très bonne base de données (IBDB, Internet Broadway Database). Bien fichue, relativement complète, avec un nombre d’erreurs relativement restreint, bref le bonheur. Et encore mieux, Wikidata a déjà des propriétés pour lier des entrées à cette base (et pas que pour les humains, il y a les mêmes pour les théâtres, pour les œuvres et pour les productions) ((Oui, j’ai créé l’item Wikidata de la production actuelle.)).

Walter Kerr Theatre, , publicité pour Grey Garden - Michael J Owens CC-BY 2.0
Walter Kerr Theatre, , publicité pour Grey Garden – Michael J Owens CC-BY 2.0

Évidemment, personne n’avait encore exploité cette base proprement et il y avait pas mal d’erreurs dans les utilisations wikidatiennes. J’ai donc nettoyé tous les usages de ces propriétés sur Wikidata. Et sur Wikipédia, parce que les erreurs viennent de là ((Dans mon expérience, s’il y a une erreur sur Wikidata, elle vient presque toujours de Wikipédia et l’IBDB ne faisait pas exception.)). J’ai râlé contre les Wikipédien⋅ne⋅s qui sourcent n’importe comment (ou ne sourcent pas), qui ne sont pas philosophiquement choqué⋅e⋅s quand iels associent une œuvre à l’identifiant d’une production voire qui pensent que l’identifiant IMDB (Internet Movie Database) est le même que l’identifiant IBDB (ahah NON) mais, comme je suis Wikimédienne, j’ai nettoyé malgré tout.

J’en suis arrivée à la conclusion que ce serait encore mieux si au lieu d’avoir quelques liens corrects on liait vraiment toutes les entrées. Passer de « j’ai-bossé-sur-Ben-Whishaw-donc-j’ai-cherché-son-identifiant-IBDB » à « voici la liste complète des identifiants IBDB, trouvons leurs entrées Wikidata correspondantes ». Joie des joies, il existe un outil merveilleux du nom de Mix n’ Match ((Et qui existe en version jeu de téléphone portable, pour ceux qui veulent jouer à améliorer Wikidata sur leur téléphone portable (et qui ont un téléphone portable qui va sur internet).)). Là encore je pourrais faire une présentation détaillée de cet outil mais dans le cadre de cet article je vais me contenter de dire qu’il nécessite de récupérer au préalable la totalité des identifiants valides de la base de données à lier à Wikidata, ce que j’ai donc commencé à faire (et je remercie pour cela Ash_Crow ((pour le python)), Dereckson ((pour le serveur)) et Rama ((pour le soutien moral et avoir regardé The Hollow Crown avec moi))). Récupérer tous ces identifiants prend du temps (pour le moment je n’ai importé que la partie de la base sur les œuvres, si vous voulez aider ((Il faut associer le bon élément Wikidata à chaque entrée de l’IBDB ou marquer l’élément comme à créer.))). Il fallait que je m’occupe en attendant que les scripts finissent de tourner. C’est là que j’ai remarqué que Ben Whishaw (oui, parce que c’est toujours de sa faute) avait été étudiant de la RADA (Royal Academy of Dramatic Art) ((Qui a dit : « enfin ! » ?)).

La RADA

Présentation

Le truc cool sur Wikidata ((En fait, il y a plein de trucs cools sur Wikidata.)) c’est que non seulement on peut indiquer (P69) où les gens ont fait leurs études, mais en plus on peut apporter plein de précisions : la date de début (P580), celle de fin (P582), le diplôme préparé (P512), la principale spécialité d’études (P812)… Il n’y avait pas de sources. Ça m’a énervée. Je suis allée en chercher. Et là… RADA !

RADA Theatre, Malet Street, Londres -- CC-BY-SA 2.0
RADA Theatre, Malet Street, Londres — CC-BY-SA 2.0

Oui. La RADA a mis en ligne les profils de ses anciens élèves. Voilà la fiche de Whishaw pour les curieu⋅ses⋅x ((Où l’on apprend qu’il pratiquait le « cat breeding », information importante s’il en est et que non, je n’ai pas encore réussi à entrer dans Wikidata. Je suis déception.)). Bref, je cherchais une source et je suis tombée sur une mine d’or. Là, la Wikimédienne en moi s’est dit : non mais attends, tu ne vas pas sourcer que pour Whishaw, tu vas pouvoir sourcer tous les anciens étudiants avec à chaque fois leur année de diplôme, leur diplôme et tout ça et faire plein de statistiques démentes à partir de requêtes SPARQL ! (et puis ça t’occupera le temps que tu récupères les identifiants de tous les gens ayant un jour bossé dans un spectacle à Broadway).

Naïvement, je me suis dit que la RADA n’avait pas tant d’élèves que ça par année et que ça ne prendrait donc pas un temps fou ((Je suis quelqu’un d’optimiste.))…

Identification des éléments concernés

Sur Wikidata

Pour commencer j’ai essayé de savoir ce qui existait déjà sur Wikidata. J’ai donc fait une petite requête pour trouver la totalité des éléments Wikidata ayant P69:Q523926 (scolarité à la Royal Academy of Dramatic Art). J’ai croisé avec la catégorie anglophone. En fait, quelqu’un a, il y a quelques mois, ajouté P69:Q523926 sur tous les éléments catégorisés comme « Alumni of the Royal Academy of Dramatic Art » ((Ou comment importer sur Wikidata les erreurs des Wikipédias (voir note 7).)). Bref, comme à l’époque je n’avais pas encore l’intention d’écrire ce billet de blog, il y en avait environ 650, avec relativement peu d’écart entre WD et la catégorie anglophone (donc peu d’entrées WD sans articles sur WP:en a priori). Il y avait plus d’éléments sur Wikidata que dans la catégorie anglophone mais toutes les entrées de la catégorie sortaient bien dans la liste Wikidata.

Pour suivre mon avancement, je n’ai donc à faire que deux requêtes : la première pour lister les étudiants de la RADA, la deuxième pour lister les étudiants de la RADA avec une date de sortie de l’école.

En WikidataQuery, parce que c’est tellement simple que ce n’est pas la peine de sortir SPARQL ça donne ((En utilisant Autolist bien sûr.)) :

claim[69:523926]

et

claim[69:523926]{claim[582]}

Simple.

Il y avait déjà quatre ou cinq élèves où l’information « date de sortie de l’école » était déjà présente mais il n’y avait soit pas de source, soit une source autre que celle de la RADA. J’ai décidé de ne pas m’en soucier et que je les traiterais en même temps que les autres.

Sur Wikipédia

J’avais déjà constaté que la totalité des articles de la catégorie anglophone « Alumni of the Royal Academy of Dramatic Art » avait la propriété P69 « scolarité » avec la valeur RADA sur Wikidata. Je sais aussi qu’il y a plus d’entrées marquées sur WD que dans la catégorie : le décalage vient-il d’articles anglophones non catégorisés ((Spoiler : oui, en partie.)) ou d’entrées Wikidata sans article correspondant en anglais ((Spoiler : oui, aussi.)) ?

La catégorie existe dans d’autres langues que l’anglais : en espagnol, en arabe, en français, en latin, en polonais, en russe, en anglais simplifié, en turc et en chinois. Mais un survol de chacune de ces catégories m’a indiqué qu’elles sont beaucoup moins remplies que la catégorie anglophone (assez logique pour une école londonienne) et qu’il est donc peu probable qu’elles me servent beaucoup.

Cependant, il n’y a pas que la catégorie pour repérer les étudiants. WP:en a aussi une liste (List of RADA alumni). Cette liste ((Liste qui est sous forme manuelle et non de tableau, ce qui est une hérésie car ne permettant pas facilement un tri par année.)) est intéressante car elle indique entre parenthèses l’année d’obtention du diplôme, ce qui est une information absente de la catégorie.

Par contre, il aurait été trop demander que la totalité des entrées de la catégorie soient présentes dans la liste, ou que la totalité des entrées de la liste soient dans la catégorie… Oui, vous avez bien lu, les deux systèmes de la Wikipédia anglophone ne se recoupent pas.

Identifions : de la RADA vers Wikidata

Le plus simple pour commencer me paraissait de partir de la base RADA et de regarder s’il y avait une correspondance sur WD/WP : en effet, même si beaucoup d’étudiant⋅e⋅s de la RADA sont devenus connu⋅e⋅s, iels n’ont pas tou⋅te⋅s un article Wikipédia, il ne faut pas exagérer. Dans un monde idéal où Wikipédia et Wikidata seraient complètes après avoir fini de vérifier toutes les entrées de la RADA je devrais être passée sur les 700 et quelques entrées Wikidata déjà repérées. Mais comme Wikipédia et Wikidata n’ont jamais prétendu être complètes, je me doutais avant de commencer que j’aurais des pertes.

Recherche artisanale par nom

Au début, je me suis dit que j’allais simplement chercher dans Wikidata chaque nom d’élève listé sur le site de la RADA et vérifier si je l⋅a⋅e trouvais. En commençant par 1906, qui est la première année avec des diplômé⋅e⋅s ((En l’occurrence, un seul.)) vu que l’école a été fondée en 1904.

Très vite, les premiers problèmes sont apparus avec cette méthode artisanale.

En 1907 par exemple, la⋅e seul⋅e élève est « H Bentley ». Le système de recherche de Wikidata fait que si je fais une recherche sur ce nom, je n’aurai comme résultat que les « H Bentley » et « H. Bentley » (et pas Henry, Harriet ou autres). Si j’ai de la chance, quelqu’un aura pensé à ajouter « H Bentley » en alias de l’élément Wikidata et iel sortira dans la recherche. Si je n’en ai pas, je suppose que je peux toujours faire une requête de la forme :

FIND H% Bentley in Labels in Alias

(lien vers la requête autolist) et espérer que quelque chose en sorte ((Spoiler : non.)). Je peux aussi rechercher « Bentley » et passer rapidement sur toutes les entrées… Bref, l’identification n’est pas simple.

Fautes d’orthographe et la base mal remplie

D’autant qu’il peut y avoir des fautes d’orthographe dans la base RADA : je suis quasiment certaine que Joan Mibourrrne n’a pas en réalité trois R dans son nom de famille ou Dorothy Reeeve trois E.

Desmond Llewellyn ((Parce que Whishaw n’est même pas le premier étudiant de la RADA à avoir joué Q dans James Bond.)) est par exemple entré dans la base RADA sous le nom de Desmond Wilkinson (il s’appelle Desmond Wilkinson Llewellyn d’après l’article en anglais, ce qui n’est même pas présent sur l’article en français). En fait ce n’est pas tout à fait vrai : lui est entré à la fois sous le nom de « Desmond Llewellyn » (fiche ici) et sous le nom de « Desmond Wilkinson ». Oui, il a deux fiches la même année.

Desmond Llewelyn en 1983 - Towpilot CC-BY-SA 3.0
Desmond Llewelyn en 1983 – Towpilot CC-BY-SA 3.0

Les doublons dans la base sont nombreux : la probabilité que deux étudiantes différentes, nommées Alison James et Allison James, soient diplômées toutes les deux en 1954 me semble assez faible.

Les homonymes

Même sans faute d’orthographe, si on trouve un homonyme, ce n’est pas nécessairement correct. Rose Hersee, étudiante de 1908 n’est pas Rose Hersee, la chanteuse née en 1845. Oui, il faut vérifier. Dans nombre de cas, cela a signifié aller fouiller l’article Wikipédia (qui parfois mentionne la RADA ! Parfois même avec des sources !) et surtout les sources de ces articles (pour la première moitié du XXe siècle, cela a essentiellement signifié lire des dizaines de nécrologies). Parfois, bingo ! le lien pouvait être fait. Parfois le non-lien pouvait être fait. Dans nombre de cas, je n’ai pas pu trancher avec une recherche de ce type parce que les profils de la RADA avant le XXIe siècle sont pour le moins sommaires.

Il peut y avoir plusieurs élèves de la RADA avec le même nom, ou des cas où la même personne a suivi plusieurs formations (surtout le cas dans les diplômes techniques, où certains noms reviennent). Côté Wikidata les homonymies sont légion (surtout avec des noms comme « John Jones »…), donc il faut parfois fouiller dans plusieurs centaines de résultats pour trouver la personne la plus probable (et remercier au passage les personnes qui remplissent les descriptions ((Les descriptions, c’est bien, mangez-en.))).

Les pseudonymes

Iels ont des pseudonymes. Un nombre impressionnant de femmes sont devenues connues sous le nom de leur mari, et personne n’a mis en alias leur nom de naissance. Un nombre impressionnant a simplement pris un pseudonyme (Conrad Havord est devenu connu sous le nom de « Conrad Phillips » par exemple). Parfois c’est l’inverse, iels se sont inscrits à la RADA avec un pseudonyme/nom d’épouse/surnom et l’article Wikipédia a conservé le nom de naissance (par exemple, June Flewett est inscrite à la RADA sous le nom de Jill Freud, son diminutif et le nom de famille de son mari). J’aime beaucoup aussi Priya Rajvansh inscrite à la RADA sous le nom de Vera Singh. Tous ces cas ne sont identifiables que si quelqu’un a pensé à mettre les alias sur Wikidata ((Les alias, c’est bien aussi, mangez-en.)). Et parfois il y a des cumuls de pseudonymes plus fautes d’enregistrement, comme dans le cas de Kay Hammond (nom de scène), dont le véritable nom est « Dorothy Katherine Standing » mais qui est enregistrée à la RADA comme « Kathrine Standing », ce qui ne facilite pas l’identification puisque ne ressortant pas dans les recherches sur Wikidata.

Est-ce que Jean Rhys, née « Ella Gwendolen Rees Williams » en 1890 et ayant utilisé nombre de pseudonymes, est Ella Reeve, l’étudiante de la RADA diplômée en 1909 ((Dans ce cas précis c’est probable mais pas certain. Certains cas sont bien plus douteux.)) ? Vern Agopsowicz est devenu connu sous le nom de John Vernon… Je pourrais continuer longtemps.

Henry Darrow et John Vernon - Domaine public aux États-Unis
Henry Darrow et John Vernon – NBC Television, Domaine public aux États-Unis

Arkanosis à la rescousse

À ce stade Arkanosis a eu pitié de moi et m’a créé un script pour faciliter le travail (avec une retouche par Ash_Crow pour être encore plus simple pour moi après) :

#! /bin/sh

if [ $# -ne 2 ]; then
    echo 'Usage: rada.sh  '
    exit 1
fi

profile=$1
year=$2

echo "Year $year
        •  » > list-$profile-$year.html wget -q ‘https://www.rada.ac.uk/profiles?search=’$profile’&yr-acting=’$year’&yr-technicaltheatrearts=’$year’&crs-technicaltheatrearts=&yr-theatrelab=’$year’&yr-directing=’$year’&crs-directing=&fn=&sn=’ -O – | \ sed -n ‘s@.*fn=\([^&]*\).*sn=\([^ »&]*\).*@\1 \2@p’ | \ while read firstname lastname; do echo « 
      • $firstname $lastname wikidata » wget -q ‘https://www.wikidata.org/w/api.php?action=query&list=search&srwhat=text&srsearch=’$firstname’+’$lastname -O – | \ sed -n ‘s@.*title&.*\(Q[0-9]\+\)&.*@\1@p’ | \ while read qid; do if grep -q $qid unhandled.lst; then echo  » $qid » fi done echo « 

 » done >> list-$profile-$year.html echo  »  » >> list-$profile-$year.html

Les urls de la base RADA étant systématiquement de la forme année/prénom/nom ((Merci à la RADA d’avoir fait ça proprement.)), il en a simplement extrait des listes par année avec un élève par ligne, sous la forme :

  • Nom de l’élève (lien vers la fiche RADA) / Wikidata (lien qui pointe sur la page de recherche avec ce nom) / éventuels Qid qui sont sortis dans le 2e lien et qui donnent aussi un résultat dans la liste des P69:Q523926 (déjà listés comme élèves de la RADA)

Par exemple une ligne pour un élève de la formation « acting » en 1947 est :
harold goodwin wikidata Q1585750

Toutes les lignes n’ont pas de Qid, loin de là (les lignes avec sont même largement minoritaires). Tous les Qid ne sont pas corrects : comme je le disais, il y a quelques homonymes à la RADA ; ou alors le système de recherche de Wikidata a pour une fois ratissé trop large et sorti des combinaisons prénom/nom qui ne correspondent pas à la fiche RADA (par exemple une recherche sur Romany Evens suggère George Bramwell Evens sur Wikidata). Néanmoins, l’immense majorité des lignes avec un Qid a effectivement permis de repérer de véritables étudiant⋅e⋅s tandis que le pourcentage était bien plus faible sur les lignes sans Qid pré-suggéré. Merci encore à Arkanosis.

Même avec ces listes pré-établies, n’ayant plus qu’à cliquer sur les liens au lieu de faire un copié-collé à la main, il a fallu passer manuellement sur toutes les entrées ((Tout compte fait, il y en a quand même beaucoup.)). Le problème de tirer les noms des url, c’est aussi la non-gestion des apostrophes et des espaces. Une recherche de peter otoole sur Wikidata ne renvoie pas Peter O’Toole par exemple.

Conclusion de la RADA vers Wikipédia

Un certain nombre d’entrées ont pu être identifiées (835 très exactement à la fin du travail sur scripts) mais la majorité des élèves listés de la RADA n’ont renvoyé aucun résultat (on s’y attendait) et un nombre important n’a renvoyé que des résultats incertains. J’ai ainsi pour le moment 442 lignes dans un tableur avec une entrée RADA et une entrée Wikidata potentielle, en attente de sources pour confirmer, et ce alors que je n’ai pensé à les lister que lorsque j’avais déjà traité un bon quart de la base : on parle donc de plusieurs centaines de cas où une recherche plus approfondie va être nécessaire.

Aparté sur les féminins

À force de regarder les éléments sur des act⋅rices⋅eurs, je me suis aperçue qu’un grand nombre d’actrices avaient une description en anglais de la forme « Nationalité actor ». Quelqu’un a fait passer un robot pour compléter automatiquement les descriptions et ne s’est pas aperçu que cela mettait une description au masculin y compris sur les femmes.

Donc j’ai requêté le nombre d’entrées Wikidata avec genre (P21) féminin (Q6581072) et une description en « % actor », j’ai mis tout ça dans un csv, que j’ai passé dans CSVtoQuickStatements, puis dans QuickStatements ((Outils qui mériteraient aussi une présentation détaillée.)), et quelques dizaines de milliers de modifications plus tard j’aimerais vous rappeler de bien faire attention lorsque vous codez vos scripts, ou de vous relire après coup. Merci.

Identifions : de Wikipédia vers la RADA

J’ai commencé à regarder les étudiant⋅e⋅s présent⋅e⋅s sur WP mais pas dans la liste traitée sur WD. Le grand retour de la méthode artisanale !

Dans un monde parfait, une fois fini de traiter les scripts, le nombre d’entrées Wikidata marquées comme élèves de la RADA et le nombre d’entrées marquées comme élèves de la RADA avec une date de fin de renseignée (et donc ayant un lien vers la base RADA comme source) aurait dû correspondre. Le monde n’étant pas parfait, il nous reste alors plus de gens que Wikipédia indique comme élèves qu’il n’a été possible d’identifier du côté de l’école. Il y a un certain recoupement avec les lignes du tableur précédemment mentionné, mais pas si important : l’essentiel du tableur est constitué d’act⋅rices⋅eurs pour lesquel⋅le⋅s il ne m’a pas été possible de trouver une mention de leur école.

En utilisant autolist, il est possible de demander la liste des entrées présentes dans la catégorie de WP:en et ne répondant pas à la requête « claim[69:523926]{claim[582]} »

Cela donnait 132 résultats, sur lesquels je suis passée manuellement. Ce passage a permis d’identifier 23 personnes de plus (pseudonymes ou noms de naissance pour les femmes essentiellement, présents dans le texte des articles, mais non renseignés en alias sur Wikidata : la recherche sur ce site de ces noms-là ne renvoyait pas aux articles Wikipédia correspondants).

Fin avril, la catégorie anglaise comptait 907 entrées, Wikidata 953 entrées et seules 835 entrées avaient en réalité été traitées proprement avec une véritable source. De plus il ne faut pas oublier que toutes les entrées Wikidata ne correspondent pas à un article sur la Wikipédia en anglais : un certain nombre d’act⋅rices⋅eurs ont des entrées sur des Wikipédias en d’autres langues mais pas sur l’anglophone et une petite dizaine n’a pas d’article Wikipédia associé du tout, leur entrée Wikidata ayant souvent été créée dans ce cas pour remplir complètement la distribution d’un film.

SELECT ?student ?studentLabel {
  ?student wdt:P31 wd:Q5 . # human
  ?student p:P69 ?statement .		# Student of...
  ?statement ps:P69 wd:Q523926 .	# ...RADA
  FILTER NOT EXISTS { ?statement pq:P582 ?x .} # with no end date
  
  SERVICE wikibase:label {
		bd:serviceParam wikibase:language "en" .
	}
  }

lien vers la requête des cas à traiter.

Les incohérences

La liste à traiter provient essentiellement de la Wikipédia en anglais : la requête SPARQL (sur Wikidata mais sans date de fin) signalait 112 erreurs fin avril quand la requête autolist (dans la catégorie anglophone mais sans date de fin sur Wikidata) n’en renvoyait que 110 (et l’un d’eux correspond à un article depuis supprimé de WP:en). Je n’ai pas vérifié systématiquement la centaine d’historiques concernés mais à chaque fois que j’ai regardé, j’ai pu confirmer que l’information était arrivée sur Wikidata lors de l’import massif de la catégorie.

Le travail consiste désormais soit à trouver sous quel nom la personne a été enregistrée côté RADA (puisqu’il y a des fautes de frappe, par exemple) ou à trouver d’où peut bien provenir l’erreur. Ash_Crow a ainsi corrigé George Bernard Shaw catégorisé comme étudiant alors qu’il a légué une partie de son héritage à la RADA ((Ce qui est fort aimable de sa part mais n’en fait pas un étudiant.)). Pour Armaan Kirmani, son entrée IMDB indique qu’il a été l’élève d’un enseignant de la RADA, ce qui ne signifie pas qu’il y a étudié non plus…

Homme barbu, photo en noir et blanc
George Bernard Shaw en 1915 – Domaine public aux États-Unis

Dans cette centaine de cas problématiques, il y a un peu tous les cas de figure, de ceux qui ne mentionnent pas du tout la RADA, à ceux qui disent clairement que la personne y a étudié mais sans citer de sources ((Par exemple Margaret Rutherford : un compte ajoute sommairement l’information sans source en 2008, ce qui conduit la page à être catégorisée en 2010…)), voire à ceux qui sourcent avec une déclaration qui n’est pas si claire que ça. En effet, la RADA ne propose pas que des formations longues diplômantes : elle organise aussi un certain nombre de stages et ateliers. Si un⋅e actrice⋅eur a participé à un stage de deux jours à la RADA, iel n’apparaîtra pas dans la base RADA des ancien⋅ne⋅s élèves mais iel pourra déclarer sincèrement en interview qu’iel a appris tel truc à la RADA… d’ici à ce qu’un⋅e Wikipédien⋅ne enthousiaste décide que ça fait d’ellui un⋅e ancien⋅ne élève, il n’y a qu’un pas. Par exemple Ash_Crow a trouvé une source (même si de qualité douteuse) affirmant qu’Émilie Rault avait bien étudié à la RADA mais elle n’est nulle part dans la base parce qu’il est extrêmement probable qu’elle n’a fait qu’y suivre des stages vu qu’elle était en master de musicologie à la Sorbonne en même temps. Ce qui pose la question de l’utilisation de la propriété « scolarité » sur Wikidata : doit-on la réserver pour les formations diplômantes ou accepter y compris jusqu’aux stages de quelques jours ?

Les écarts entre la liste et la catégorie

Comme préalablement signalé, la « List of RADA alumni » ne correspond pas à la liste de la catégorie. Systématiquement, à chaque fois que j’identifiais une personne et l’article associé, j’ai ajouté son nom dans la liste et je l’ai catégorisé correctement. Je n’ai cependant pas encore trouvé le courage de vérifier les deux listes proprement pour identifier les décalages. La liste manuelle devrait être plus complète que la catégorie, puisque comprenant également des liens rouges (non existant sur la Wikipédia en anglais) avec des liens vers l’article dans d’autres langues.

Xavier Combelle ayant eu l’amabilité de lister les différences entre la catégorie et la liste début mai, il reste bien dans la catégorie la centaine de cas problématiques précédemment évoqués (non présents dans la liste donc) et dans la liste, outre les liens rouges tout à fait normaux, dix-huit articles non catégorisés. Aucun d’entre eux ne renvoie de lien évident avec une entrée de la RADA, à l’exception de Xenia Kalogeropoulou qui a pu être identifiée avec Xenia Calogeropoulos et être catégorisée dans la foulée. Parmi ces cas, certains articles Wikipédia évoquent explicitement que la formation à la RADA a pris la forme d’ateliers ou de stages. Nous revenons à la question : quel cursus faut-il avoir suivi pour être considéré⋅e comme un⋅e ancien⋅ne étudiant⋅e ?

Les problèmes sur la base RADA

Une fois listés tous les problèmes côté Wikipédia/Wikidata (qui peuvent se résumer à : des gens ajoutent des informations sans sourcer et celles-ci se répandent ensuite partout ((C’est une épidémie.))), force est de constater qu’une partie des problèmes provient de la base RADA.

Complétude des données

Comme nous l’avons déjà constaté, la base est remplie de doublons, chaque pseudonyme ou graphie de nom créant une nouvelle page au lieu de se centraliser avec une page par élève. Cela pose évidemment un problème si nous sommes intéressé⋅e⋅s par le nombre d’étudiant⋅e⋅s par année par exemple.

Du point de vue wikidatien, cela empêche également la solution simple de créer une entrée par élève, indépendamment de la présence d’un article Wikipédia. La base de données de Cambridge par exemple, attribue un identifiant fixe par élève, ce qui a permis l’importation complète de ces identifiants sur Wikidata, au besoin en créant les entrées manquantes (P1599: ID de la Cambridge Alumni Database) ((Mix n’ Match permet de marquer un identifiant comme nécessitant la création d’une entrée Wikidata.)). Si la RADA avait choisi la solution d’un identifiant/élève au lieu d’url de la forme diplôme/année/prénom/nom, il aurait été plus facile de l’importer entièrement.

Ce qui nous amène au point suivant : il n’est pas du tout certain que la base soit actuellement complète. Rien n’est indiqué en ce sens sur le site. Un petit tour sur la Wayback Machine d’Internet Archive nous montre que la base n’est en ligne que depuis 2015, auparavant seul⋅e⋅s les élèves en cours d’études avaient un profil sur le site. S’il semble donc très probable que les données les plus récentes soient complètes (à partir de 1999, où les profils sont détaillés et accompagnés de photographies), les profils des années antérieures sont parfois très sommaires. Surtout, certaines années semblent étrangement vides d’élèves, comme 1988.

Serait-il possible que dans la centaine de cas listés comme élèves de la RADA qui n’ont pu trouver de correspondance dans la base il y ait des oublis ? Un des cas qui me font douter est celui de Noel Streatfeild qui d’après son site internet aurait été acceptée comme élève en 1919. J’ai bien trouvé un⋅e « Noel Goodwin » diplômé⋅e en 1922 mais est-ce elle ?

Un cas encore plus explicite est celui de Dora Mavor Moore, qui d’après cet article biographique a été la première Canadienne acceptée à la RADA et aurait été diplômée en 1912. Le problème, c’est que côté RADA, un seul élève a été diplômé cette année-là et « Leonard Notcutt » n’est pas un pseudonyme connu de Dora Mavor Moore.

Fiabilité des données

Le problème avec probablement le plus d’impact, c’est que certain⋅e⋅s des élèves listé⋅e⋅s dans la base RADA en sont sorti⋅e⋅s avant d’être diplômé⋅e⋅s. Quelqu’un comme Harold Pinter a bien une fiche RADA disant qu’il fait partie de la promotion de 1949. En fait, Pinter est entré à la RADA en 1948 et a abandonné le cursus en 1949, avant d’être diplômé donc. La RADA liste-t-elle ses ancien⋅ne⋅s élèves indépendamment du fait qu’iels aient achevé leur cursus ? Dans Wikidata ces cas sont gérés en entrant un « no value » au lieu d’une valeur personnalisée dans le champ du qualificatif « diplôme » de la propriété « scolarité ».

Il est tout de même un peu problématique que nous ne puissions pas faire confiance à l’école elle-même pour savoir qui en a été diplômé⋅e…

J’ai un autre problème avec la fiche RADA de Sheila Terry qui me semble correspondre à Sheila Terry sur Wikipédia. Il est à peu près certain qu’elle n’a pas mis les pieds à Londres pendant ses études ; d’après WP, elle les aurait faites à la Dickson-Kenwin academy, une école « affiliée » à la RADA. Est-ce à dire que cette école délivrait alors le diplôme de la RADA ? (oui, avant la réforme des années 2000, la RADA délivrait ses propres diplômes). Là encore, je manque d’informations.

J’ai un certain Jack May de la promotion de 1943 dont l’article Wikipédia en anglais dit explicitement qu’il a été reçu à la RADA et n’y est jamais allé

Bref, ce n’est pas simple, même lorsque les personnes en question sont identifiées !

Requêtes et statistiques marrantes

Tout ceci étant dit, nous avons malgré tout un échantillon intéressant avec 835 entrées. Cela ne correspond pas à tous les élèves de la RADA, loin de là, mais c’est un nombre suffisant pour pouvoir commencer à s’amuser un peu avec les requêtes SPARQL !

Nombre d’élèves avec entrée WD par année

Commençons tout simplement par demander la liste complète des élèves de la RADA avec une date de fin d’études :

SELECT ?year (COUNT(?student) AS ?number) {
  ?student wdt:P31 wd:Q5 .
  ?student p:P69 ?statement .
  ?statement ps:P69 wd:Q523926 .
  ?statement pq:P582 ?endtime .
  BIND(YEAR(?endtime) as ?year) . 
} GROUP BY ?year ORDER BY ?year

lien vers la requête ce qui nous permet de faire ce joli graphique :

Nombre d'élèves de la RADA ayant une entrée Wikidata par année
Nombre d’élèves de la RADA ayant une entrée Wikidata par année

Âge moyen à la sortie d’école

Toujours sur l’échantillon wikidatien, maintenant que nous savons quand iels sont sorti⋅e⋅s de l’école, à quel âge l’ont-iels fait ? Cela suppose que leur date de naissance est renseignée sur Wikidata, ce qui réduit encore un peu notre échantillon.

SELECT ?endYear (AVG(?age) AS ?averageAge) WHERE {
	?person p:P69 ?radaStatement .
    ?radaStatement ps:P69 wd:Q523926 .
    ?radaStatement pq:P582 ?endDate .
    ?person wdt:P569 ?birthDate .
   	BIND(YEAR(?endDate) AS ?endYear)
  	BIND(?endYear - YEAR(?birthDate) AS ?age)
} GROUP BY ?endYear ORDER BY ?endYear

lien vers la requête

Ou même une requête plus avancée : l’âge moyen à la sortie de l’école, selon les années, le genre (masculin ou féminin, aucun autre genre déclaré dans notre échantillon), avec indication du nombre de personnes concernées par année :

SELECT ?endYear ?genderLabel (ROUND(AVG(?age)) AS ?averageAge) (COUNT(?person) AS ?number) WHERE {
	?person p:P69 ?radaStatement .
    ?person wdt:P21 ?gender .
    ?gender rdfs:label ?genderLabel filter (lang(?genderLabel) = "fr") .
    ?radaStatement ps:P69 wd:Q523926 .
    ?radaStatement pq:P582 ?endDate .
    ?person wdt:P569 ?birthDate .
   	BIND(YEAR(?endDate) AS ?endYear)
  	BIND(?endYear - YEAR(?birthDate) AS ?age)
} GROUP BY ?endYear ?genderLabel ORDER BY ?endYear

lien vers la requête. Il y aurait une pyramide des âges à faire si je n’étais pas si flemmarde.

Combien de nationalités ont été représentées à la RADA ?

	 	 
SELECT ?nationality ?number ?nationalityLabel {
 {SELECT ?nationality (COUNT(?student) AS ?number) {
 ?student p:P69 ?statement .
 ?statement ps:P69 wd:Q523926 .
 ?statement pq:P582 ?endtime .
 ?student wdt:P27 ?nationality .
 } GROUP BY ?nationality}
 SERVICE wikibase:label { bd:serviceParam wikibase:language "en" . }
} ORDER BY desc(?number)

lien vers la requête qui affiche donc la liste des nationalités avec à chaque fois le nombre d’élèves concerné⋅e⋅s, classé de la plus représentée (étonnamment ((Ou pas.)), les Britanniques) à la plus rare. Plus d’une trentaine de nationalités ont donc été représentées à la RADA !

Nombre d’étudiants de la RADA ayant joué dans un James Bond

SELECT DISTINCT ?actor ?actorLabel WHERE {
  ?item wdt:P179 wd:Q2484680 .
  ?item wdt:P161 ?actor .
  ?actor wdt:P69 wd:Q523926 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en" . }
} ORDER BY ?actorLabel

lien vers la requête.
Ce qui représente quand même plus d’une quarantaine de personnes, ce n’est pas rien !

Conclusion

  1. Je n’ai pas fini ;
  2. J’espère que l’archiviste de la RADA est sympathique ;
  3. Les gens, sérieusement, importez les alias sur Wikidata ;
  4. Et vos sources. C’est bien, les sources ;
  5. Et photographiez Ben Whishaw, on manque cruellement d’images libres ;
  6. On peut quand même faire des requêtes amusantes non ((Et des notes de bas de page, qui sont quand même la partie la plus intéressante de ce billet.)) ?

(image à la une : Fronton de la RADA, par Chemical Engineer, CC-BY-SA 3.0)

Enregistrer

Catégories
Wikidata

À la recherche des communes françaises sur Wikidata

J’ai eu besoin récemment d’obtenir la liste des communes françaises avec leur identifiant Wikidata. Cette liste change constamment : si la France compte toujours un peu plus de 35 000 communes, le nombre exact change plusieurs fois par an, les communes fusionnant ou étant séparées à un rythme difficile à suivre. Il y a même un article de Wikipédia dédié aux nombre de communes en France. Si on peut s’y fier, il y en a donc très exactement 35 884 au moment où j’écris ces lignes, et une autre fusion entrant en vigueur mardi 1er mars (entre Binic et Étables-sur-Mer), il y aura à ce moment une commune de moins.

L’article n’est cependant pas clair sur ce qui est supposé être inclus dans ce décompte : la métropole uniquement ? Les DOM sont-ils inclus ? Et les COM ? Avant de me pencher plus en détails là-dessus, allons-voir combien ce qu’en disent d’autres sources.

Une liste officielle des communes de la métropole et des DOM ((excluant donc les 48 communes de Polynésie française et les deux de Saint-Pierre-et-Miquelon)) est publiée chaque année par l’Insee dans le Code officiel géographique (COG) mais la dernière version publiée est celle de 2015. Le fichier, dont on voit un extrait ci-dessous, compte 36 658 entrées , ce qui est cohérent avec les données annoncées par l’article de Wikipédia pour 2015…

CDC    CHEFLIEU    REG    DEP    COM    AR    CT    TNCC    ARTMAJ    NCC    ARTMIN    NCCENR
0    0    82    01    001    2    08    5    (L')    ABERGEMENT-CLEMENCIAT    (L')    Abergement-Clémenciat
0    0    82    01    002    1    01    5    (L')    ABERGEMENT-DE-VAREY    (L')    Abergement-de-Varey
0    1    82    01    004    1    01    1        AMBERIEU-EN-BUGEY        Ambérieu-en-Bugey
0    0    82    01    005    2    22    1        AMBERIEUX-EN-DOMBES        Ambérieux-en-Dombes
0    0    82    01    006    1    04    1        AMBLEON        Ambléon
0    0    82    01    007    1    01    1        AMBRONAY        Ambronay
0    0    82    01    008    1    01    1        AMBUTRIX        Ambutrix
0    0    82    01    009    1    04    1        ANDERT-ET-CONDON        Andert-et-Condon

Par curiosité, je regarde aussi du côté d’OpenStreetMap qui, de son côté, fournit sur data.gouv.fr un export du découpage des communes françaises. D’après sa description, il est à jour au 1er février 2016, et contient le titre des articles Wikipédia. C’est un fichier shapefile dont il est très simple d’extraire la liste des codes Insee et le titre des articles Wikipédia correspondants grâce à la librairie python qui va bien et un tout petit bout de code. Surprises, il contient 35 888 communes, soit deux de trop comparé à Wikipédia ((deux et non quatre, car le fichier inclut les deux communes de Saint-Pierre-et-Miquelon qui ne sont pas dans le COG. Pourquoi Saint-Pierre-et-Miquelon et pas la Polynésie française, mystère.)), et pour 282 d’entre elles, il manque le lien vers l’article de Wikipédia.

Mais revenons à Wikidata, qui devrait avoir 35 934 communes, en comptant les TOM. Vérifions avec SPARQL :

PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>

SELECT (COUNT(DISTINCT ?commune) AS ?nbCommunes) {
  ?commune wdt:P31 wd:Q484170 .
}

http://tinyurl.com/gm4xdyt

Le résultat que j’obtiens est de 38 663 communes. C’est 2729 de trop… C’est dû aux anciennes communes, fusionnées ou supprimées depuis. Pour obtenir la liste à jour, il me faudrait donc faire un filtre sur la présence d’un qualificateur « Date de fin (P582) » sur la déclaration « wdt:P31 wd:Q484170 ».  Sauf qu’en faisant ça… J’obtiens 37 475 résultats : la date de fin n’est manifestement pas correctement indiquée de manière systématique. Il semble également y avoir quelques îles marquées comme commune alors qu’un élément séparé existe pour celle-ci.

Bon, plus qu’à se retrousser les manches et corriger tout ça…

Histoire de dégrossir le travail, je vais commencer par passer sur toutes les communes sans code Insee ni date de fin et corriger ce qui cloche :

PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX pq: <http://www.wikidata.org/prop/qualifier/>

SELECT ?commune ?communeLabel {
  ?commune p:P31 ?statement .
  ?statement ps:P31 wd:Q484170 . 
  FILTER NOT EXISTS { ?statement pq:P582 ?x } .  #Pas de date de fin
  FILTER NOT EXISTS { ?commune wdt:P374 ?insee } . #Ni de code Insee, histoire de dégager les communes actuelles
  
  SERVICE wikibase:label {
    bd:serviceParam wikibase:language "fr" .
  }
} ORDER BY ?communeLabel

http://tinyurl.com/hkoqlho

Pour chaque commune : je vérifie la date de fusion ou suppression indiquée dans Wikipédia, et je reporte l’info dans Wikidata. Si c’est devenu une commune associée, je l’indique également et j’en profite aussi pour supprimer la nature « ancienne commune française » qui est présente sur une poignée d’éléments et ne devrait tout simplement même pas exister… Ça donne un résultat comme ça et si vous voulez venir me filer un coup de main, vous êtes les bienvenus 🙂

(Image à la une : Le port de Binic, ou plutôt maintenant Binic-Étables-sur-Mer, CC-BY-SA-3.0 Semnoz)