swh:1:snp:80d54e43462bc8e3a7de024649d51f49d931d060
Tip revision: 50790d370cc6a7d81f80942cc4c5569a3c58efe1 authored by Software Heritage on 20 March 2020, 00:00:00 UTC
hal: Deposit 495 in collection hal
hal: Deposit 495 in collection hal
Tip revision: 50790d3
arbresetstats.py
# -*- coding: utf-8 -*-
"""
@author: lejocelyn
@licence:GPL3 + CeCill 2.1
"""
from __future__ import print_function
import oursql
import argparse
import sys
import graphviz as gv
import functools
import csv
import re
from collections import OrderedDict
graph = functools.partial(gv.Graph, format='svg')
digraph = functools.partial(gv.Digraph, format='svg')
parser = argparse.ArgumentParser(description='Get the data from a CSV file to input into the graph.')
parser.add_argument("--data", "-d", dest='data', type=str, default=False,
help="Spécifie le fichier duquel les données sont extraites.")
parser.add_argument("--fichier", "-f", dest='fichier', type=str, default="arbre_corpus",
help="Spécifie le nom du fichier dans lequel est écrit le graphique.")
parser.add_argument("--lettre", "-l", dest='lettre', type=str, default=False,
help="Restreint aux formes contenant la ou les lettres spécifiées.")
parser.add_argument("--syllabe", "-s", dest='syllabe', type=str, default=False,
help="Faire des stats et arbre pour la syllabe")
parser.add_argument("--contexte", "-c", dest='contexte', type=str, default=False,
help="""Définit un contexte pour limiter la recherche. Le formalisme
de définition du contexte est celui des expressions régulières.""")
parser.add_argument("--couleurs", "-o", dest='couleurs', type=str, default=False,
help="""Active ou non l'usage de couleurs pour marquer les lettres recherchées.""")
#parser.add_argument("--mots", "-m", dest='mots', type=str, default=False,
# help="""Si l'option est précisée, la requête est effectuée sur les unités d'intonations
# et représente les morphèmes à la place des lettres.""")
args = parser.parse_args()
####
####
#### Fonctions récurrentes proposées par la doc de graphviz
####
def add_nodes(graph, nodes):
for n in nodes:
if isinstance(n, tuple):
graph.node(n[0], **n[1])
else:
graph.node(n)
return graph
def add_edges(graph, edges):
for e in edges:
if isinstance(e[0], tuple):
graph.edge(*e[0], **e[1])
else:
graph.edge(*e)
return graph
def log_stats(info):
"""
append the stats information to the end of the stat file
"""
with open("stats_" + args.fichier + ".txt", "a") as myfile:
print(info, file=myfile)
myfile.write("\n")
def find_lettre_in_list(letter, liste):
"""
a letter being defined by a form and a position, find if a same label and
a same position can be already match in the list of node
"""
for element in liste: # si le caractère et la positon sont identiques
if element[1]["label"] == letter[1]["label"] and element[1]["position"] == letter[1]["position"] and element[1]["id_lettre_precedente"] == letter[1]["id_lettre_precedente"]:
return element[0]
return False
def get_lettre_in_list(id_lettre, liste_noeuds):
"""
retourne le nœud/lettre correspondant à l'id
"""
for lettre in liste_noeuds:
if lettre[0] == str(id_lettre):
return lettre
def find_liens_in_list(liste_liens, id_A=False, id_B=False):
"""
chercher un lien dans la liste des liens.
Si les deux ID, A et B, sont spécifiés, retourne le lien,
Si seul un ID, A ou B, est spécifié, retourne la liste des liens
satisfaisants l'ID demandé
"""
if id_A != False and id_B != False:
for lien in liste_liens:
# Lorsque l'on trouve le bon lien, on le renvoie
if lien[0][0] == id_A and lien[0][1] == id_B:
return lien
return False
elif id_A != False:
liste_id_A = []
for lien in liste_liens:
if lien[0][0] == id_A :
liste_id_A.append(lien)
return liste_id_A
elif id_B != False:
liste_id_B = []
for lien in liste_liens:
if lien[0][1] == id_B:
liste_id_B.append(lien)
return liste_id_B
def incremente_occurrence(id_lettre, liste_node, nom):
'''
incremente d'une occurrence la lettre dans la liste
et retourne la liste
'''
# exemple id_lettre : '1',
# exemple liste_node : [('1', {'style': 'filled', 'occurrence': '397',
# 'label': u'v', 'fillcolor': 'grey', 'position': '0', 'id_lettre_precedente': ' '}),
# ('2', {'style': 'filled', 'occurrence': '397',
# 'label': u'a', 'fillcolor': 'grey', 'position': '1', # 'id_lettre_precedente': '1'}),
# ('3', {'style': 'filled', 'occurrence': '397',
# 'label': u'n', 'fillcolor': 'grey', 'position': '2', 'id_lettre_precedente': '2'})],
# exemple nom : (u'va', 194L))
i_list = 0
for element in liste_node:
if element[0] == str(id_lettre):
tmp_occurrence = int(liste_node[i_list][1]["occurrence"])
tmp_occurrence += nom[1]
liste_node[i_list][1]["occurrence"] = str(tmp_occurrence)
i_list += 1
return liste_node
def incremente_lien(id_A, id_B, liste_liens, nom):
"""
Incrémente d'une occurrence du lien
"""
i_list = 0
for element in liste_liens:
if element[0][0] == str(id_A) and element[0][1] == str(id_B):
tmp_occurrence = int(liste_liens[i_list][1]["label"])
tmp_occurrence += nom[1]
liste_liens[i_list][1]["label"] = str(tmp_occurrence)
i_list += 1
#print(liste_liens)
return liste_liens
def ordonner_node(liste_noeuds):
"""
ordonne la liste des nœuds par ordre décroissant
"""
liste_ordonnee = []
#print(len(liste))
index = 0
for element in liste_noeuds:
i = 0
if len(liste_ordonnee) == 0:
liste_ordonnee.append(element)
else:
while True:
if len(liste_ordonnee) - i == 0:
liste_ordonnee.insert(i, element)
break
elif int(element[1]["occurrence"]) <= int(liste_ordonnee[i][1]["occurrence"]):
i += 1
else:
liste_ordonnee.insert(i, element)
break
index += 1
return liste_ordonnee
def get_total(liste_nodes):
"""
Retourne le nombre total d'occurrences de la requête. Ce nombre correspond à la somme
des occurrences des lettres en première position
"""
total = 0
for element in liste_nodes:
if int(element[1]["position"]) == 0:
total += int(element[1]["occurrence"])
return total
def couleur_noeud(label):
"""
Définit la couleur d'un noeud dans le schema SVG
"""
## Colorisation du schéma SVG
##
couleur_lettre = "white"
if args.couleurs:
# if label in args.contexte:
# couleur_lettre = "green"
if isinstance(args.lettre,str):
if label in args.lettre:
couleur_lettre = "red"
return couleur_lettre
def get_total_position(liste_nodes):
"""
retourne une liste de totaux suivant la position de la lettre
À quoi ça sert ?
"""
liste_total = []
for element in liste_nodes:
if len(liste_total) <= int(element[1]["position"]):
liste_total.append(int(element[1]["occurrence"]))
else:
liste_total[int(element[1]["position"])] += int(element[1]["occurrence"])
return liste_total
def compte_total_occurrence_lettres(liste_nodes):
"""
retourne un dictionnaire du nombre total d'occurrences de chacune des lettres et en fonction de leur position
"""
dico_compte_occurrence_lettres = {}
# Le dictionnaire aura la forme suivante :
# label : total, "position" : nb_occurrence
# {"s" : 13}
# pour rappel, un noeud à la forme suivante :
# str(id_lettre), {"label": label , "position": str(position_node),
# "id_lettre_precedente": " ", "occurrence":str(nom[1]), "fillcolor":couleur_noeud(label), "style":"filled"})
for noeud in liste_nodes:
lettre = noeud[1]["label"]
label_position = lettre + "_position_" + noeud[1]["position"]
if lettre in dico_compte_occurrence_lettres.keys():
dico_compte_occurrence_lettres[lettre] += int(noeud[1]["occurrence"])
else :
dico_compte_occurrence_lettres[lettre] = 0
dico_compte_occurrence_lettres[lettre] += int(noeud[1]["occurrence"])
if label_position in dico_compte_occurrence_lettres.keys():
dico_compte_occurrence_lettres[label_position] += int(noeud[1]["occurrence"])
else :
dico_compte_occurrence_lettres[label_position] = 0
dico_compte_occurrence_lettres[label_position] += int(noeud[1]["occurrence"])
dico_compte_occurrence_lettres = OrderedDict(sorted(dico_compte_occurrence_lettres.items(), key=lambda t: t[0]))
return dico_compte_occurrence_lettres
def comptage_formes(listes_liens, listes_nodes):
"""
Calcul du nombre de formes différentes dans l'arbre résultant de l'analyse du corpus.
"""
## Une lettre égale (str(id unique), dico{"label": "a", "position":"1", id_lettre_precedente = 23, "occurrence":str(nom[1])})
## lien = ((id_lettre_A, id_lettre_B), {"label": str(nom[1])})
nb_formes = 0
# Afin de déterminer le nombre de formes, le principe est de comparer le nombre
# d'occurrences. Si le nombre d'occurrences d'une lettre est différent du
# nombre d'occurrences de la lettre précédentes, cela signifie qu'il y a
# une forme langagière.
# Une forme est :
# Si l'on prend la liste des morphèmes, cela correspond à un morphème
# Si l'on prend la liste des syllables, cela correpond à une syllabe,
# si l'on prend la liste des squellettes, cela correspond à un squelette
# Initialisation des variables de comparaison à false
occurrence_lettre_A = False
occurrence_lettre_B = False
# Calcul du nombre de branches, puis on ajoutera les moments où
# la somme des occurrences des lettres "branches" n'est pas égale au nombre d'occurrences
# du nœud précédent
nb_branches = 0
nb_arbres = 0
liste_A_deja_compte = {}
# la clef, un str, indique le nombre de lettres du morphème, et la valeur son nombre d'occurrences
dico_forme_nb_lettres = {}
# il faut compter les lettres isolées :
# si l'id de la lettre n'est pas dans la liste des liens
# alors l'ajouter comme une lettre isolée
liste_id_lettre = []
liste_id_liens = []
for lettre in listes_nodes:
liste_id_lettre.append(int(lettre[0]))
for element in listes_liens:
liste_id_liens.append(int(element[0][0]))
liste_id_liens.append(int(element[0][1]))
for id_lettre in liste_id_lettre:
lettre_temp = get_lettre_in_list(id_lettre,listes_nodes)
dico_forme_nb_lettres[lettre_temp[1]["position"]] = 0
if id_lettre not in liste_id_liens:
nb_formes += 1
# la lettre ne peut pas avoir déjà été ajouté, vu qu'elle n'est pas dans la liste
dico_forme_nb_lettres[lettre_temp[1]["position"]] += 1
copie_listes_liens = listes_liens # pas clair la raison de ce hack, une question de globalspace
for lien in listes_liens:
lettre_A_id = lien[0][0]
lettre_B_id = lien[0][1]
lettre_A = get_lettre_in_list(lettre_A_id,listes_nodes)
lettre_B = get_lettre_in_list(lettre_B_id,listes_nodes)
# initialisation du comptage de nombre de formes par position :
if dico_forme_nb_lettres.get(lettre_A[1]["position"]) == None :
dico_forme_nb_lettres[lettre_A[1]["position"]] = 0
if dico_forme_nb_lettres.get(lettre_B[1]["position"]) == None :
dico_forme_nb_lettres[lettre_B[1]["position"]] = 0
## Si la lettre est la première de la forme, alors il s'agit d'une nouvelle
## forme
if int(lettre_A[1]["position"]) == 0:
if lettre_A_id not in liste_A_deja_compte:
# pas la peine de les compter car cela ferait doublon avec le compte des branches terminales
#nb_formes += 1
nb_arbres += 1
#print("nouvel arbre")
occurrence_lettre_A = int(lettre_A[1]["occurrence"])
occurrence_lettre_B = int(lettre_B[1]["occurrence"])
liste_lien_lettre_A = find_liens_in_list(copie_listes_liens, id_A=lettre_A_id)
liste_lien_lettre_B = find_liens_in_list(copie_listes_liens, id_A=lettre_B_id)
somme_occurrence_lien = 0
for lien in liste_lien_lettre_A:
somme_occurrence_lien += int(lien[1]["label"])
if somme_occurrence_lien != occurrence_lettre_A:
if lettre_A_id in liste_A_deja_compte:
pass
else:
# Les branches intermédiaires sont en fait des formes
# existantes mais qui possèdent également des sous-branches
nb_formes += 1
dico_forme_nb_lettres[lettre_A[1]["position"]] += 1
#print("branche intermédiaire")
if len(liste_lien_lettre_B) == 0:
nb_formes += 1
dico_forme_nb_lettres[lettre_B[1]["position"]] += 1
#print("fin de la branche")
# On conserve la somme des occurrences des branches pour les prochaines itérations
liste_A_deja_compte[lettre_A_id] = somme_occurrence_lien
log_stats("Nombre total d'arbres:\n")
log_stats(nb_arbres)
log_stats("Nombre de formes existantes en fonction du nombre de lettres :\n")
tri_dico_forme_nb_lettres = OrderedDict(sorted(dico_forme_nb_lettres.items()))
log_stats(tri_dico_forme_nb_lettres)
return nb_formes
def navigation_arbre_lettre(liste_des_noms):
"""à définir """
# dans ce dico, on stocke les noms correspondants à la requete
dico_correspond = {}
noms_total = 0
for element in liste_formes:
noms_total += int(element[1])
liste_nodes = []
liste_liens = []
# Une lettre égale (str(id unique), dico{"label": "a", "position":"1", id_lettre_precedente = 23, "occurrence":str(nom[1])})
i_lien = 0
i_node = 0
#id_lettre est un identifiant unique pour chaque lettre
id_lettre = 0
# nombre de morphèmes existants dans le corpus
nb_formes = 0
liste_lettres_premiere_position = []
# nom est un tuple : (forme, nb_occurrences)
for nom in liste_formes:
# Si l'utilisateur a spécifié qu'il souhaité concentré la recherche uniquement
# sur les mots contenant une ou plusieurs lettres, les autres mots sont enlevé
# de la recherche.
if args.lettre != False:
for lettre in args.lettre:
if lettre not in nom[0]:
cont = True
else :
cont = False
if args.lettre != True:
cont = False
if cont == True:
continue
# Si l'utilisateur définit un contexte, il faut voir si le nom
# contient le contexte rechercher par l'utilisateur, sinon, on passe
if args.contexte != False:
match = re.search(args.contexte, nom[0])
if match is None:
continue
# Si l'utilisateur spécifie qu'il étudie la structure syllabique, les lettres
# sont alors remplacées par leur symbole correspondant S = Demivoyelle; V = voyelle, C = consonne
if args.syllabe != False:
nouveau_nom = u""
i_index_lettre = 0
for lettre in nom[0]:
if lettre in consonnes:
nouveau_nom += "C"
elif lettre in voyelles:
# Gestion des semiconsonnes
if len(nom[0]) > 1 and len(nom[0]) == i_index_lettre + 1 and nom[0][i_index_lettre -1] in voyelles:
if lettre == "i" or lettre == "o":
nouveau_nom += "S"
else:
nouveau_nom += "V"
else:
nouveau_nom += "V"
else:
nouveau_nom += lettre
i_index_lettre += 1
nom = (nouveau_nom, nom[1])
# dictionnaire des noms correspondant
dico_correspond[nom[0]] = nom[1]
# Le premier cas de la liste est particulier, étant donné qu'il ne peut être comparé
# avec la lettre précédente..
position_node = 0
label = nom[0][0]
lettre_A = (str(id_lettre), {"label": label , "position": str(position_node),
"id_lettre_precedente": " ", "occurrence":str(nom[1]), "fillcolor":couleur_noeud(label), "style":"filled"})
# si la lettre est en première position du mot
if position_node == 0:
liste_lettres_premiere_position.append(lettre_A[1]["label"])
liste_lettres_premiere_position = list(dict.fromkeys(liste_lettres_premiere_position))
# qu'est qu'on vérifie déjà ?
if len(nom[0]) == 1:
id_lettre_A = find_lettre_in_list(lettre_A, liste_nodes)
if id_lettre_A: # déjà dans la liste des lettres existantes
liste_nodes = incremente_occurrence(id_lettre_A, liste_nodes, nom)
lettre_A = get_lettre_in_list(id_lettre_A, liste_nodes)
else: # ajout de la lettre A dans la liste des nodes
id_lettre += 1
lettre_A = (str(id_lettre), {"label": label , "position": str(position_node),
"id_lettre_precedente": " ", "occurrence":str(nom[1]), "fillcolor":couleur_noeud(label), "style":"filled"})
liste_nodes.append(lettre_A)
continue
# On commence par le deuxième élément de la liste, le premier ayant déjà été étudié
for lettre in nom[0][1:]:
# la lettre de référence, lettre A, est la première lettre du mot
id_lettre_A = find_lettre_in_list(lettre_A, liste_nodes)
if id_lettre_A: # déjà dans la liste des lettres existantes
if position_node == 0:
liste_nodes = incremente_occurrence(id_lettre_A, liste_nodes, nom)
lettre_A = get_lettre_in_list(id_lettre_A, liste_nodes)
else: # ajout de la lettre A dans la liste des nodes
id_lettre += 1
lettre_A = (str(id_lettre), {"label": label , "position": str(position_node),
"id_lettre_precedente": " ", "occurrence":str(nom[1]), "fillcolor":couleur_noeud(label), "style":"filled"})
liste_nodes.append(lettre_A)
id_lettre_A = lettre_A[0]
# La première lettre étant A, on incrémente pour la lettre B
position_node += 1
# la lettre B est la lettre suivante du mot
label_b = nom[0][position_node]
lettre_B = (str(id_lettre), {"label":label_b, "position":str(position_node),
"id_lettre_precedente":lettre_A[0], "occurrence":str(nom[1]), "fillcolor":couleur_noeud(label_b), "style":"filled"})
id_lettre_B = find_lettre_in_list(lettre_B, liste_nodes)
if(id_lettre_B): # déjà dans la liste des lettres existantes
lettre_B = get_lettre_in_list(id_lettre_B, liste_nodes)
liste_nodes = incremente_occurrence(id_lettre_B, liste_nodes, nom)
#print("find B")
#raw_input()
if lettre_A[0] == lettre_B[1]["id_lettre_precedente"]:
liste_liens = incremente_lien(id_lettre_A, id_lettre_B, liste_liens, nom)
else: # nouveau lien
liste_liens.append(((id_lettre_A, id_lettre_B), {"label": str(nom[1])}))
else: # ajout de la lettre B dans la liste des nodes
id_lettre += 1
lettre_B = (str(id_lettre), {"label":nom[0][position_node], "position":str(position_node),
"id_lettre_precedente":lettre_A[0], "occurrence":str(nom[1]), "fillcolor":couleur_noeud(label_b), "style":"filled"})
liste_nodes.append(lettre_B)
liste_liens.append(((id_lettre_A, lettre_B[0]), {"label": str(nom[1])}))
# Les occurrences ayant déjà été comptabilisé une fois, il ne faut pas les ajouter à nouveau.
lettre_A = lettre_B # la lettre de référence devient la lettre B, la lettre suivante
#raw_input()
log_stats("Liste des lettres en première position de mot :")
log_stats(liste_lettres_premiere_position)
total = get_total(liste_nodes)
log_stats("Nombre total d'occurrences des nœuds:")
log_stats(total)
position_totale = get_total_position(liste_nodes)
log_stats("Nombre total d'occurrences des nœuds par position:")
log_stats(position_totale)
occurrences_lettres = compte_total_occurrence_lettres(liste_nodes)
log_stats("compte lettres noeuds :")
log_stats(occurrences_lettres)
log_stats("Liste des mots, ordonnée par taille :\n")
dico_tri = OrderedDict(sorted(dico_correspond.items(), key=lambda x:len(x[0])))
log_stats(dico_tri)
log_stats("Nombre de formes:\n")
nb_formes_total = 0
for element in dico_tri.items() :
nb_formes_total += element[1]
log_stats(str(nb_formes_total))
#print(len(liste_nodes))
liste_nodes = ordonner_node(liste_nodes)
formes = comptage_formes(liste_liens, liste_nodes)
log_stats("Nombre totales de formes existantes :\n")
log_stats(formes)
#print(liste_liens)
add_edges(
add_nodes(digraph(), liste_nodes),
liste_liens
).render("img/" + args.fichier)
def navigation_arbre_mots(liste_des_enonces):
return "hé hé, pas encore"
##### extrait les noms du fichiers CSV pour en faire une liste []
log_stats("args.fichier")
log_stats(args.fichier)
liste_formes = []
if args.data:
with open(args.data, 'rb') as csvfile:
spamreader = csv.reader(csvfile, delimiter=',', quotechar='|')
for row in spamreader:
liste_formes.append((unicode(row[0]), int(row[1])))
else :
db = oursql.connect(host="localhost", # your host, usually localhost
user="lejocelyn", # your username
passwd='Lejocelyn1', # your password
db="lexique_nisvai") # name of the data base
cursor = db.cursor()
if args.mots:
cursor.execute("""SELECT nisvais
FROM Enonces;"""
)
else:
### COUNT permet d'ordonner les résultats de la recherche
### par ordre décroissant de gauche à droite de la forêt
### d'arbres
cursor.execute("""SELECT Termes.termes, COUNT(Termes.id_termes)
FROM Termes_has_Enonces INNER JOIN Termes ON Termes.id_termes = Termes_has_Enonces.id_termes
WHERE Termes.id_categories=1
GROUP BY Termes.id_termes
ORDER BY COUNT(Termes.id_termes) DESC;"""
)
liste_formes = cursor.fetchall()
#### Les lettres du nisvais
consonnes = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w"]
voyelles = ["a", "e", "u", "i", "o", "y"]
#### Possibilité de définir d'autres classes
####
if args.mots:
navigation_arbre_mots(liste_formes)
else :
navigation_arbre_lettre(liste_formes)
########### MOYENNE DURÉE GROUPE DE SOUFFLE
# select Textes.id_textes, SUM(t2-t1)/COUNT(Textes.id_textes) AS moyenne From Enonces INNER JOIN Textes on Enonces.id_textes=Textes.id_textes WHERE Textes.id_corpus="T9" OR Textes.id_corpus="T8";