Editado por: Luis Fernando Apáez Álvarez
Named Entity recognition o NER, es una tarea del procesamiento del lenguaje natural que se utiliza para identificar entidades nombradas en el texto, como personar, lugares, organizaciones, fechas, estados, obras de arte, entre muchas otras entidades más, dependiendo de la librería que sea utilizada. NER se puede utilizar junto con la identificación de temas, o por sí solo para determinar elementos importantes dentro de un texto. Gracias a ello podemos preguntarnos:
Para el siguiente ejemplo se utilizará el NER de Stanford, el cual requiere descargas adicionales (Link). Para ello
# Importaciones necesarias
import nltk
from nltk.tag.stanford import StanfordNERTagger
# Inicializamos el etiquetador:
# Requerimos especificar las direcciones
d1='C:/Users/usuario/Downloads/stanford-ner-2020-11-17/stanford-ner.jar'
d2='C:/Users/usuario/Downloads/stanford-ner-2020-11-17/classifiers/english.all.3class.distsim.crf.ser.gz'
PATH_TO_JAR = d1
PATH_TO_MODEL = d2
tagger = StanfordNERTagger(model_filename=PATH_TO_MODEL,
path_to_jar=PATH_TO_JAR,
encoding='utf-8')
sentence = """First up in London will be Riccardo Tisci, onetime Givenchy darling,
favorite of Kardashian-Jenners everywhere, who returns to the catwalk with men’s
and women’s wear after a year and a half away, this time to reimagine Burberry
after the departure of Christopher Bailey."""
# Tokenizamos el texto
words = nltk.word_tokenize(sentence)
# Luego, colocamos las palabras tokenizadas dentro del etiquetador
tagged = tagger.tag(words)
tagged
[('First', 'O'), ('up', 'O'), ('in', 'O'), ('London', 'LOCATION'), ('will', 'O'), ('be', 'O'), ('Riccardo', 'PERSON'), ('Tisci', 'PERSON'), (',', 'O'), ('onetime', 'O'), ('Givenchy', 'ORGANIZATION'), ('darling', 'O'), (',', 'O'), ('favorite', 'O'), ('of', 'O'), ('Kardashian-Jenners', 'O'), ('everywhere', 'O'), (',', 'O'), ('who', 'O'), ('returns', 'O'), ('to', 'O'), ('the', 'O'), ('catwalk', 'O'), ('with', 'O'), ('men', 'O'), ('’', 'O'), ('s', 'O'), ('and', 'O'), ('women', 'O'), ('’', 'O'), ('s', 'O'), ('wear', 'O'), ('after', 'O'), ('a', 'O'), ('year', 'O'), ('and', 'O'), ('a', 'O'), ('half', 'O'), ('away', 'O'), (',', 'O'), ('this', 'O'), ('time', 'O'), ('to', 'O'), ('reimagine', 'O'), ('Burberry', 'O'), ('after', 'O'), ('the', 'O'), ('departure', 'O'), ('of', 'O'), ('Christopher', 'PERSON'), ('Bailey', 'PERSON'), ('.', 'O')]
donde la etiqueta O
es solo una etiqueta de fondo para palabras que no se ajustaban a ninguna de las etiquetas de categoría de entidad nombrada. Notamos que el resultado anterior es bueno con una presición decente. Por ejemplo, para Bailey
se identifico como una persona, a Givenchy
como una organización, etcétera. Veamos otro ejemplo pero ahora accederemos a información de Albert Einsein obtenida de la Wikipedia:
# Importacion necesaria
import wikipedia
# Lenguaje es espaniol
wikipedia.set_lang('en')
# Busqueda de un articulo de 10 frases
result = wikipedia.summary('Albert Einstein', sentences=10)
# Tokenizamos el texto
words = nltk.word_tokenize(result)
# Luego, colocamos las palabras tokenizadas dentro del etiquetador
tagged = tagger.tag(words)
# Veamos lo que se ha logrado etiquetar
for i in range(len(tagged)):
if tagged[i][1] != 'O':
print(tagged[i])
('Albert', 'PERSON') ('Einstein', 'PERSON') ('Einstein', 'PERSON') ('Einstein', 'PERSON') ('Einstein', 'PERSON') ('Einstein', 'PERSON')
Lo cual solo nos sirve para ver que ha aparecido el nombre de Albert Eistein en el artículo de Wikipedia.
Para ver cambios en el etiquetador a algo un poco más elaborado, cambiaremos de modelo:
# Inicializamos el etiquetador:
# Requerimos especificar las direcciones
d1='C:/Users/usuario/Downloads/stanford-ner-2020-11-17/stanford-ner.jar'
# Cambiamos de direccion para cambiar de modelo
d2='C:/Users/usuario/Downloads/stanford-ner-2020-11-17/classifiers/english.conll.4class.distsim.crf.ser.gz'
PATH_TO_JAR = d1
PATH_TO_MODEL = d2
tagger = StanfordNERTagger(model_filename=PATH_TO_MODEL,
path_to_jar=PATH_TO_JAR,
encoding='utf-8')
# Busqueda de un articulo de 10 frases
result = wikipedia.summary('Albert Einstein', sentences=10)
# Tokenizamos el texto
words = nltk.word_tokenize(result)
# Luego, colocamos las palabras tokenizadas dentro del etiquetador
tagged = tagger.tag(words)
# Veamos lo que se ha logrado etiquetar
for i in range(len(tagged)):
if tagged[i][1] != 'O':
print(tagged[i])
('Albert', 'PERSON') ('Einstein', 'PERSON') ('German', 'MISC') ('German-born', 'MISC') ('Einstein', 'LOCATION') ('Nobel', 'MISC') ('Prize', 'MISC') ('Einstein', 'LOCATION') ('Einstein', 'PERSON') ('Brownian', 'MISC') ('Einstein', 'LOCATION')
lo cual nos arroja un reconocimiento de entidad más rico, donde no sólo vemos el reconocimiento de personas.
La librería NLTK tiene integrado su propio NER, veamos un ejemplo:
import nltk
# Descarga necesaria
nltk.download('averaged_perceptron_tagger')
# Texto
sentence = """First up in London will be Riccardo Tisci, onetime Givenchy darling,
favorite of Kardashian-Jenners everywhere, who returns to the catwalk with men’s
and women’s wear after a year and a half away, this time to reimagine Burberry
after the departure of Christopher Bailey."""
# Tokenizamos el texto
words = nltk.word_tokenize(sentence)
# Etiquetador
tagged = nltk.pos_tag(words)
tagged
[nltk_data] Downloading package averaged_perceptron_tagger to [nltk_data] C:\Users\usuario\AppData\Roaming\nltk_data... [nltk_data] Package averaged_perceptron_tagger is already up-to- [nltk_data] date!
[('First', 'NNP'), ('up', 'RP'), ('in', 'IN'), ('London', 'NNP'), ('will', 'MD'), ('be', 'VB'), ('Riccardo', 'NNP'), ('Tisci', 'NNP'), (',', ','), ('onetime', 'RB'), ('Givenchy', 'NNP'), ('darling', 'NN'), (',', ','), ('favorite', 'NN'), ('of', 'IN'), ('Kardashian-Jenners', 'NNP'), ('everywhere', 'RB'), (',', ','), ('who', 'WP'), ('returns', 'VBZ'), ('to', 'TO'), ('the', 'DT'), ('catwalk', 'NN'), ('with', 'IN'), ('men', 'NNS'), ('’', 'VBP'), ('s', 'NN'), ('and', 'CC'), ('women', 'NNS'), ('’', 'VBP'), ('s', 'JJ'), ('wear', 'NN'), ('after', 'IN'), ('a', 'DT'), ('year', 'NN'), ('and', 'CC'), ('a', 'DT'), ('half', 'NN'), ('away', 'RB'), (',', ','), ('this', 'DT'), ('time', 'NN'), ('to', 'TO'), ('reimagine', 'VB'), ('Burberry', 'NNP'), ('after', 'IN'), ('the', 'DT'), ('departure', 'NN'), ('of', 'IN'), ('Christopher', 'NNP'), ('Bailey', 'NNP'), ('.', '.')]
donde
Entre otras etiqeutas más.
Después, mediante ne_chunk()
obtendremos el texto como un árbol:
nltk.download('maxent_ne_chunker')
nltk.download('words')
print(nltk.ne_chunk(tagged))
(S First/NNP up/RP in/IN (GPE London/NNP) will/MD be/VB (PERSON Riccardo/NNP Tisci/NNP) ,/, onetime/RB (GPE Givenchy/NNP) darling/NN ,/, favorite/NN of/IN Kardashian-Jenners/NNP everywhere/RB ,/, who/WP returns/VBZ to/TO the/DT catwalk/NN with/IN men/NNS ’/VBP s/NN and/CC women/NNS ’/VBP s/JJ wear/NN after/IN a/DT year/NN and/CC a/DT half/NN away/RB ,/, this/DT time/NN to/TO reimagine/VB (PERSON Burberry/NNP) after/IN the/DT departure/NN of/IN (PERSON Christopher/NNP Bailey/NNP) ./.)
[nltk_data] Downloading package maxent_ne_chunker to [nltk_data] C:\Users\usuario\AppData\Roaming\nltk_data... [nltk_data] Package maxent_ne_chunker is already up-to-date! [nltk_data] Downloading package words to [nltk_data] C:\Users\usuario\AppData\Roaming\nltk_data... [nltk_data] Package words is already up-to-date!
donde estos árboles de nltk son diferentes a los árboles respecto de otras librerías, no obstante, el árbol obtenido tiene hojas y subárboles que representan una gramática más compleja. Dicho árbol muestra las entidadas nombradas etiquetadas como sus propios fragmentos, tales como PERSON Christopher/NNP
.