Je fais un script de parsing d'XML. Il fait un prétraitement avec ElementTree et extrait des phénomènes linguistiques complexes d'un texte. J'ai mis ce texte dans un dictionnaire qui a pour clé un identifiant unique (le numéro d’apparition du mot) et pour valeur le mot.
Pour chaque phénomène linguistique, ex : le segment de phrase "a été averti", je dois obtenir l'id de dico3 du premier mot (pour ce 'a', c'est 66) et du dernier mot (pour 'averti', c'est 68) afin d'avoir une colonne avec ces id. Le problème, c'est que les mots peuvent apparaître plusieurs fois dans mon texte et j'obtiens donc plusieurs id pour chaque mot alors que je veux l'id précis des mots de ce segment de phrase...
On m'a conseillé de transformer dico3 en une liste car il n'y a par exemple pas d'ordre dans un dictionnaire :
dico3 = [{k, v} for k, v in enumerate(l_content)] #OU liste contenant des dictionnaires
dico3 = [[k, v] for k, v in enumerate(l_content)] #OU liste contenant des listes
J'ai déjà essayé plusieurs choses pour extraire l'id, mais je n'y arrive pas dans mes boucles et en utilisant des list comprehensions...
Est-ce que quelqu'un aurait une idée ? Merci beaucoup !
Voici ce que j'essaie d'obtenir :
Filename \t Typetext_Gold \t ID_start_end
SAJ1 \t {'features': 'phenomene;passive'} \t a été averti \t [66, 68]
SAJ1 \t {'features': 'phenomene;passive'} \t est terminée \t [118, 119]
SAJ1 \t {'features': 'phenomene;abreviation'} \t SAJ \t [85]
Voici ce que j'obtiens avec key_list... les id ne sont pas corrects à cause de son emplacement dans la boucle (j'ai aussi essayé de le déplacer à la fin, mais je n'obtiens plus d'id avec key_list).
Filename \t Type \t text_Gold \t ID
SAJ1 \t {'features': 'phenomene;passive'} \t a été averti \t [67]
SAJ1 \t {'features': 'phenomene;abreviation'} \t SAJ \t [57, 94, 118]
Et voici mon code complet :
import re
import xml.etree.ElementTree as ET
filename = str(input("Fichier : ")) #Nom du fichier à traiter
xmlfile = open(filename, "r", encoding="utf-8")
b = filename.strip(".xml").split('-')
textname = b[0] #Récupération du nom du texte
tree = ET.parse(xmlfile)
root = tree.getroot()
resultfile = open("result.txt", "w", encoding="utf-8")
dico1 = [] #Liste contenant les labels des balises (type de phénomènes)
dico2 = [] #Liste contenant le segment annoté
for line in xmlfile:
re.sub(r"'","'", line) #Prétraitement des erreurs
for segment in root.iter('segment'):
dico1.append(segment.attrib) #Liste contenant un dico
dico2.append(segment.text) #Liste contenant des strings
all_phenomene = ["\tFilename", "Type", "text_Gold", "ID", "\n"] #Ajouter le ID (début-fin) +
type_phenomene = ["passive", "abreviation", "subordonnee", "subordonnee;relatives", "subordonnee;completives", "subordonnee;autres"]
#"""
#Test pour l'alignement sur la base d'un id pour chaque mot du texte source sans annotation (fonctionne)
sourcefile = open("SAJ1.txt", "r", encoding="utf-8")
content = sourcefile.read()
l_content = content.split()
dico3 = {k: v for k, v in enumerate(l_content)} #Dictionnaire contenant chaque mot (valeur) associé à l'id (clé/nombre unique)
#dico3 = [{k, v} for k, v in enumerate(l_content)] #OU liste contenant des dictionnaires
#dico3 = [[k, v] for k, v in enumerate(l_content)] #OU liste contenant des listes
print(dico3) #Ex. : {0: 'score-kms:', 1: 'date:', 2: 'source:SAJ.doc', 3: 'section:1', 4: 'organe:www.aidealajeunesse.cfwb.be', 5: 'title:Demande', 6: "d'intervention…", 7: 'Le', 8: 'service', 9: 'de', 10: "l'aide", 11: 'à', 12: 'la', 13: 'jeunesse', 14: '(SAJ)', 15: 'Si', 16: 'vous', 17: 'souhaitez', ...}
sourcefile.close()
key_list = []
mot_segment = str(dico2).split() #Les segments de phrases annotés et +- tokenisés dans une liste
#"""
for phenomene in type_phenomene:
for a, b in zip(dico1, dico2): #a est un dict ; b est un string / dico1 une liste ; dico2 une liste
if a.get("features") == f"phenomene;{phenomene}":
all_phenomene.append(textname) #Le nom du fichier
del a['id'] #C'est l'id donné par CorpusTool (l'ordre des annotations), cela peut être utile de conserver pour retrouver le 'parent' (sub imbriquées)
del a['state']
all_phenomene.append(str(a)) #La balise (id de CorpusTool et type de phénomène)
all_phenomene.append(b) #Le segment de phrase
#"""
#Suite du test pour l'alignement (fonctionne en partie)
c = b.split() #Problème, pas d'id pour les mots avant le split
#print(c, len(c))
for word in c: #Parcourt les mots des segments
#print(mot_segment, len(mot_segment))
if word in mot_segment: #Si le mot se trouve dans le dico3
#key_list = ([(k, val) for k, val in [dico3{k, val}.items()] if val == word]) #Pour chaque mot, donne tous les id possibles or on veut celui du segment en cours
key_list = [k for (k, val) in dico3.items() if val == word] #Pour chaque mot, donne tous les id possibles or on veut celui du segment en cours
#del key_list[1:]
print(key_list, word)
all_phenomene.append(str(key_list))
#L'idée était de comparer ces nombres et de récupérer les valeurs (mot) dont les int(clés) seraient donc une suite de nombres continue avec len>n à déterminer
#"""
all_phenomene.append("\n") #Le retour à la ligne
nbre_line = (len(all_phenomene)//5)-1 #Diviser par le nbre d'éléments différents dans la liste de phénomènes, -1 à cause de l'entête des colonnes
print(f"Nombre de phénomènes dans le fichier : {nbre_line}")
"""
Autre début de piste pour l'alignement, mais sans arriver à obtenir des id...
phrases, words =[], []
for text_Gold in all_phenomene[2::4]:
token = text_Gold.split()
phrases.append(token)
for word in token:
words.append(word)
print("Phrases :", phrases)
print("Words :", words)
"""
new_all_phenomene = "\t".join(all_phenomene)
resultfile.write(new_all_phenomene)
xmlfile.close()
resultfile.close()
On t'a proposé une liste à juste titre, parce qu'un ID peut-être comparé à un index de liste.
Créer un dictionnaire en mettant un entier comme clé représentant des ID (ou index) ne sert strictement à rien...
Ta liste est facilement définissable avec un simple words = [w for w in l_content] mais tu ferais bien d'apprendre les boucles simples si tu ne maîtrises pas les boucles complexes, c'est suffisant.
Pour avoir un mot par rapport à un ID, word = words[ID]
Pour avoir l'ID par rapport à un mot, ID = words.index(word)
- Edité par fred1599 5 avril 2020 à 11:40:31
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard) La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Merci pour ta réponse. Je rencontre néanmoins d'autres problèmes.
phrases, words, ID =[], [], []
for text_Gold in all_phenomene[2::4]:
token = text_Gold.split()
phrases.append(token)
for word in token:
word1 = list(word)
#words.append(word)
words = [w for w in l_content]
print(words, "word:", word, "word1:", word1)
print(type(words), "word:", type(word), "word1:", type(word1))
ID = words.index(word)
print(ID)
Que j'écrive ID = words.index(word) ou ID = words.index(word1), j'obtiens une ValueError comme quoi word ou word1 n'est pas une liste... et ce, même quand je le transforme explicitement en liste comme dans cette capture d'écran :
De plus, je pensais que la méthode .index(string) renvoie uniquement l'index de la première occurrence du mot. Si le mot du segment est le deuxième dans 'content', cela peut-il fonctionner ?
Pourquoi générer les mots à chaque token alors que tu auras toujours le même résultat pour words ?
Pour ta dernière question, c'était une demande dans ton 1er topic ? Pour index regarde la doc...
Merci d'être plus clair dans la demande et d'utiliser les balises code du forum.
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard) La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Anonyme
5 avril 2020 à 17:25:01
- Message modéré pour le motif suivant : Merci d'utiliser le bouton code du forum pour insérer votre code
Merci de colorer votre code à l'aide du bouton Code
Les forums d'Openclassrooms disposent d'une fonctionnalité permettant de colorer et mettre en forme les codes source afin de les rendre plus lisibles et faciles à manipuler par les intervenants. Pour cela, il faut utiliser le bouton de l'éditeur, choisir un des langages proposés et coller votre code dans la zone prévue. Si vous utilisez l'éditeur de messages en mode Markdown, il faut utiliser les balises <pre class="brush: python;">Votre code ici</pre>.
Merci de modifier votre message d'origine en fonction.
Ce message n'avait pas besoin d'être modéré... fred1599 m'avait simplement demandé un screenshot de print. Il n'y avait aucun code en plus par rapport à mon précédent post. Bon, je reprends puisque je ne peux pas le modifier.
Désolée, je suis encore débutante en Python, j'espère que c'est plus clair.
Voici le résultat de la variable que tu m'as demandé. En fait, je fais une boucle afin de parcourir les mots qui se trouvent dans la variable token afin d'associer à ces mots l'index de ces mots (le premier et le dernier) dans la liste l_content. J'ai testé plusieurs choses, mais j'obtiens toujours une ValueError à cause d'une liste.
print(l_content)
for text_Gold in all_phenomene[2::4]:
token = text_Gold.split()
print(token)
for word in token:
words = [w for w in l_content]
ID = words.index(word)
#print(ID, l_content)
Et oui, j'avais bien compris ce que faisait la méthode index. Le problème, c'est qu'un mot de mon texte peut apparaître plusieurs fois. Par exemple, "'à', 'la', 'Jeunesse', ..., 'à', 'une', 'convocation'". Si mon segment est le trigramme "à une convocation", la méthode sur le mot "à" va me renvoyer l'index du premier mot alors que je veux le deuxième.
list.index(x)
Retourne la position du premier élément de la liste ayant la valeur x. Une exception est levée s’il n’existe aucun élément avec cette valeur.
Alors déjà pour la modération il avait raison et il aura encore raison de virer tes screenshots illisibles.
Si je veux faire des petits tests de mon côté, il me faut la sortie de ton print(token) dans un texte que je puisse copier coller.
Il me faudra de la même manière l_content avec un petit code de ta part testable, c'est à dire que quand j'exécute, je dois reproduire la même erreur que toi... en simplement le copiant collant.
Ensuite le plus simple est de donner le format que tu attends (plusieurs exemples c'est top) qu'on puisse comparer notre code test et les résultats attendus.
Voilà normalement comment tu dois présenter ton code. Merci pour nos yeux !
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard) La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Ce message n'avait pas besoin d'être modéré... fred1599 m'avait simplement demandé un screenshot de print. Il n'y avait aucun code en plus par rapport à mon précédent post. Bon, je reprends puisque je ne peux pas le modifier.
Bonjour,
Si ce message avais besoin d'être modéré. Je ne vois pas dans les messages de fred qu'il vous aie demander un screenchot, ce qui m’étonnerais d’ailleurs puisqu’il connait les règles du forum.
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)