Con el actual CoreNLPParser.tag()
, la "retokenización" de Stanford CoreNLP es inesperada:
>>> from nltk.parse.corenlp import CoreNLPParser
>>> ner_tagger = CoreNLPParser(url='http://localhost:9000', tagtype='ner')
>>> sent = ['my', 'phone', 'number', 'is', '1111', '1111', '1111']
>>> ner_tagger.tag(sent)
[('my', 'O'),
('phone', 'O'),
('number', 'O'),
('is', 'O'),
('1111\xa01111\xa01111', 'NUMBER')]
El comportamiento esperado debería ser:
>>> from nltk.parse.corenlp import CoreNLPParser
>>> ner_tagger = CoreNLPParser(url='http://localhost:9000', tagtype='ner')
>>> sent = ['my', 'phone', 'number', 'is', '1111', '1111', '1111']
>>> ner_tagger.tag(sent)
[('my', 'O'), ('phone', 'O'), ('number', 'O'), ('is', 'O'), ('1111', 'DATE'), ('1111', 'DATE'), ('1111', 'DATE')]
La solución propuesta es permitir la sobrecarga de argumentos de properties
para .tag()
y .tag_sents()
, es decir, en https://github.com/nltk/nltk/blob/develop/nltk/parse/ corenlp.py # L348 y por defecto usamos properties = {'tokenize.whitespace':'true'}
porque estamos concatenando los tokens por espacios en tag_sents()
.
def tag_sents(self, sentences, properties=None):
"""
Tag multiple sentences.
Takes multiple sentences as a list where each sentence is a list of
tokens.
:param sentences: Input sentences to tag
:type sentences: list(list(str))
:rtype: list(list(tuple(str, str))
"""
# Converting list(list(str)) -> list(str)
sentences = (' '.join(words) for words in sentences)
if properties == None:
properties = {'tokenize.whitespace':'true'}
return [sentences[0] for sentences in self.raw_tag_sents(sentences, properties)]
def tag(self, sentence, properties=None):
"""
Tag a list of tokens.
:rtype: list(tuple(str, str))
>>> parser = CoreNLPParser(url='http://localhost:9000', tagtype='ner')
>>> tokens = 'Rami Eid is studying at Stony Brook University in NY'.split()
>>> parser.tag(tokens)
[('Rami', 'PERSON'), ('Eid', 'PERSON'), ('is', 'O'), ('studying', 'O'), ('at', 'O'), ('Stony', 'ORGANIZATION'),
('Brook', 'ORGANIZATION'), ('University', 'ORGANIZATION'), ('in', 'O'), ('NY', 'O')]
>>> parser = CoreNLPParser(url='http://localhost:9000', tagtype='pos')
>>> tokens = "What is the airspeed of an unladen swallow ?".split()
>>> parser.tag(tokens)
[('What', 'WP'), ('is', 'VBZ'), ('the', 'DT'),
('airspeed', 'NN'), ('of', 'IN'), ('an', 'DT'),
('unladen', 'JJ'), ('swallow', 'VB'), ('?', '.')]
"""
return self.tag_sents([sentence], properties)[0]
def raw_tag_sents(self, sentences, properties=None):
"""
Tag multiple sentences.
Takes multiple sentences as a list where each sentence is a string.
:param sentences: Input sentences to tag
:type sentences: list(str)
:rtype: list(list(list(tuple(str, str)))
"""
default_properties = {'ssplit.isOneSentence': 'true',
'annotators': 'tokenize,ssplit,' }
default_properties.update(properties or {})
# Supports only 'pos' or 'ner' tags.
assert self.tagtype in ['pos', 'ner']
default_properties['annotators'] += self.tagtype
for sentence in sentences:
tagged_data = self.api_call(sentence, properties=default_properties)
yield [[(token['word'], token[self.tagtype]) for token in tagged_sentence['tokens']]
for tagged_sentence in tagged_data['sentences']]
Eso debería hacer cumplir la lista de tokens de cadena introducidos por los usuarios.
Si permitimos que .tag()
sobrecarguen las propiedades antes que raw_tag_sents
, eso también permitirá a los usuarios manejar fácilmente casos como # 1876
Se ve bien.
Solo algunos comentarios menores. Debe ser if properties is None
, no if properties == None
. assert self.tagtype in ['pos', 'ner']
debe ser assert self.tagtype in ['pos', 'ner'], "CoreNLP tagger supports only 'pos' or 'ner' tags."
.
Realmente no me gusta la idea de unir y dividir cadenas, tal vez podría haber una forma de pasar una lista de palabras a CoreNLP como una oración en lugar de una simple cadena.
Hola, me gustaría abordar este tema como mi primer número.
Es genial que esté interesado en el tema. Si tiene alguna pregunta, hágala aquí.
Comentario más útil
Se ve bien.
Solo algunos comentarios menores. Debe ser
if properties is None
, noif properties == None
.assert self.tagtype in ['pos', 'ner']
debe serassert self.tagtype in ['pos', 'ner'], "CoreNLP tagger supports only 'pos' or 'ner' tags."
.Realmente no me gusta la idea de unir y dividir cadenas, tal vez podría haber una forma de pasar una lista de palabras a CoreNLP como una oración en lugar de una simple cadena.