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?
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
.
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]
É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)
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)
@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)
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]))
.