web-dev-qa-db-fra.com

lemmatisation wordnet et balisage pos en python

Je voulais utiliser le lemmatiseur wordnet dans python et j'ai appris que la balise pos par défaut est NOUN et qu'elle ne produit pas le lemme correct pour un verbe, sauf si la balise pos est explicitement spécifiée comme VERBE .

Ma question est quelle est la meilleure prise de vue pour effectuer la lemmatisation ci-dessus avec précision?

J'ai fait le balisage pos en utilisant nltk.pos_tag Et je suis perdu dans l'intégration des balises pos de la banque d'arbres aux balises pos compatibles avec wordnet. Veuillez aider

from nltk.stem.wordnet import WordNetLemmatizer
lmtzr = WordNetLemmatizer()
tagged = nltk.pos_tag(tokens)

J'obtiens les balises de sortie en NN, JJ, VB, RB. Comment les remplacer par des balises compatibles wordnet?

Dois-je également former nltk.pos_tag() avec un corpus balisé ou puis-je l'utiliser directement sur mes données pour évaluer?

50
user1946217

Tout d'abord, vous pouvez utiliser nltk.pos_tag() directement sans l'entraîner. La fonction chargera un tagueur pré-formé à partir d'un fichier. Vous pouvez voir le nom du fichier avec nltk.tag._POS_TAGGER:

nltk.tag._POS_TAGGER
>>> 'taggers/maxent_treebank_pos_tagger/english.pickle' 

Comme il a été formé avec le corpus Treebank, il utilise également le jeu de balises Treebank .

La fonction suivante mapperait les balises treebank à la partie WordNet des noms de discours:

from nltk.corpus import wordnet

def get_wordnet_pos(treebank_tag):

    if treebank_tag.startswith('J'):
        return wordnet.ADJ
    Elif treebank_tag.startswith('V'):
        return wordnet.VERB
    Elif treebank_tag.startswith('N'):
        return wordnet.NOUN
    Elif treebank_tag.startswith('R'):
        return wordnet.ADV
    else:
        return ''

Vous pouvez ensuite utiliser la valeur de retour avec le lemmatiseur:

from nltk.stem.wordnet import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize('going', wordnet.VERB)
>>> 'go'

Vérifiez la valeur de retour avant de la transmettre au Lemmatizer car une chaîne vide donnerait un KeyError.

69
Suzana

Comme dans le code source de nltk.corpus.reader.wordnet ( http://www.nltk.org/_modules/nltk/corpus/reader/wordnet.html )

#{ Part-of-speech constants
 ADJ, ADJ_SAT, ADV, NOUN, VERB = 'a', 's', 'r', 'n', 'v'
#}
POS_LIST = [NOUN, VERB, ADJ, ADV]
10
pg2455

Étapes pour convertir: Document-> Phrases-> Tokens-> POS-> Lemmas

import nltk
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet

#example text text = 'What can I say about this place. The staff of these restaurants is Nice and the eggplant is not bad'

class Splitter(object):
    """
    split the document into sentences and tokenize each sentence
    """
    def __init__(self):
        self.splitter = nltk.data.load('tokenizers/punkt/english.pickle')
        self.tokenizer = nltk.tokenize.TreebankWordTokenizer()

    def split(self,text):
        """
        out : ['What', 'can', 'I', 'say', 'about', 'this', 'place', '.']
        """
        # split into single sentence
        sentences = self.splitter.tokenize(text)
        # tokenization in each sentences
        tokens = [self.tokenizer.tokenize(sent) for sent in sentences]
        return tokens


class LemmatizationWithPOSTagger(object):
    def __init__(self):
        pass
    def get_wordnet_pos(self,treebank_tag):
        """
        return WORDNET POS compliance to WORDENT lemmatization (a,n,r,v) 
        """
        if treebank_tag.startswith('J'):
            return wordnet.ADJ
        Elif treebank_tag.startswith('V'):
            return wordnet.VERB
        Elif treebank_tag.startswith('N'):
            return wordnet.NOUN
        Elif treebank_tag.startswith('R'):
            return wordnet.ADV
        else:
            # As default pos in lemmatization is Noun
            return wordnet.NOUN

    def pos_tag(self,tokens):
        # find the pos tagginf for each tokens [('What', 'WP'), ('can', 'MD'), ('I', 'PRP') ....
        pos_tokens = [nltk.pos_tag(token) for token in tokens]

        # lemmatization using pos tagg   
        # convert into feature set of [('What', 'What', ['WP']), ('can', 'can', ['MD']), ... ie [original Word, Lemmatized Word, POS tag]
        pos_tokens = [ [(Word, lemmatizer.lemmatize(Word,self.get_wordnet_pos(pos_tag)), [pos_tag]) for (Word,pos_tag) in pos] for pos in pos_tokens]
        return pos_tokens

lemmatizer = WordNetLemmatizer()
splitter = Splitter()
lemmatization_using_pos_tagger = LemmatizationWithPOSTagger()

#step 1 split document into sentence followed by tokenization
tokens = splitter.split(text)

#step 2 lemmatization using pos tagger 
lemma_pos_token = lemmatization_using_pos_tagger.pos_tag(tokens)
print(lemma_pos_token)
8
Deepak

Vous pouvez créer une carte en utilisant le dict par défaut python et profiter du fait que pour le lemmatiseur la balise par défaut est Noun.

from nltk.corpus import wordnet as wn
from nltk.stem.wordnet import WordNetLemmatizer
from nltk import Word_tokenize, pos_tag
from collections import defaultdict

tag_map = defaultdict(lambda : wn.NOUN)
tag_map['J'] = wn.ADJ
tag_map['V'] = wn.VERB
tag_map['R'] = wn.ADV

text = "Another way of achieving this task"
tokens = Word_tokenize(text)
lmtzr = WordNetLemmatizer()

for token, tag in pos_tag(tokens):
    lemma = lmtzr.lemmatize(token, tag_map[tag[0]])
    print(token, "=>", lemma)
7
Shuchita Banthia

@Suzana_K fonctionnait. Mais il y a des résultats de cas dans KeyError comme le mentionne @ Clock Slave.

Convertir les balises treebank en balise Wordnet

from nltk.corpus import wordnet

def get_wordnet_pos(treebank_tag):

    if treebank_tag.startswith('J'):
        return wordnet.ADJ
    Elif treebank_tag.startswith('V'):
        return wordnet.VERB
    Elif treebank_tag.startswith('N'):
        return wordnet.NOUN
    Elif treebank_tag.startswith('R'):
        return wordnet.ADV
    else:
        return None # for easy if-statement 

Maintenant, nous ne saisissons pos dans la fonction lemmatize que si nous avons une balise wordnet

from nltk.stem.wordnet import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
tagged = nltk.pos_tag(tokens)
for Word, tag in tagged:
    wntag = get_wordnet_pos(tag)
    if wntag is None:# not supply tag in case of None
        lemma = lemmatizer.lemmatize(Word) 
    else:
        lemma = lemmatizer.lemmatize(Word, pos=wntag) 
2
Haha TTpro

Vous pouvez le faire sur une seule ligne:

wnpos = lambda e: ('a' if e[0].lower() == 'j' else e[0].lower()) if e[0].lower() in ['n', 'r', 'v'] else 'n'

Ensuite, utilisez wnpos(nltk_pos) pour obtenir le POS à donner à .lemmatize (). Dans votre cas, lmtzr.lemmatize(Word=tagged[0][0], pos=wnpos(tagged[0][1])).

0
wordsforthewise