INTRODUCTION

    OBJECTIF: Extraction des patrons morphosyntaxiques dans les étiquetages produits avec Talismane/Treetagger

  • Données
    • Entrée :

        les sorties au format XML de l'étiquetage (via Treetagger) issues de la Boîte à Outils Série 2
        les sorties "brutes" de l'étiquetage (via Talismane) issues de la Boîte à Outils Série 2

      Sortie :
        des listes des patrons morphosyntaxiques triés par ordre de fréquence d'occurrence (1 fichier txt par motif et par rubrique)

  • Méthodes et Outils
    • Perl : utiliser un script Perl pour l'extraction des patrons.
      Python : adapter le script pour l'extraction des patrons.
      Xquery : fouiller les données des fichiers XML par des requêtes XQuery, en passant par le logiciel BaseX.
      Xslt : en choisissant la méthode de sortie texte et en utilisant Cygwin ou Firefox, on obtient des pages ou des fichiers de résultats.

  • Scripts et resultats
  • script sur cygwin

      On a utilisé cygwin pour de divers tâches, comme l'extractions de patron, la classification de sorties, et le comptage des patrons, etc.

    (extraire les patrons avec perl):
    perl5.28.0 extract-terminologie-ter.pl 3208-2018-talismane.txt termino.txt
    (classer et compter les items dans un fichier):
    less all_patrons.txt | sort | uniq -c | sort -gr >item_count_patron.txt
    (extraire les items avec xslt):
    xsltproc extractionPatrons.xsl 3208_2018.xml > patronN-PREP-N.txt
    (extraire,classer et compter les items avec xslt):
    xsltproc extractionPatrons.xsl 3208_2018.xml | sort | uniq -c | sort -gr >item_count_patron.txt

    Perl

      Quand on rencontre une ligne qui correspond à la fin d'une phrase, on ouvre le fichier contenant le patron. Chaque ligne correspond à un patron à retrouver. On transforme le patron en expression régulière et on stocke le tout dans une variable $listePatron. Ensuite, on recherche ce motif dans notre phrase recomposée : s'il y a une correspondance, on la récupère grâce à la variable par défaut, puis on enlève l'étiquette de POS pour ne garder que la forme. Le script renvoie cette correspondance nettoyée. Voilà le script fourni par M. Serge FLEURY et J.-M.D.:

    
    #!/usr/bin/perl
    <) {
    	chomp($patron);
        push(@{$listePatron},[split(/ +/,$patron)])
    }
    close($fileTer);
    
    my %dicoPatron=();
    my $nbTerme=0;
    my @WORDS;
    my @POS;	
    
    open my $fileT,"<:encoding(UTF-8)",$ARGV[0];
    while (my $ligne=<$fileT>) {
    	if (($ligne!~/^1\t££/) and ($ligne!~/^\#\#/) and ($ligne!~/^$/)){
    		my @TMPLIGNE=split(/\t/,$ligne);
    		push(@WORDS,$TMPLIGNE[1]);
    		push(@POS,$TMPLIGNE[3]);
    	}
    }
    close($fileT);
    
    my $lg=0;
    while (my $pos=$POS[$lg]) {
    	foreach my $patron (@{$listePatron}) {
    		if ($pos eq $patron->[0] ) {
    			my $indice=1;
    			my $longueur=1;
    			my $stop=1;
    			while (($indice <= scalar @$patron) and ($stop == 1)) {
    				if ($POS[$indice+$lg] eq $patron->[$indice]) {
    					$longueur++;
    					$indice++;
    				}
    				else {
    					$stop=0;
    				}
    			}
    			if ($longueur == scalar @$patron) {
    				$dicoPatron{join(" ",@{$patron})}->{join(" ",@WORDS[$indice+$lg-scalar @$patron..$indice+$lg-1])}++;
    				$nbTerme++;
    			}
    		}
    	}
    	$lg++;
    }
    open my $fileResu,">:encoding(UTF-8)","perlIsTheBigOneBis.txt";
    print $fileResu "$nbTerme éléments trouvés\n";
    foreach my $patron (keys %dicoPatron) {
    	print $fileResu "\nType de pattern: ".$patron." \n\n";
    	foreach my $terme (sort {$dicoPatron{$patron}->{$b} <=> $dicoPatron{$patron}->{$a} } keys %{$dicoPatron{$patron}}) {
    		print $fileResu $dicoPatron{$patron}->{$terme}."\t".$terme."\n";
    	}
    }
    print $fileResu "\nScript execution time: " . tv_interval($timepg) . " seconds.";
    close($fileResu);
    exit;
        							 

      On a comparé les résultats de trois rubriques en utilisant Perl et Python pour extraire les patrons. Pour la rubrique 3208 et 3214, ils ont rendu le même résultat, alors que pour la rubrique 3246, Perl a trouvé deux éléments de plus que Python. On n'a pas encore trouvé l'explication pour le problème.


    Python

      Dans cette phase, nous utilisons le script fourni par Danrun et Pierre, et voici quelques étapes importantes dans ce processus.

      sentence_list.pop()
      patterns_list = list(map(lambda x: findall('\w+', x)

    • sauter des lignes qui sont inutiles :
    • words = list(filter(lambda x: x and x.startswith("#") == False, lines))
    • utiliser \t(space) pour séparer chaque partie d'étiqutage :
    • champs = word.split('\t')
    • chercher les patrons dans la liste de tags du texte :
    • for i, tag in enumerate(tags):
      if tag in patterns_dico.keys():
    • comparer la liste de patron la liste de catégorie des mots dans le texte :
    • if tags[i:i+pat_leng] == ele:
    • le patron est la clé de dicationnaire et il correpond à plusieurs valeurs, qui sont la forme de chaque mot :
    • patrons_dico[key].append(n_gram)
    • parcourir toute la dictionnaire :
    • for pattern, patrons in patrons_dico.items():
    • compter le nombre des chaque item qui correspond à chaque patron :
    • tmplist = sorted(tmp.items(), key = lambda x:x[1], reverse = True)

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    from time import monotonic
    from re import findall
    
    
    filepath_sequence = input('Saisissez un fichier talismane:\n> ')
    patterns = input('Saisissez les patrons (séparés par un /):\n> ')
    
    start = monotonic()
    
    with open(filepath_sequence, 'r', encoding = 'utf-8', newline = '\n') as fichier:
    	contenu = fichier.read()
    	
    sentence_list = contenu.split('\n\n')
    sentence_list.pop()
    
    patterns_list_input = patterns.split('/')
    patterns_list = list(map(lambda x: findall('\w+', x), patterns_list_input))
    
    patterns_dico = {}
    patrons_dico = {}
    
    for pattern in patterns_list:
    	patrons_dico[' '.join(pattern)] = []
    	try:
    		patterns_dico[pattern[0]]
    	except:
    		patterns_dico[pattern[0]] = []
    	patterns_dico[pattern[0]].append(pattern)
    
    
    for sentence in sentence_list:
    	lines = sentence.split('\n')
    	words = list(filter(lambda x: x and x.startswith("#") == False, lines))
    
    	tokens = []
    	tags = []
    	
    	for word in words:
    		champs = word.split('\t')
    		tokens.append(champs[1])
    		tags.append(champs[3])
    	
    	if len(tokens) == 1:
    		continue
    		
    	for i, tag in enumerate(tags):
    		if tag in patterns_dico.keys():
    			pat_list = patterns_dico[tag]
    			print(pat_list)
    			for ele in pat_list:
    				pat_leng = len(ele)
    				if tags[i:i+pat_leng] == ele:
    					n_gram = ' '.join(tokens[i:i+pat_leng])
    					key = ' '.join(ele)
    					patrons_dico[key].append(n_gram)
    					
    countresult = 0
    
    for pattern, patrons in patrons_dico.items():
    
    	tmp = {}
    	for patron in patrons:
    		try:
    			tmp[patron]
    		except:
    			tmp[patron] = 0
    		tmp[patron] += 1
    		
    	tmplist = sorted(tmp.items(), key = lambda x:x[1], reverse = True)
    	countresult += len(patrons)
    	patrons_dico[pattern] = tmplist
    	
    with open('sortie_talismane.txt', 'w', encoding = 'utf-8', newline = '\n') as sortie:
    	sortie.write('{} éléments trouvés\n'.format(countresult))
    	for pattern, patrons in patrons_dico.items():
    		sortie.write("Type de pattern: {}\n\n".format(pattern))
    		tmp = list(map(lambda x: sortie.write("{0}\t{1}\n".format(x[1], x[0])), patrons))
    		sortie.write('\n\n')
    		
    end = monotonic()
    print('Temps de traitement: {:.2f}s'.format(end - start))
    
        							 


      resultat_quatre_patrons




    Xquery

      treetagger_quatre_patrons
    for $art in collection("sortie-3214-regexp")//article
    for $elt in $art/element
    let $conc2 :=
      if (($elt/data[1]="NOM") and ($elt/following-sibling::element[1]/data[1]="PRP") and ($elt/following-sibling::element[2]/data[1]="NOM") and ($elt/following-sibling::element[3]/data[1]="PRP")) then (
        concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text()," ",$elt/following-sibling::element[2]/data[3]/text()," ",$elt/following-sibling::element[3]/data[3]/text()," ")
      )
      else if (($elt/data[1]="NOM") and ($elt/following-sibling::element[1]/data[1]/text()="ADJ")) then (
           concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text())
      )
      else if (($elt/data[1]="ADJ") and ($elt/following-sibling::element[1]/data[1]/text()="NOM")) then (
           concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text())
      )
      else if (($elt/data[1][contains(text(),"VER")]) and ($elt/following-sibling::element[1]/data[1][contains(text(),"DET")]) and ($elt/following-sibling::element[2]/data[1]/text()="NOM")) then (
           concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text()," ",$elt/following-sibling::element[2]/data[3]/text())
      )
      else (
        "
    "
      )
    where $conc2 != "
    "
    return $conc2
    
    							

      resultat_quatre_patrons

      script_xquery_chaque_patron

      resultat_chaque_patron



      script_talismane_quatre_patrons
    for $art in collection("sortie-3214-regexp")//article
    for $elt in $art/element
    let $conc2 :=
      if (($elt/data[1]="NOM") and ($elt/following-sibling::element[1]/data[1]="PRP") and ($elt/following-sibling::element[2]/data[1]="NOM") and ($elt/following-sibling::element[3]/data[1]="PRP")) then (
        concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text()," ",$elt/following-sibling::element[2]/data[3]/text()," ",$elt/following-sibling::element[3]/data[3]/text()," ")
      )
      else if (($elt/data[1]="NOM") and ($elt/following-sibling::element[1]/data[1]/text()="ADJ")) then (
           concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text())
      )
      else if (($elt/data[1]="ADJ") and ($elt/following-sibling::element[1]/data[1]/text()="NOM")) then (
           concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text())
      )
      else if (($elt/data[1][contains(text(),"VER")]) and ($elt/following-sibling::element[1]/data[1][contains(text(),"DET")]) and ($elt/following-sibling::element[2]/data[1]/text()="NOM")) then (
           concat($elt/data[3]/text()," ",$elt/following-sibling::element[1]/data[3]/text()," ",$elt/following-sibling::element[2]/data[3]/text())
      )
      else (
        "
    "
      )
    where $conc2 != "
    "
    
    return $conc2
    
    							

      resultat_quatre_patrons

        Ici, on peut observer que le nombre de result de xquery est le même avec python! (13,899 results)






    Xslt


      script_xslt_chaque_patron_treetagger

      resultat_html_patron_treetagger
        ATTENTION: il faut ouvrir ces pages avec le navigateur Firefox qui possède un convertisseur xslt-xml

        Si vous en avez pas, voici la photo de résultat


      script_xslt_chaque_patron_treetagger

      resultat_texte_patron_treetagger(on a omis quelques résultats pas très intéressants ici)



      script_talismane_quatre_patrons
    						


      resultat_quatre_patrons

        ATTENTION: il faut ouvrir ces pages avec le navigateur Firefox qui possède un convertisseur xslt-xml

        Si vous en avez pas, voici la photo de résultat
      script_xslt_chaque_patron_talismane

      resultat_texte_patron_talismane(le résultat est le même avec xquery et python)