Pour le projet Gallicagram, nous avons téléchargé massivement plusieurs corpus, en particulier :
En voici la liste complète, ainsi que quelques détails sur les corpus - en particulier la date où nous les avons téléchargés :
Titre | Période (conseillée) | Volume (en mots) | Code API | Longueur max | Résolution | Seuils | Date de téléchargement |
---|---|---|---|---|---|---|---|
Le Monde | 1944-2023 | 1,5 milliards | lemonde | 4gram | Journalière | Aucun | Janvier 2023 |
Presse de Gallica | 1789-1950 | 57 milliards | presse | 3gram | Mensuelle | 2gram>1,3gram>1 | Mars 2021 |
Livres de Gallica | 1600-1940 | 16 milliards | livres | 5gram | Annuelle | 2gram>1, etc | Mars 2021 |
Deutsches Zeitungsportal (DDB) | 1780-1950 | 39 milliards | ddb | 2gram | Mensuelle | 1gram > 1, 2gram>2 | Août 2023 |
American Stories | 1798-1963 | 20 milliards | american_stories | 3gram | Annuelle (mensuelle à venir ?) | 1gram>1,2gram>2,3gram>3 | Octobre 2023 |
Journal de Paris | 1777-1827 | 86 millions | paris | 2gram | Journalière | 2gram>1 | Août 2023 |
Moniteur Universel | 1789-1869 | 511 millions | moniteur | 2gram | Journalière | 2gram>1 | Août 2023 |
Journal des Débats | 1789-1944 | 1,2 milliards | journal_des_debats | 1gram | Journalière | Aucun | Août 2023 |
La Presse | 1836-1869 | 253 millions | la_presse | 2gram | Journalière | 2gram>1 | Août 2023 |
Le Constitutionnel | 1821-1913 (très lacunaire) | 64 millions | constitutionnel | 2gram | Journalière | 2gram>1 | |
Le Figaro | 1854-1952 | 870 millions | figaro | 2gram | Journalière | 2gram>1 | Août 2023 |
Le Temps | 1861-1942 | 1 milliard | temps | 2gram | Journalière | 2gram>1 | Août 2023 |
Le Petit Journal | 1863-1942 | 745 millions | petit_journal | 2gram | Journalière | 2gram>1 | Août 2023 |
Le Petit Parisien | 1876-1944 | 631 millions | petit_parisien | 2gram | Journalière | 2gram>1 | Août 2023 |
L’Humanité | 1904-1952 | 318 millions | huma | 2gram | Journalière | 2gram>1 | Août 2023 |
Opensubtitles (français) | 1935-2020 | 17 millions | subtitles | 3gram | Annuelle | Aucun | Juillet 2023 |
Opensubtitles (anglais) | 1930-2020 | 102 millions | subtitles_en | 3gram | Annuelle | Aucun | Juillet 2023 |
Rap (Genius) | 1989-février 2024 | 20 millions | rap | 5gram | Annuelle | Aucun | Mars 2024 |
Persée | 1789-2023 | 1 milliard | route à part (query_persee) | 2gram | Annuelle | Aucun | Décembre 2023 |
Pour l’application, nous avons constitué des bases de données dénombrant le nombre d’occurrences des mots et groupes de mots sur chaque corpus, sur chaque période. Ce sont ces mêmes bases que l’application utilise pour afficher ses graphes (s’il fallait compter à chaque fois les occurrences dans le corpus, cela prendait des semaines). Bref, nous avons fait des calculs interminables pour compter le nombre d’occurrences de chaque mot, et cette information pourrait être utile à d’autres. Ces bases de données étant trop vastes pour être téléchargeables (2 téras au total) et manipulables. À titre d’exemple, nous avons déposé la base des 1grams des archives du Monde sur Huggingface au format parquet, à cette adresse, et rendons les autres interrogeables à travers cette API, qui vous envoie les données au format csv.
Mettons d’emblée les pieds dans le plat. Cette API est simple d’usage, voyez plutôt :
tableau = read.csv("https://shiny.ens-paris-saclay.fr/guni/query?mot=patate")
En insérant cette ligne dans votre code R, vous obtiendrez un dataframe de la fréquence mensuelle du mot patate dans la presse de Gallica.
Pour encore plus d’ergonomie, vous pouvez utiliser les packages R, python et Ruby (voir ci-dessous), qui sont des “wrappers” de cette API. Nos bases sont stockées en SQLite, et structurées avec les colonnes suivantes : n (nombre d’occurrences), gram (mot ou syntagme recherché), année, mois et jour (selon le corpus). À titre d’exemple, nous avons déposé la base des 1grams des archives du Monde sur Huggingface au format parquet, à cette adresse. Le code de l’API (une banale application codée en python/flask) est disponible à cette adresse. Dans le dossier scripts_ngram, vous trouverez des scripts python ayant servi à construire les bases sqlite ici présentées.
Là où c’est nécessaire, les bases sont doublées d’une structure fulltext (sqlite fts5), qui permet des interrogations plus complexes. L’API ajoute aussi une colonne “total”, qui donne le nombre total de mots ou groupes de mots de cette taille dans le corpus, sur chaque période. On peut donc calculer la fréquence en divisant la colonne “n” par la colonne “total”. Ces fichiers de totaux sont situés à cette adresse, avec le code source de l’application. Elles ont pour nom de fichier “{code_corpus}{n}.csv” - les 1gram du Monde s’appellent donc lemonde1.csv.
Les bases ont été constituées légèrement différement selon le corpus :
Voici la procédure que nous avons suivie pour constituer ces bases de données :
nltk.RegexpTokenizer(r"[0-9a-zà-ÿ']+")
) (notons que nous avons considéré l’apostrophe comme une lettre).CREATE UNIQUE INDEX index_bla on gram (gram,annee,mois,jour);
(selon la résolution temporelle).select sum(n) as n,annee,mois,jour from gram group by annee,mois,jour;
).Les bases de données peuvent être interrogées de plusieurs façons. Si en voyant la structure des données décrites ci-dessus, un autre mode vous vient à l’esprit, n’hésitez pas à nous écrire (cette API est essentiellement constituée d’idées d’autres personnes, et son existence même est due à une demande d’Etienne Brunet, que je salue).
Syntaxe : https://shiny.ens-paris-saclay.fr/guni/query?mot=patate&corpus=presse&from=1789&to=1950
Une simple route pour obtenir le nombre d’occurrence de mot
entre l’année from
et l’année to
, dans le corpus
voulu (qui doit appartenir à “presse”, “livres” et “lemonde”). Seul l’argument mot
est nécessaire; par défaut on cherche dans le corpus “presse”, entre 1789 et nos jours.
Syntaxe : https://shiny.ens-paris-saclay.fr/guni/contain?corpus=lemonde&mot1=patate&mot2=une&from=2015&to=2022
Une sorte de mode co-occurrence proche : cette route vous compte le nombre de 3gram (4gram pour le corpus Le Monde) qui contiennent à la fois mot1
et mot2
. C’est en particulier utile pour étudier les stéréotypes (exemple).
Si ce qui vous intérese ce n’est pas les comptage mais de jeter un oeil aux bouts de textes qui contiennent ces deux mots (pour comprendre pourquoi deux mots sont associés dans la route associated
décrite ci-dessous par exemple), vous pouvez glisser count=False
. On vous retournera les 3 ou 4-gram (selon le corpus) comptés et datés.
Analogue à notre mode Joker sur l’application Gallicagram, inspiré de celui de Ngram Viewer. Vous renvoie ce qui suit (ou ce qui accompagne si after=False
) le plus souvent mot
, avec le nombre d’occurrences sur toute la période (tot
). Par exemple, “camarade” est souvent suivi par “Staline” et “khrouchtchev” dans Le Monde. L’option after
, activée par défaut, contraint à ne chercher que ce qui vient après le mot (“camarade *”) a. Si on la désactive, on obtient également les groupes de mots “* camarade”. Pour avoir ce qui précède le plus couramment (pas moyen de l’obtenir directement avec fts5), vous pouvez mettre un n_joker
élevé (ou n_joker=all
), after=False
et exclure dans votre code toutes les formes “camarade *”. Avec n_joker=all
, la route vous renvoie la totalité des jokers (attention aux gros dataframes, surtout sur les corpus gallica, où les erreurs d’OCR sont foison…).
Le paramètre length
contrôle la taille des ngrams que vous cherchez. Concrètement, avec length=2
on vous renverra “camarade de”, avec length=3
vous aurez par exemple accès à “camarade de chambre”. La taille maximale est 3 sur les corpus Gallica et 4 sur Le Monde (à noter que length=3 produit des calculs interminables sur le corpus presse, qui atteignent parfois le timeout pour les mots fréquents, mais rien ne coûte d’essayer !).
Cette route fonctionne également avec des groupes de mots, dans la mesure des limites des bases de données : cette route est limitée à 2 mots pour les corpus “presse” et “livres” (par exemple), et à 3 mots pour Le Monde. A noter que sur le corpus “presse”, ce mode est très lent, car la base des 3gram est monumentale. Rappelons également l’exclusion susmentionnée des lignes où n=1
dans les deux corpus Gallica, qui rend ce mode moins fiable pour les expressions rares.
Dans l’application, nous couplons cette fonctionnalité avec une liste de “mots vides”, les mots les plus fréquents dans le corpus Gallica. Nous excluons autant de mots vides que l’utilisateur le désire (par défaut 500), puisqu’ils sont souvent peu instructifs (“camarade de” et “camarade qui” sont les plus fréquents, et on s’en fiche pas mal). Cette fonctionalité n’est pas implémentée pour l’instant.
Syntaxe : https://shiny.ens-paris-saclay.fr/guni/associated?mot=changement%20climatique&corpus=lemonde&from=1945&to=2022&n_joker=200&length=4&stopwords=0
Crée sur une idée de Vincent Bagilet, cette route généralise la route Joker. Elle vous renvoie les mots le plus souvent associés à mot
, dans un voisinage de length
(paramètre limité à 3 sur les corpus Gallica). Vous pouvez entrer un nombre de stopwords à ignorer, entre 0 et 1000 (avec stopwords=500
, on ignorera les 500 mots les plus fréquents, la liste ayant été établie sur le corpus de livres). Cette route est probablement la plus utile, elle vous permet d’explorer l’environnement sémantique de mot, de distinguer selon ses acceptions, etc. Par exemple, Vincent Bagilet l’a utilisée pour quantifier combien on utilisait, au cours du temps, le mot “climatique” en termes d’action, de causes, de conséquences ou de problème.
Cette route peut être un peu lente, surtout si length
est élevé. Pour des mots extrêmement fréquents (comme “pas”) vous risquez d’atteindre le timeout (actuellement fixé à 5000 secondes). Dans ce cas, n’hésitez pas à relancer. SQL garde en cache les calculs déjà faits, alors avec quelques essais, ça finira par marcher.
Egalement due à Vincent, cette route explore aussi l’environnement sémantique d’un mot, mais au niveau de l’article entier (et non du groupe de mot). Deux limites : elle ne fonctionne que sur Le Monde (seul corpus segmenté en articles) et seulement sur un mot : vous pourrez chercher “climatique”, mais pas “changement climatique”. Cette route est lente sur les mots très fréquents.
Cette route vous donne le nombre d’articles où figurent deux mots, par exemple où figurent à la fois le mot “crise” et “climatique”. Vous pouvez aussi fournir à cette route une collection de mot, auquel cas on sépare les mots par des +, comme dans l’exemple ci-dessus (crise+crises
. La route vous renvoie aussi le nombre total d’articles à chaque période (nb_total_article
), afin de pouvoir calculer les fréquences de cooccurrences au cours du temps.
Syntaxe : https://shiny.ens-paris-saclay.fr/guni/query_article?mot=d%C3%A9linquance&from=1960&to=2000
Tout simplement un comptage du nombre d’articles où figure le mot, là où la route query compte le nombre d’occurrences. On vous renvoie aussi bien sûr le nombre total d’articles sur chaque période (nb_total_article
) pour calculer les fréquences. Cette route peut (entre autre) servir de test de robustesse, ou de comparaison à d’autres corpus où la mesure est “par article” et non “par occurrence”. Je ne l’utilise personnellement pas, mais plusieurs personnes nous l’ont demandée, alors la voici.
Une route à part pour compter les occurrences dans le corpus Persée. Sa particularité est d’avoir été indexé non seulement par année, mais aussi par revue. Vous pouvez donc chercher dans une seule revue, ou dans un bouquet de revue que vous vous constituez. Par exemple, pour étudier la diffusion d’un concept sociologique, il serait plus pertinent de chercher dans une dizaine de revues canoniques en sociologie, plutôt que dans le corpus tout entier, qui contient également des géosciences. Les revues disponibles sont renseignées ici. La colonne “Codes” du tableau vous donne l’identifieur des revues, que vous fournisser au paramètre nb_total_article
dans l’API. Vous pouvez chercher dans plusieurs revues en séparant les revues par des + (dans l’exemple ci-dessus, on cherche dans les Actes de la Recherche en Sciences sociales, les Annales, la RFS, Droit et Société et Déviance et société. Avec by_revue=False
(la valeur par défaut), les occurrences sont agrégées par année. Avec by_revue=True
, on conserve leur ventilation dans les différentes revues. Avec by_revue=True
et un champ revue
non renseigné, vous pouvez chercher d’où proviennent les occurrences dans la totalité du corpus.
Une limite : on ne peut pour l’instant pas chercher de syntagme de plus de deux mots.
Pour plus d’informations sur le corpus Persée, les revues qu’il contient et les périodes de disponibilité, ça se passe ici.
Le seul package que nous avons écrit, car python c’est quand même vachement mieux que R (oui, Gallicagram est codé en R, j’en souffre suffisamment, pas besoin de me le rappeler… Fichue dépendance au sentier. Parenthèse fermée.)
Le package contient des fonctions correspondant à chaque route, à l’exception de query_persee
. Il est disponible ici : https://github.com/regicid/pyllicagram ainsi que sur pypy.
Pour l’installer : pip install pyllicagram
si vous êtes sur mac/linux (ou pip3 install pyllicagram
) . Si vous êtes sur Windows, j’en ai pas la moindre idée et c’est pas ma faute s’il y a encore des gens sur Windows.
Note : le package n’est vraiment pas à jour et il faudrait que je travaille dessus.
Vincent Bagilet a développé ce magnifique package en R https://vincentbagilet.github.io/rallicagram/. Comme Vincent est très très fort, il est aujourd’hui plus développé que pyllicagram, et mieux documenté. On va essayer de rattraper le retard.
Nicolas Roux a eu la bonté de développer une gem Ruby. Pour connaître son stade de devéloppement, rendez-vous sur https://github.com/nicolrx/gallicagram
Si des bonnes volontés veulent développer des packages dans d’autres langages, qu’ils n’hésitent pas à m’envoyer un mail et je les ajouterai à la liste.