tef-innu

Transducteur à états finis de l’innu
git clone git://git.asteride.xyz/tef-innu.git
Journaux | Fichiers | Références

rapport (4229B)


      1 #!/usr/bin/env python3
      2 #
      3 # rapport.py -- Produire un rapport sur la performance du modèle.
      4 #
      5 # $1 - Chemin vers l’extension
      6 # $2 - Chemin vers l’échantillon
      7 # $3 - Chemin vers les préfixes
      8 
      9 import sys
     10 
     11 # Charger dans un ensemble de tuples les paires contenues dans un fichier. Ces
     12 # paires doivent figurer une par ligne et leurs éléments doivent être séparés
     13 # par un caractère de tabulation.
     14 def charger_paires(fichier):
     15     paires = set()
     16     with open(fichier, "r") as f:
     17         for ligne in f:
     18             champs = ligne.rstrip().split("\t")
     19             if len(champs) != 2:
     20                 raise ValueError(f"{fichier}: {len(champs)} champ(s) plutôt que 2.")
     21             paires.add((champs[0], champs[1]))
     22     return paires
     23 
     24 def charger_lignes(fichier):
     25     lignes = set()
     26     with open(fichier, "r") as f:
     27         lignes = {ligne.rstrip() for ligne in f}
     28     return lignes
     29 
     30 # Convertir les paires d’un ensembe de couples à un dictionnaire dont la clé en
     31 # est le premier élément et la valeur le second. Aucune information n’est
     32 # perdue si le transducteur est séquentiel.
     33 def paires_vers_dict(paires):
     34     return {paire[0]:paire[1] for paire in paires}
     35 
     36 # Tester la séquentialité de l’extension dans le sens de la génération. Une
     37 # description abstraite doit correspondre à une seule forme. Renvoie un
     38 # ensemble contenant les descriptions abstraites qui rendent l’extension
     39 # non-séquentielle.
     40 def tester_sequentialite(extension):
     41     desc = set()
     42     doublons = set()
     43     for paire in extension:
     44         if paire[0] not in desc:
     45             desc.add(paire[0])
     46         else:
     47             doublons.add(paire[0])
     48     return doublons
     49 
     50 # Renvoyer les formes générés correctes.
     51 def vrais_positifs(echantillon, extension):
     52     vp = set()
     53     for c in echantillon:
     54         if c in extension and echantillon[c] == extension[c]:
     55             vp.add(c)
     56     return vp
     57 
     58 # Renvoyer les formes générées incorrectes.
     59 def faux_positifs(echantillon, extension):
     60     fp = set()
     61     for c in echantillon:
     62         if c in extension and echantillon[c] != extension[c]:
     63             fp.add(c)
     64     return fp
     65 
     66 # Renvoyer les formes non générées qui auraient dû l’être.
     67 def faux_negatifs(echantillon, extension):
     68     fn = set()
     69     for c in echantillon:
     70         if c not in extension:
     71             fn.add(c)
     72     return fn
     73 
     74 def precision(vp, fp):
     75     return len(vp) / (len(vp) + len(fp)) * 100
     76 
     77 def rappel(vp, fn):
     78     return len(vp) / (len(vp) + len(fn)) * 100
     79 
     80 def f1(pre, rap):
     81     return 2 * (pre * rap) / (pre + rap)
     82 
     83 # Afficher le rapport un sortie standard.
     84 def rapporter (echantillon, extension):
     85     print("=== RAPPORT ===")
     86     print()
     87     res = tester_sequentialite(extension)
     88     if res:
     89         print("NON SÉQUENTIEL!")
     90         for desc in res:
     91             print(desc)
     92         return
     93     # Convertir les paires
     94     echantillon = paires_vers_dict(echantillon)
     95     extension = paires_vers_dict(extension)
     96     print(f"Nombre de formes générées: {len(extension)}")
     97     res = len({extension[c] for c in extension})
     98     print("Nombre de formes uniques générées: "
     99         f"{res} ({res/len(extension)*100:.2f}%)")
    100     print(f"Taille de l’échantillon: {len(echantillon)} "
    101           f"({len(echantillon)/len(extension)*100:.2f}%)")
    102     print()
    103     vp = vrais_positifs(echantillon, extension)
    104     fp = faux_positifs(echantillon, extension)
    105     fn = faux_negatifs(echantillon, extension)
    106     print("--- FAUX POSITIFS ---")
    107     print()
    108     for f in fp:
    109         print(f"{f}: {echantillon[f]} ({extension[f]})")
    110     if fp:
    111         print()
    112     print("--- FAUX NÉGATIFS ---")
    113     print()
    114     for f in fn:
    115         print(f"{f}: {echantillon[f]}")
    116     if fn:
    117         print()
    118     print(f"Nombre de vrais positifs: {len(vp)}")
    119     print(f"Nombre de faux positifs: {len(fp)}")
    120     print(f"Nombre de faux négatifs: {len(fn)}")
    121     pre = precision(vp, fp)
    122     print(f"Précision: {pre:.2f}")
    123     rap = rappel(vp, fn)
    124     print(f"Rappel: {rap:.2f}")
    125     f = f1(pre, rap)
    126     print(f"F1: {f:.2f}")
    127 
    128 if __name__ == "__main__":
    129     if len(sys.argv) != 3:
    130         raise RuntimeError("Mauvais arguments.")
    131 
    132     ext = charger_paires(sys.argv[1])
    133     ech = charger_paires(sys.argv[2])
    134 
    135     rapporter(ech, ext)