Le calcul de la couverture en terme de mots de deux textes n'a rien de bien compliqué dans la mesure où :

  • il nous est possible de découper le texte en mots ;
  • nous savons compter le nombre de mots qu'ils ont en commun.

Pour le découpage en mots, nous allons utiliser la bibliothèque NLTK (j'utilise la version bêta de la 2.0) qui propose une méthode word_tokenize :

import nltk
nltk.word_tokenize(u"A sentence to be tokenized")
 
[u'A', u'sentence', u'to', u'be', u'tokenized']

Le tokeniseur est loin d'être parfait, notamment pour les textes qui ne sont pas de l'anglais, mais il fonctionne suffisamment bien pour l'utilisation que nous en avons. Ce serait beaucoup plus problématique pour une tâche de recherche d'information par exemple.

Nous passerons donc le contenu des fichiers à comparer à cette fonction qui nous retourne la liste des mots correspondant. Il nous faut alors calculer l'intersection des deux listes de mots.

Les objets set offrent une méthode intersection qui ferait l'affaire. Cependant la conversion en un ensemble va faire disparaître les doublons, or nous aimerions avoir un recouvrement aussi précis que possible. Nous définissons donc une fonction qui va calculer l'intersection de deux listes. Elle peut certainement être largement améliorée (ne pas hésiter à proposer une correction), mais suffira pour l'exemple :

def intersect_list(lst1, lst2):
	"""
	Calcule l'intersection entre deux listes
	"""
	# Intersection
	inter = []
	# Calcul des éléments en commun
	common = set(lst1).intersection(lst2)
	# Construction de la liste commune
	for e in common:
		nbe = min(lst1.count(e), lst2.count(e))
		for i in range(nbe):
			inter.append(e)
	return inter

Nous avons désormais en main tous les éléments nécessaire pour écrire un petit script qui calculera le taux de recouvrement en mots entre deux fichiers textes.

Voici le script complet pour ceux que ça intéresse :

#! /usr/bin/python
# -*- coding: utf-8 -*-
#
# Script permettant de calculer le taux de recouvrement en mots entre les
# deux textes passés en paramètre.
 
import nltk
import os.path
import sys
import codecs
 
def loadTxt(fic):
	"""
	Charge le contenu textuel du fichier en paramètre
	"""
	fh  = codecs.open(fic, "r", "utf-8", errors='ignore')
	txt = fh.read()
	fh.close()
	return txt
 
def intersect_list(lst1, lst2):
	"""
	Calcule l'intersection entre deux listes
	"""
	# Intersection
	inter = []
	# Calcul des éléments en commun
	common = set(lst1).intersection(lst2)
	# Construction de la liste commune
	for e in common:
		nbe = min(lst1.count(e), lst2.count(e))
		for i in range(nbe):
			inter.append(e)
	return inter
 
# Vérifie qu'il y a bien deux fichiers passés en paramètre du script
if len(sys.argv) == 3:
	# Charge les textes des fichiers
	txt1 = loadTxt(sys.argv[1])
	txt2 = loadTxt(sys.argv[2])
	# Tokenisation en mots
	txt1toks = nltk.word_tokenize(txt1)
	txt2toks = nltk.word_tokenize(txt2)
	# Calcul de la couverture
	incommon = intersect_list(txt1toks, txt2toks)
	# Affichage
	print "Couverture de %s par rapport à %s" % (sys.argv[1],sys.argv[2])
	print "\t%f" % (float(len(incommon))/len(txt1toks))
	print "Couverture de %s par rapport à %s" % (sys.argv[2],sys.argv[1])
	print "\t%f" % (float(len(incommon))/len(txt2toks))
else:
	print "Utilisation :"
	print "\t%s <fichier 1> <fichier 2>" % sys.argv[0]

Bien entendu, le taux de recouvrement en mots n'est pas très performant pour évaluer le degré de dérivation entre deux textes. Une manière de l'améliorer serait de calculer le taux de recouvrement de n-grammes plutôt. J'attends vos propositions :)