Procesamiento de lenguaje natural¶



Autor: Luis Fernando Apáez Álvarez



  • Introducción
  • Ejemplo de uso
    • Vectorización
    • Tuberías




Librería SpaCy¶

SpaCy es otra librería con la cual podemos trabajar para el procesamiento del lenguaje natural muy similar a Gensim pero con diferentes implementaciones. En esta librería se incluyen pipelines de NLP para generar modelos y corpus. Además, ésta incluye un herramienta denominada Displacy para la visualización de árboles de análisis.

Spacy tiene tambíen herramientas para crear vectores de palabras y documentos a partir de un texto. Para comenzar a utilizarlo descargamos la librería y la importamos, donde podremos tener vectores de palabras pre-entrenados apropiados, o bien realizar manualmente el entrenamiento de los vectores y después cargarlos.

Introducción ¶

Dado el modelo 'en_core_web_sm' que utilizaremos, será necesario escribir en consola python -m spacy download en_core_web_sm para descargarlo. Una vez descargado escribimos:

In [3]:
# Importacion necesaria
import spacy

# Realizamos la carga que funge de manera similar al
# diccionario y corpus Gensim
nlp = spacy.load('en_core_web_sm')

El modelo cargado en nlp tiene varios objetos. Por ejemplo tiene un objeto entidad el cual es un reconocedor de entidades lo cual nos ayudará a identificar entidades en el texto. Lo que sigue es cargar un documento nuevo pasándolo en la variable nlp.

In [5]:
doc = nlp("""Berlin is the capital of Germany;
                and the residence of Chancellor Angela Merkel.""")

Una vez que se carga el documento, las entidades nombradas se almacenan como un atributo, del documento, llamado ents:

In [6]:
doc.ents
Out[6]:
(Berlin, Germany, Angela Merkel)

donde SpaCy ha etiquetado de manera correcta las tres entidades principales de la oración. Podemos también investigar las etiquetas asociadas a las entidades:

In [13]:
for i in range(3):
    print(doc.ents[i], ':', doc.ents[i].label_, end='\n')
Berlin : GPE
Germany : GPE
Angela Merkel : PERSON

donde GPE hace alusión a una entidad geopolítica. Cabe mencionar que SpaCy tiene muchos más modelos, incluidos modelos avanzados en alemán y chino. Además, es una herramienta poderosa para la extracción y el NLP de forma rápida e iterativa.

Algunas consideraciones¶

  • SpaCy Tiene un conjunto diferente de tipos de entidad.
  • Etiqueda, a menudo, de manera diferente a nltk.
  • Viene con un corpus de lenguaje informal, lo cual permite encontrar de manera más sencilla entidades en documentos como tweets y mensajes de chat.
  • Es una librería en rápida crecimiento y uso.
  • Está diseñada para la planificación de soluciones NLP de extremo a extremo.
  • Se diseño para implementar sistemas listos para su producción
  • Spacy se anuncia a sí misma como "la mejor manera de preparar el texto para el aprendizaje profundo"

Ejemplo de uso ¶

El texto que se ocupará:

In [18]:
# Texto
text = u"I can't imagine spending $3000 for a single bedroom apartment in N.Y.C."

# Cargamos el documento nuevo pasandolo en la variable nlp
doc = nlp(text)

Realizamos algunas importaciones que ocuparemos

In [19]:
# Visualizacion de algunos modelos de SpaCy
from spacy import displacy
# Palabras vacias
from spacy.lang.es.stop_words import STOP_WORDS

Nuestro texto ya ha sido preprocesado desde el momento que escribimos nlp(text), de donde la tokenización ya ha sido realizada. Veamos cada uno de los tokens de nuestro documento

In [20]:
for token in doc:
    print(token)
I
ca
n't
imagine
spending
$
3000
for
a
single
bedroom
apartment
in
N.Y.C.

Tenemos entonces que, el documento doc es una secuencia de tokens. Podemos tener una salida familiar de los tokens como si utilizaramos nltk:

In [21]:
tokens = [token for token in doc]
tokens
Out[21]:
[I,
 ca,
 n't,
 imagine,
 spending,
 $,
 3000,
 for,
 a,
 single,
 bedroom,
 apartment,
 in,
 N.Y.C.]

Por otro lado, podemos identificar las stopwords utilizando el atributo is_stop:

In [22]:
for word in doc:
    if word.is_stop == True:
        print(word)
I
ca
n't
for
a
in

las cuales son las palabras vacías identificadas. Resaltemos, de nuevo, que todo lo que hemos estado haciendo es acceder a información del documento doc el cual preprocesamos mediante nlp(text).

Podemos acceder a distinta información de los tokens:

In [24]:
for token in doc:
    print(token.text, token.lemma_, token.pos_, token.tag_, token.dep_, token.shape_, token.is_stop)
I I PRON PRP nsubj X True
ca can AUX MD aux xx True
n't not PART RB neg x'x True
imagine imagine VERB VB ROOT xxxx False
spending spend VERB VBG xcomp xxxx False
$ $ SYM $ nmod $ False
3000 3000 NUM CD dobj dddd False
for for ADP IN prep xxx True
a a DET DT det x True
single single ADJ JJ amod xxxx False
bedroom bedroom NOUN NN compound xxxx False
apartment apartment NOUN NN pobj xxxx False
in in ADP IN prep xx True
N.Y.C. N.Y.C. PROPN NNP pobj X.X.X. False

Si bien la información anterior es clara, podría ser útil una visualización para obtener una información más concisa mediante displacy:

In [29]:
displacy.render(doc, style='dep', jupyter=True, options={'distance': 100})
I PRON ca AUX n't PART imagine VERB spending VERB $ SYM 3000 NUM for ADP a DET single ADJ bedroom NOUN apartment NOUN in ADP N.Y.C. PROPN nsubj aux neg xcomp nmod dobj prep det amod compound pobj prep pobj

Por otro lado, doc ya está procesado para el reconocimiento de entidades como vimos al inicio. Para ello

In [30]:
doc.ents
Out[30]:
(3000, N.Y.C.)
In [31]:
# Para mayor informacion
for ent in doc.ents:
    print(ent.text, ent.start_char, ent.end_char, ent.label_)
3000 26 30 MONEY
N.Y.C. 65 71 GPE

de donde tenemos: entidad nombrada - índice inicial de caracteres - índice final de caracteres - tipo de entidad (etiqueta). La visualización de displacy es útil de nuevo:

In [32]:
displacy.render(doc, style='ent', jupyter=True)
I can't imagine spending $ 3000 MONEY for a single bedroom apartment in N.Y.C. GPE

Notemos que hasta ahora, para als tareas que hemos llevado a cabo, el código empleado es muy poco.

Vectorización ¶

La similitud se determina comparando vectores de palabras o "encajes de palabras", representaciones de significado multidimensional de una palabra. Los vectores de palabras se pueden generar usando un algoritmo como word2vec. La vectorización también es hecha al momento del procesamiento del texto mediante nlp(text), para ello

In [33]:
for token in tokens:
    #                                     norma del         Fuera del 
    #                                     vector asociado   vocabulario
    print(token.text, token.has_vector, token.vector_norm, token.is_oov)
I True 9.075287 True
ca True 10.381921 True
n't True 12.949737 True
imagine True 8.851482 True
spending True 9.689276 True
$ True 10.311399 True
3000 True 8.525616 True
for True 8.754489 True
a True 8.8193 True
single True 8.373207 True
bedroom True 7.6481376 True
apartment True 6.749393 True
in True 8.934182 True
N.Y.C. True 8.92939 True

SpaCy puede comparar dos objetos y hacer una predicción de cuán similares son. Predecir la similitud es útil para crear sistemas de recomendación o marcar duplicados. Por ejemplo, puede sugerir un contenido de usuario que sea similar al que está viendo actualmente o etiquetar un ticket de soporte como duplicado si es muy similar a uno que ya existe. Para ello escribiremos .similirity, el cual es un método que permite comparar objetos y determinar la similitud. Por supuesto, la similitud siempre es subjetiva: si dos palabras, intervalos o documentos son similares realmente depende de cómo sea mirado. La implementación de similitud de SpaCy generalmente asume una definición de similitud bastante general.

Para ello será necesario utilizar un modelo más robusto python -m spacy download en_core_web_md, después:

In [37]:
# Cargamos el modelo
nlp = spacy.load("en_core_web_md")

# Documentos a comparar
doc1 = nlp("I like salty fries and hamburgers.")
doc2 = nlp("Fast food tastes very good.")

# Calculamos la similitud entre los dos documentos
print(doc1, "<->", doc2, doc1.similarity(doc2))
print()

# Calculamos la similitud entre dos tokens
# Tokens
french_fries = doc1[2:4]
burgers = doc1[5]

print(french_fries, "<->", burgers, french_fries.similarity(burgers))
I like salty fries and hamburgers. <-> Fast food tastes very good. 0.691649353055761

salty fries <-> hamburgers 0.6938489675521851

Calcular puntuaciones de similitud puede ser útil en muchas situaciones, pero también es importante mantener expectativas realistas sobre la información que puede proporcionar. Las palabras se pueden relacionar entre sí de muchas maneras, por lo que una sola puntuación de "similitud" siempre será una combinación de diferentes señales , y los vectores entrenados en diferentes datos pueden producir resultados muy diferentes que pueden no ser útiles para un propósito dado.

Tuberías ¶

Cuando nlp llama a un texto (e.j. nlp(text)), SpaCy primero tokeniza el texto para producir un Doc objeto. Doc luego se procesa en varios pasos diferentes; esto también se conoce como canalización de procesamiento. La canalización utilizada por las canalizaciones entrenadas suele incluir un etiquetador, un lematizador, un analizador y un reconocedor de entidades, como vimos al inicio del primer ejemplo. Cada componente de canalización devuelve el procesado Doc, que luego se pasa al siguiente componente.

Las capacidades de una tubería de procesamiento siempre dependen de los componentes, sus modelos y cómo fueron entrenados. Por ejemplo, una canalización para el reconocimiento de entidades con nombre debe incluir un componente reconocedor de entidades con nombre entrenado con un modelo estadístico y pesos que le permitan hacer predicciones de etiquetas de entidades. Esta es la razón por la que cada tubería especifica sus componentes y sus configuraciones en la configuración:

In [ ]:
# Por ejemplo
pipeline = ["tok2vec", "tagger", "parser", "ner"]

Notas¶

  • Comenzando con spaCy para procesamiento de lenguaje natural

  • SpaCy 101: Todo lo que necesitas saber