Le domaine de l’Information retrieval, profondément lié dans son histoire à l’informatique, connaît sans cesse des développements très importants, au cœur de l’activité du Web, de la documentation, des moteurs de recherche. On peut comprendre la tentation d’exploiter certains des acquis de cette science pour l’appliquer aux domaines qui nous intéressent, ou, pour reprendre une métaphore dans la tonalité générale de notre carnet, de boire à cette coupe qui ne se tarit jamais. Toutefois, une telle démarche ne peut aller sans une réflexion préalable.
Il ne faut pas en effet oublier que ces outils ont été créés non pas pour faciliter le travail des philologues, pour opérer des traitements scientifiques sur des corpus de textes, mais bien dans une optique de recherche d’information et de pertinence qui diffère sensiblement de la nôtre. Ce billet se veut le premier d’une série cherchant, sans exhaustivité, à passer en revue certains des outils les plus fréquents dans le domaine de l’Information retrieval et de voir en quoi ils peuvent nous être utiles, s’ils sont applicables ou adaptables à nos sciences. À cette fin, nous commencerons par un des éléments les plus « classiques », l’Approximate string matching, dont nous connaissons tous empiriquement le principe, ne serait-ce que par notre utilisation des moteurs de recherche…
1. Algorithmes et calculs de distance
La Distance de Levenshtein
La mesure de distance décrite en 1965 par le mathématicien soviétique Vladimir Levenshtein1 consiste en la somme des suppressions, remplacements ou insertions qu’il faudrait effectuer pour passer d’une chaîne de caractères à une autre. De cette façon, pour passer de
Philologe à Philologie
la distance est de 1 (une insertion) ou env. 11%. Et entre :
Philologie et Philosophie
la distance est de 3 (deux remplacements et une insertion) ou 30%. La distance de Levenshtein a été implémentée par les informaticiens Robert Wagner et Michael Fischer2 (on parle alors d’algorithme de Wagner-Fischer).
La distance de Damerau–Levenshtein
La distance dite de Damerau–Levenshtein, du nom du chercheur d’IBM Frederick J. Damerau, quant à elle, se distingue de la distance de Levenshtein en ce qu’elle inclue, outre les suppressions, remplacements ou insertions, un quatrième type d’opération, à savoir l’interversion de caractères adjacents. Ainsi, la distance entre
Philoloige et Philologie
est de 2 selon la mesure de Levenshtein, et seulement de 1 selon la mesure de Damerau-Levenshtein.
Autres mesures de distance
Si ces deux mesures de distance entre chaînes de caractères sont celles que l’on rencontre le plus fréquemment, il en existe d’autres. On citera ainsi pour mémoire la Distance de Hamming, qui ne fonctionne qu’avec des chaînes du même nombre de caractères et consiste en la somme de caractères différents à la même position. D’après cette mesure, la distance entre
Histoire et Histeire
est de 1, tandis qu’entre
Histoire et Hstoires
elle est de 7. Il faut dire que cette mesure de distance, qui correspond assez peu au fautes de frappe habituelles, est peu utilisée en tant que telle dans le domaine de la recherche d’information.
2. Mise en œuvre
Des modules Perl existant permettent de mettre en œuvre ces calculs. Nous parlerons ici brièvement des deux principaux, Text::WagnerFischer et String::Approx (je déconseille d’utiliser Text::Levenshtein qui a apparemment des problèmes avec utf8 et, chez moi en tout cas, donne des résultats faux…).
Text::WagnerFischer sert à la comparaison entre deux chaînes de caractères et permet d’obtenir le résultat de la mesure de distance, ainsi :
#!/usr/bin/perl
use Text::WagnerFischer qw(distance);
print distance("bonjour","bonsoir") ;
donne comme résultat 2 (deux substitutions en l’occurrence). Mais ce module permet également d’aller un peu plus loin en configurant séparément (mais dans cet ordre) le coût d’une correspondance, d’une suppression/insertion, et d’une substitution. Ainsi, pour reprendre l’exemple précédent :
print distance([0,1,1],"bonjour","bonsoir") ;
print distance([-1,2,3],"bonjour","bonsoir");
Si le résultat de la première commande donnera toujours 2 (deux substitutions dont le coût est 1), la seconde donnera cinq correspondances et deux substitutions, soit -1*5 + 3 *2, c’est-à-dire 1 (ce n’est qu’un exemple).
Le module String::Approx, quant à lui, permet, de façon relativement simple, non plus de simplement comparer des chaînes de caractères (i.e. établir la distance qui les sépare), mais de relever directement les chaînes qui correspondent à une autre pour une distance préétablie (par défaut 10%). Ainsi, dans le script suivant :
use String::Approx 'amatch';
@mots = qw("bonjous", "bonjours", "bonsoir", "adieu");
@resultat1 = amatch("bonjour", @mots);
@resultat2 = amatch("bonjour",["25%"], @mots);
la liste @resultat1 comprendra les mots “bonjous”, “bonjours” et la liste @resultat2 les mots “bonjous”, “bonjours”, “bonsoir” (la distance spécifiée étant de 25%).
3. Exemple d’application
Pour prendre un exemple un peu plus intéressant, j’ai testé ce module sur un corpus de textes occitans médiévaux. J’y ai recherché le terme cansos avec la distance par défaut de 10%. Dans ma liste de résultats se trouvent les termes suivants :
cansonetas, 1
cansos, 5
cansson, 5
canssons, 5
canssos, 7
chansos, 2
Ce résultat est intéressant, car ne s’y trouvent en effet que des graphies différentes de cansos, (excepté cansonetas, ce qui nous apprend par la même occasion que amatch est programmé pour s’arrêter dès qu’il trouve une correspondance, en l’occurrence canson[etas], ce qui peut-être particulièrement gênant si l’on veut traiter des monosyllabes). Toutefois, toutes les formes de cansos ne figurent pas dans cette liste : il y manque notamment chansson, chanssons et chanssos. On peut tenter d’augmenter la distance, en la fixant par exemple à 20%, mais dans ce cas, on obtient également tout une série de termes qui on peu de choses à voir avec nos chansons, en vrac canorgues, Cartosa, enansset, fermanssa, percassava3…
Pour conclure, on pourra noter que, si ces modules peuvent en effet donner des résultats intéressants, il manque, pour correspondre tout à fait à nos besoins, la possibilité de configurer indépendamment des coûts permettant de différencier certaines substitutions bénignes (comme la simple variation graphique entre i et y ou l’alternance c/ch par exemple) de celles qui ne le sont pas. Pour ce faire, a priori, il faudra plutôt recourir à une grammaire d’expressions régulières.
- Vladimir I. Levenshtein, « Binary codes capable of correcting deletions, insertions, and reversals », dans Soviet Physics Doklady, 10 (1966), p. 707-710. [↩]
- Robert A.Wagner et Michael J.Fischer, « The string- to-string correction problem », dans Journal of the ACM, 21(1974), p. 168–173. [↩]
- Les précédentes versions de String::Approx contenaient une commande aregex() qui aurait permis de contourner en partie ces difficultés par l’emploi d’expressions régulières, mais celle-ci n’existe hélas plus dans la dernière version. [↩]