Projeter des annotations Talismane sur un corpus TXM

On part du fichier TEI-TXM situé dans le sous-dossier ./txm :

$HOME/TXM/corpora/TESTMAGUERRE/txm/TESTMAGUERRE/maguerre.xml

Ce fichier contient (en autres) la tokenisation du corpus par TXM.

On applique un coup d’XSL pour extraire la liste des formes. Talismane a du mal à gérer une très longue colonne de mots. Sans doute pour des raisons de pré-segmentation en phrases. Une solution qui fonctionne consiste à conserver une structure en paragraphes (ou genre).

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:txm="http://textometrie.org/1.0"
    xmlns:tei="http://www.tei-c.org/ns/1.0" version="1.0">
    <xsl:output method="text"/>
    <xsl:template match="/">
        <xsl:apply-templates select="tei:TEI"/>  
    </xsl:template>
    <xsl:template match="tei:p|tei:div1|tei:div2|tei:head|tei:quote">
        <xsl:apply-templates select="tei:*"/>  
        <xsl:text>&#10;&#10;</xsl:text>  
    </xsl:template>
    <xsl:template match="tei:w">
        <xsl:value-of select="normalize-space(txm:form)"/>
        <xsl:text>&#10;</xsl:text>  
    </xsl:template>
    <xsl:template match="tei:*">
        <xsl:apply-templates select="tei:*"/>  
    </xsl:template>
</xsl:stylesheet>
On obtient le fichier txm-par.txt

On lance Talismane sur ce texte brut présegmenté.

java -Xmx8G -Dconfig.file=talismane-fr-4.1.0.conf -jar talismane-core-4.1.0.jar --analyse --encoding=UTF8  --inFile=txm-par.txt --outFile=txm-par.tal
On obtient le fichier txm-par.tal (le suffixe .tal vaut pour talismane).

On extrait la liste des formes retokenisées par Talismane par un coup de awk. On supprime au passage les lignes vides. On obtient le fichier tal-tokens.txt.

awk 'NF > 0 { print $2 }' txm-tokens.tal > tal-tokens.txt

On recourt à une autre XSL pour extraire la liste des formes de TXM : txm-tokens.txt

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:txm="http://textometrie.org/1.0"
    xmlns:tei="http://www.tei-c.org/ns/1.0" version="1.0">   
    <xsl:output method="text"/>   
    <xsl:template match="/">
        <xsl:apply-templates select="tei:TEI"/>  
    </xsl:template>
    <xsl:template match="tei:w">
        <xsl:value-of select="normalize-space(txm:form)"/>
        <xsl:text>&#10;</xsl:text>  
    </xsl:template>    
    <xsl:template match="tei:*">
        <xsl:apply-templates select="tei:*"/>  
    </xsl:template>   
</xsl:stylesheet>

On compare les deux listes de formes (txm-tokens.txt et tal-tokens.txt) par un diff.

diff -y txm-tokens.txt tal-tokens.txt > tokens.diff
grep '[|><]' tokens.diff > tokens.diff.grep

Adapter la tokenisation de Talismane par des règles

La tokenisation de Talismane peut être adaptée par des règles (TokenFilters). Il suffit de les rassembler dans un fichier et d'appeler ce dernier en lançant Talismane :

java ... --tokenFilters <File> ...

Ces règles peuvent s'ajouter aux règles en vigueur et même les défaire. Il faut pour cela mettre le préfixe replace: devant le nom du fichier.

Talismane sans tokenisation

Il semblerait qu'on puisse utiliser Talismane après tokenisation sur la base d'un fichier CONNL. Cela est décrit ici

On indique dans la ligne de commande le premier et le dernier module de la chaîne de traitement que l'on souhaite activer. Pour un simple POS-tagging, il faut mettre PosTag :

java ... startModule=PosTag endModule=PosTag ...

Idéalement, il faudrait pouvoir conserver l'ID du token tout au long du process. Cela veut dire préparer Talismane au fait d'avoir avant le token un ID qu'il ne faut pas parser et qu'il faut restituer en sortie.

S'il n'est pas évident de passer sous silence cet ID, Talismane va l'analyser (ce qui va générer du bruit). On peut arriver à configurer la sortie pour que le fichier résultant ait l'allure d'un CoNNL.

On doit concevoir une paramétrisation de la sortie, dans un fichier connl.ftl (un template, voir cette documentation.

[#ftl]
[#list sentence as unit][#if unit.token.index=1]${unit.token.originalText}[/#if][#if unit.token.index>1]	${unit.token.originalText}	[#if unit.posTaggedToken.lemmaForCoNLL=="_"]${unit.token.textForCoNLL}[#else]${unit.posTaggedToken.lemmaForCoNLL}	${unit.posTaggedToken.morphologyForCoNLL}[/#if][/#if][#if unit.token.trailingRawOutput??]${unit.token.trailingRawOutput}[/#if][/#list]

Comme Talismane lit deux tokens au lieu d'un (le premier est en fait l'ID TXM du second), le template va traiter différemment la sortie du premier et la sortie du second.

  • Pour le premier, il recrache tout simplement le token (l'ID).
  • Pour le second, il recrache l'analyse du second token.

Attention, l'analyse syntaxique sera forcément fausse car l'ID n'est pas censé figurer dans la phrase.

Pour terminer, voici comment appeler Talismane avec ce template :

jar ... --template connl.ftl

La feuille de style XSL permettant d'obtenir un CoNNL à deux colonnes : ID (ou le rang du mot) et token.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:txm="http://textometrie.org/1.0"
    xmlns:tei="http://www.tei-c.org/ns/1.0" version="1.0">    
    <xsl:output method="text"/>
    <xsl:template match="/">
        <xsl:apply-templates select="tei:TEI"/>  
    </xsl:template>    
    <xsl:template match="tei:w">
	<xsl:value-of select="txm:ana[@type='#n']"/>
	<xsl:text>&#9;</xsl:text>
        <xsl:value-of select="normalize-space(txm:form)"/>
	<xsl:text>&#10;</xsl:text>  
    </xsl:template>
    <xsl:template match="tei:*">
        <xsl:apply-templates select="tei:*"/>  
    </xsl:template>
    <xsl:template match="text()"/>    
</xsl:stylesheet>

Un programme awk permettant de nettoyer le résultat de Talismane et notamment d'éclater des informations morphosyntaxiques dans des colonnes.

BEGIN {
    printf("# ID\tTOKEN\tLEMMA\tNUMBER\tGENDER\tTIME\tPERSON\tPOSSESSOR\n");
}
NF == 2 {  printf("%s\t%s\n",$1,$2)}
NF == 3 {  printf("%s\t%s\t%s\n",$1,$2,$3)}
NF == 4 {  printf("%s\t%s\t%s\n",$1,$2,$3);
    printf("%s\t%s\t%s\t",$1,$2,$3);
    
    myNumber="_";
    myGender="_";
    myTime="_";
    myPossessor="_";
    myPerson="_";
    
    #printf("%s\t",$4);
    temp = split($4,seg,"|");
    
    for (i=1;i<=temp;i++) {
        if (match(seg[i],"^n=")) myNumber=substr(seg[i],3,10);
        if (match(seg[i],"^g=")) myGender=substr(seg[i],3,10);
        if (match(seg[i],"^t=")) myTime=substr(seg[i],3,10);
        if (match(seg[i],"^poss=")) myPossessor=substr(seg[i],6,10);
        if (match(seg[i],"^p=")) myPerson=substr(seg[i],3,10);
    }
    
    printf("%s\t%s\t%s\t%s\t%s\n",myNumber,myGender,myTime,myPerson,myPossessor);
}

public/talismane.txt · Dernière modification: 2017/07/24 16:28 par matthieu.quignard@ens-lyon.fr