Workshop @fabelier, 15 février 2012
>>> from sulci.textmining import SemanticalTagger >>> text = u"""«La Russie et la Chine finiront par regretter leur décision qui ... les a vues s’aligner sur un dictateur en fin de vie et qui les a mises en ... porte-à-faux avec le peuple syrien.»""" >>> s = SemanticalTagger(text) >>> s.descriptors [(<Descriptor: Russie>, 100.0), (<Descriptor: Chine>, 100.0), (<Descriptor: diplomatie>, 14.798308089447328), (<Descriptor: Dmitri Medvedev>, 10.337552742616033)]
En d'autres termes, en entrée, on fournit un texte, en sortie on reçoit des descripteurs, i.e. des mots-clés ou expressions censés décrire le sens du texte.
Pourquoi ce projet
version propriétaire et fermée (Windows) achetée en 2007 et jamais jugée utilisable
outil demandé depuis lors par le service qui gère nos archives
L'intérêt d'un tel outil pour eux est d'avoir automatiquement les descripteurs les plus évidents, pour se concentrer sur les plus délicats
le projet est né un peu par hasard, comme exercice pédagogique
l'objectif est que l'outil soit utilisé aussi par les journalistes cette année
Comment ça se prononce
soule-tchi
Pourquoi ça s'appelle comme ça
Ça vient de la région du Sulcis, au sud de la Sardaigne (Italie). Mon grand-père y était mineur. Et il y a laissé la peau.
C'est une bête fonction python (sulci.textutils.normalize_text), qui:
>>> from sulci.textutils import normalize_text >>> text = """<p>«C’est le petit monde politico-médiatique qui m’a prise en ... grippe, pas l’opinion publique.»</p> <p><strong>Eva Joly </strong> ... candidate Europe Ecologie-les Verts à l’Elysée dans l’hebdomadaire ... <em>Politis </em> paru hier</p>""" >>> print normalize_text(text) «C'est le petit monde politico-médiatique qui m'a prise en grippe, pas l'opinion publique.» Eva Joly candidate Europe Ecologie - les Verts à l'Elysée dans l'hebdomadaire Politis paru hier
Pour aller voir le code:
https://github.com/yohanboniface/sulci/blob/master/sulci/textutils.py#L30
>>> text = u"Les insultes sont la seule raison des pauvres d'esprit" >>> st = StemmedText(text) >>> sample = st.samples[0] # Première phrase >>> token = sample[0] >>> token.original u'Les' >>> token.lemme u'le'
Note
<https://github.com/yohanboniface/sulci/blob/master/sulci/textutils.py#L50> <https://github.com/yohanboniface/sulci/blob/master/sulci/base.py#L105> <https://github.com/yohanboniface/sulci/blob/master/sulci/base.py#L217>
On détermine le "rôle" d'un Token dans la phrase: nom commun, adjectif, ponctuation, etc.
Pourquoi ?
>>> for t in sample: ... print t.original, t.tag Les DTN:pl insultes SBC:pl sont ECJ:pl la DTN:sg seule ADJ:sg raison SBC:sg des DTC:pl pauvres SBC:pl d' PREP esprit SBC:sg
On détermine la version "neutre" d'un mot, pour essayer de gommer les aspérités de son utilisation dans le contexte:
Par exemple, la phrase:
Les insultes sont la seule raison des pauvres d'esprit
devient:
Le insulte être le seul raison de un pauvre de esprit
>>> from sulci.textmining import StemmedText >>> text = u"Les insultes sont la seule raison des pauvres d'esprit" >>> st = StemmedText(text) >>> print st.samples[0] # la première phrase le insulte être le seul raison des pauvre de esprit
Et la stemmatisation ?
Pros:
Cons:
Pour tester quand même (package pystemmer à installer):
>>> from Stemmer import Stemmer >>> stemmer = Stemmer("french") >>> stemmer.stemWord("chevaux") # résultat attendu 'cheval' >>> stemmer.stemWord("genoux") # résultat considéré comme une erreur 'genoux'
Extraire les éléments du discours qui représentent le sens du texte.
Une entité clé, c'est quoi ?
Pointwise mutual information
Compare la fréquence d'apparition d'une expression avec celle des éléments de cette expression
ngram_possible = len(self.text) - len(self) + 1 members_probability = product([1.0 * s.count/len(self.text) for s in self]) s_m_i = math.log(1.0 * self.count / ngram_possible / members_probability)
Pondération des entités
statistical_mutual_information * nrelative_frequency * POS score
En d'autres termes:
>>> from sulci.textmining import SemanticalTagger >>> text = u"""A l’occasion d’un attroupement lors de sa visite à Fessenheim, ... hier, Nicolas Sarkozy nous convie à faire quelques pas avec lui devant les ... caméras. Il tient manifestement à s’adresser directement aux lecteurs de ... Libération. Le président-candidat : «[François Hollande] se coupe des ... ouvriers en faisant cela [en fermant Fessenheim]. C’est une erreur. François ... Mitterrand ne l’aurait jamais fait. Les gens ont bien compris que cette ... décision était purement électoraliste. Ils ne sont pas bêtes.» ... Le journaliste de Libération : «Mais cela va coûter beaucoup d’argent de ... remettre à niveau la centrale.» ... Le président-candidat : «Le rapport de la Cour des comptes a été très clair. ... Ça coûterait encore plus cher d’investir dans le photovoltaïque.» On entre ... dans un nouveau bâtiment. Encore le président-candidat : «Sans moi, vous ... allez vous embêter. Qu’est-ce que Libération va devenir ? Combien de pages ... vous faites sur moi par jour ?»""" >>> s = SemanticalTagger(text) >>> s.deduplicate_keyentities() >>> for ke in s.keyentities: ... print ke François Hollande Nicolas Sarkozy François Mitterrand aller président-candidat Libération cela Fessenheim Qu'est Cour
>>> for d in s.descriptors[:10]: ... print d (<Descriptor: Nicolas Sarkozy>, 111.5773664718986) (<Descriptor: élection présidentielle>, 99.607961983161587) (<Descriptor: 2012>, 70.391150257770533) (<Descriptor: François Mitterrand>, 65.768314429804633) (<Descriptor: chef de l'Etat>, 64.654728257089261) (<Descriptor: Libération (journal)>, 58.484979899632719) (<Descriptor: primaire électorale>, 43.289428857194572) (<Descriptor: Parti socialiste>, 42.946056049664115) (<Descriptor: candidature>, 39.57865973263668) (<Descriptor: déclaration>, 36.031019330252548)
chaque apprentissage s'appuie sur un corpus
qu'est-ce qu'un corpus ?
Un ensemble de textes sur lesquels sont déjà posés les descripteurs qu'on souhaite faire apprendre
A quoi ressemble le corpus
La/DTN:sg liberté/SBC:sg de/PREP la/DTN:sg presse/SBC:sg n'/ADV aura/ACJ:sg donc/ADV vécu/PAR:sg que/SUB vingt/CAR et/COO un/CAR ans/SBC:pl en/PREP Hongrie/SBP:sg ./.
le corpus est dupliqué dans une version sans les tags
un premier tag issu de règles basiques est appliqué à chaque mot du corpus
les deux corpus sont alors comparés
dès qu'une erreur est trouvée, l'algorithme infère des règles pouvant expliquer cette erreur en utilisant les templates fournis
chacune de ces règles est testée sur tout le corpus de travail; est retenue celle qui a le meilleur bilan erreurs corrigées / erreurs créées
on passe à l'erreur suivante, et ainsi de suite tant qu'il reste des erreurs
Toute cette séquence est répétée deux fois:
- une fois pour les règles lexicales (s'appuyant sur la forme des mots)
- une fois pour les règles contextuelles (s'appuyant sur les mots et tags voisins)
Exemples de règles
Règles lexicales:
> SBC:sg des fgoodright SBC:pl
> SBC:sg ait fhassuf 3 VCJ:sg
> SBC:sg les fgoodright SBC:pl
> SBC:sg ces fhassuf 3 SBC:pl
> SBC:sg aient fhassuf 5 VCJ:pl
> SBC:sg rer fhassuf 3 VNCFF
Règles contextuelles:
> DTN:sg PRV:sg WDNEXTTAG leur VNCFF
> SBC:sg PAR:sg PREVBIGRAM a été
> DTN:pl PRO:pl WDAND2TAGBFR PRV:pl tous
A quoi ressemble le corpus
> La/DTN:sg/le liberté/SBC:sg de/PREP la/DTN:sg/le presse/SBC:sg n'/ADV/ne > aura/ACJ:sg/avoir donc/ADV vécu/PAR:sg/vivre que/SUB vingt/CAR et/COO un/CAR > ans/SBC:pl/an en/PREP Hongrie/SBP:sg ./.
Exemples de règles
> COO MAKELOWER 0.678643
> ECJ:sg FORCELEMME être 0.660030
> PAR:sg CHANGESUFFIX "enu" "enir" 0.471148
> VNCNT CHANGESUFFIX "ssant" "sser" 0.270237
> ADJ:pl CHANGESUFFIX "aines" "ain" 0.422129
> ADJ:pl CHANGESUFFIX "ales" "al" 0.465632
> ADJ:sg CHANGESUFFIX "uelle" "uel" 0.422129
Dans l'apprentissage Libération actuel:
>>> trigger = Trigger.objects.get(original="Nicolas Sarkozy") >>> for relation in trigger: ... print relation, relation.pondered_weight Nicolas Sarkozy =[952.000000]=> Nicolas Sarkozy 1.0 Nicolas Sarkozy =[530.000000]=> chef de l'Etat 0.556722689076 Nicolas Sarkozy =[346.000000]=> UMP 0.207169853114 Nicolas Sarkozy =[306.000000]=> élection présidentielle 0.292729591837 Nicolas Sarkozy =[269.000000]=> gouvernement 0.128829582681 Nicolas Sarkozy =[263.000000]=> réforme 0.205825814745 Nicolas Sarkozy =[260.000000]=> déclaration 0.244856563315 Nicolas Sarkozy =[249.000000]=> 2012 0.23511588751 Nicolas Sarkozy =[234.000000]=> polémique 0.156721544204 Nicolas Sarkozy =[226.000000]=> France 0.060967341482 Nicolas Sarkozy =[212.000000]=> Parti socialiste 0.0744638549426 >>> descriptor = Descriptor.objects.get(name="Parti socialiste") >>> for relation in descriptor.triggertodescriptor_set.all()[:10]: ... print relation, relation.pondered_weight PS =[634.000000]=> Parti socialiste 1.0 Martine Aubry =[374.000000]=> Parti socialiste 0.589905362776 France =[255.000000]=> Parti socialiste 0.116548967594 UMP =[219.000000]=> Parti socialiste 0.124626466201 Nicolas Sarkozy =[212.000000]=> Parti socialiste 0.0744638549426 Parti =[212.000000]=> Parti socialiste 0.322225408661 Ségolène Royal =[211.000000]=> Parti socialiste 0.332807570978 Français =[193.000000]=> Parti socialiste 0.169804525811 François Hollande =[177.000000]=> Parti socialiste 0.279179810726 Dominique Strauss-Kahn =[172.000000]=> Parti socialiste 0.192820084991
pondered_weight
> weight de la relation courante
> / weight de la relation max du déclencheur
> / weight de la relation max du descripteur
Libé, bien sûr, laboratoire permanent
Jérôme Petazzoni, optimisateur garanti sans gaz à effet de serre
<http://snowball.tartarus.org/> - algo Porter dans le projet snowball
<http://www.fabienpoulard.info/post/2008/02/21/Lalgorithme-de-Porter> - algo Porter par Fabien Poulard
<http://en.wikipedia.org/wiki/Pointwise_mutual_information> - pointwise mutual information
<http://archimede.bibl.ulaval.ca/archimede/fichiers/22225/22225.html> - adaptation du catégoriseur de Brill au français et modification de l'approche
Table of Contents | t |
---|---|
Exposé | ESC |
Full screen slides | e |
Presenter View | p |
Source Files | s |
Slide Numbers | n |
Toggle screen blanking | b |
Show/hide slide context | c |
Notes | 2 |
Help | h |