2017-05-27 4 views
0

Exemple de mon fichier xml ressemble:en utilisant des arguments de mots clés en fonction pour la génération de n-grammes en option

<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet type="text/xsl" href="folia.xsl"?> 
<FoLiA xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://ilk.uvt.nl/folia" xml:id="untitled" generator="libfolia-v0.10"> 
    <metadata type="native"> 
    <annotations> 
     <token-annotation annotator="ucto" annotatortype="auto" datetime="2017-04-17T14:50:04" set="tokconfig-nl"/> 
     <pos-annotation annotator="frog-mbpos-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mbpos-cgn"/> 
     <lemma-annotation annotator="frog-mblem-1.1" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mblem-nl"/> 
     <chunking-annotation annotator="frog-chunker-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-chunker-nl"/> 
     <entity-annotation annotator="frog-mwu-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mwu-nl"/> 
     <entity-annotation annotator="frog-ner-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-ner-nl"/> 
     <morphological-annotation annotator="frog-mbma-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mbma-nl"/> 
     <dependency-annotation annotator="frog-depparse-1.0" annotatortype="auto" set="http://ilk.uvt.nl/folia/sets/frog-depparse-nl"/> 
    </annotations> 
    </metadata> 
    <text xml:id="untitled.text"> 
    <p xml:id="untitled.p.1"> 
     <s xml:id="untitled.p.1.s.1"> 
     <w xml:id="untitled.p.1.s.1.w.1" class="WORD"> 
      <t>De</t> 
      <pos class="LID(bep,stan,rest)" confidence="0.999701" head="LID"> 
      <feat class="bep" subset="lwtype"/> 
      <feat class="stan" subset="naamval"/> 
      <feat class="rest" subset="npagr"/> 
      </pos> 
      <lemma class="de"/> 
      <morphology> 
      <morpheme> 
       <t offset="0">de</t> 
      </morpheme> 
      </morphology> 
     </w> 

je fais une fonction pour générer mot uniforme, bi et trigrammes d'un fichier xml. Je veux rendre le n-gramme optionnel, de sorte que vous puissiez choisir si vous voulez tous les n-grammes ou par exemple seulement les unigrams. Le résultat de ma fonction est la fréquence relative vectorisée du mot n-gram. J'ai essayé ceci en utilisant des arguments de mot-clé dans mes paramètres (en utilisant Vrai et Faux). Je reçois un dictionnaire vide, donc je dois faire quelque chose de mal. Voici ce que j'ai. Quelqu'un peut-il me dire ce que je fais mal?

import re 
import xml.etree.ElementTree as ET 

def word_ngrams(frogged_xmlfile, unigrams=True, bigrams=True, trigrams=True): 
    vector = {} 
    tree = ET.parse(frogged_xmlfile) #enter the xml tree 
    root = tree.getroot() 
    tokens = [] 
    words = [] 
    regex = re.compile(r'[^0-9] |[^(\.|\,|\?|\:|\;|\!)]') 
     for node in root.iter('w'): 
     for w in node.findall('t'): 
      tokens.append(w.text) 
    for word in tokens: 
     if regex.search(word): 
      words.append(word) 
    if (unigrams): 
     for n in [1]: #unigrams 
      grams = ngrams(words, n) 
      fdist = FreqDist(grams) 
      total = sum(c for g,c in fdist.items()) 
     for gram, count in fdist.items(): 
      vector['w'+str(n)+'+'+' '.join(gram)] = count/total 

    if (bigrams): 
     for n in [2]: #bigrams 
      grams = ngrams(tokens, n) 
      fdist = FreqDist(grams) 
      total = sum(c for g,c in fdist.items()) 
     for gram, count in fdist.items(): 
      vector['w'+str(n)+'+'+' '.join(gram)] = count/total 

    if (trigrams): 
     for n in [3]: #trigrams 
      grams = ngrams(tokens, n) 
      fdist = FreqDist(grams) 
      total = sum(c for g,c in fdist.items()) 
     for gram, count in fdist.items(): 
      vector['w'+str(n)+'+'+' '.join(gram)] = count/total 
    return vector 
print(word_ngrams('romanfragment_frogged.xml', unigrams = True, bigrams = False, trigrams = False)) 
+0

Le segment unigramme de ce code doit être en retrait, ce qui effacera votre logique. – robertlayton

+0

@robertlayton, l'erreur d'identification a été faite lorsque j'ai tapé le code ici. Je l'ai réparé, mon problème reste. Ou voulez-vous dire autre chose? – Bambi

+0

@HughBothwell je vous remercie pour les modifications, mais ce sont aussi des fautes que j'ai faites lors de la saisie du code ici – Bambi

Répondre

2
  1. Votre recherche ignore l'espace de noms par défaut de documents, il ne trouve jamais les étiquettes correspondant.

  2. Votre regex est vraiment terrible -

    "[^0-9] "     # not-a-digit, followed by space 
    "|"       # OR 
    "[^(\.|\,|\?|\:|\;|\!)]" # bad syntax, but I think you mean not one of .,?:;! 
    

    Il acceptera toute ponctuation suivi d'un espace (comme non un chiffre), ou un chiffre ou un autre caractère ou des espaces (comme sans ponctuation) ! Fondamentalement, la seule chose qui ne correspond pas est "une chaîne composée entièrement de caractères de ponctuation".

    Je vais deviner que ce que vous vouliez vraiment était "une chaîne contenant au moins une lettre et aucun caractère non-lettre", mais n'hésitez pas à me corriger.

  3. Votre code n'inclut pas ngrams() ou FreqDist() donc je ne peux pas le tester.

  4. L'indentation de for gram, count ... semble incorrecte - je pense qu'il devrait être indenté d'un niveau de plus.

  5. Vous avez beaucoup de code dupliqué inutilement.

Essayez ceci:

# import re 
import xml.etree.ElementTree as ET 

FOLIA_NAMESPACE = { 
    'default': 'http://ilk.uvt.nl/folia', 
    'xlink': 'http://www.w3.org/1999/xlink' 
} 

def is_word(s): 
    return s.isalpha() 
    # as a regex: 
    # return re.match("[A-Za-z]+$", s) is not None 

def load_words(folia_xml_file, is_word=is_word, namespace=FOLIA_NAMESPACE): 
    root = ET.parse(folia_xml_file).getroot() 
    tokens = root.findall(".//default:w/default:t", namespace) 
    return [t.text for t in tokens if is_word(t.text)] 

def make_ngram_vectors(words, n_values=[1,2,3]): 
    vectors = {} 
    for n in n_values: 
     grams = ngrams(words, n) 
     fdist = FreqDist(grams) 
     total = sum(count for gram,count in fdist.items()) 
     for gram,count in fdist.items(): 
      key = "w{}+{}".format(n, " ".join(gram)) 
      vectors[key] = count/total 
    return vectors 

def main(): 
    words = load_words("romanfragment_frogged.xml") 
    vectors = make_ngram_vectors(words, [1]) 
    print(vectors) 

if __name__ == "__main__": 
    main() 

Edit: Si vous regardez dans la balise <FoLiA> en haut de votre fichier xml, vous verrez xmlns= (le lien définissant l'espace de noms par défaut du document, c'est-à-dire quelles balises sont disponibles) et xmlns:xlink= (un autre espace de noms XLink, qui définit des balises comme xlink:href et xlink:show - voir https://www.w3schools.com/xml/xml_xlink.asp). ElementTree aime étendre les espaces de noms en ligne afin que vos balises ressemblent à celles de {http://ilk.uvt.nl/folia}w. Le passage d'un dict de l'espace de noms nous permet d'utiliser une mise en forme plus lisible comme default:w à la place.

Pour obtenir les mêmes formats d'entrée/sortie en tant que votre fonction d'origine, vous pouvez utiliser une fonction wrapper comme:

def word_ngrams(folia_xml_file, unigrams=True, bigrams=True, trigrams=True): 
    # condense parameters into n_values 
    n_values = [] 
    if unigrams: 
     n_values.append(1) 
    if bigrams: 
     n_values.append(2) 
    if trigrams: 
     n_values.append(3) 
    words = load_words(folia_xml_file) 
    return make_ngram_vectors(words, n_values) 
+0

Merci beaucoup pour votre aide! En effet, je veux tous les mots, mais pas de chiffres et pas de ponctuation. Je suis assez nouveau dans la programmation, donc je ne comprends pas complètement votre code. J'ai quelques questions. 1.Qu'est-ce que l'espace de noms folia exactement, en particulier x-link? 2.Cette fonction doit s'intégrer dans un système d'extraction de caractéristiques, de sorte que les vecteurs de mots n-grammes sont 1 caractéristique pour former un classificateur sur. Je suppose qu'il n'est pas possible d'adapter vos 4 fonctions en 1 grande fonction? – Bambi

+0

Je ne peux pas vous remercier assez. Tout est tellement plus clair maintenant! – Bambi

+0

J'ai un autre problème. J'essaie de faire un test unitaire pour – Bambi