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.
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:
# 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
.
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
:
doc.ents
(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:
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.
nltk
.El texto que se ocupará:
# 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
# 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
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
:
tokens = [token for token in doc]
tokens
[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
:
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:
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
:
displacy.render(doc, style='dep', jupyter=True, options={'distance': 100})
Por otro lado, doc
ya está procesado para el reconocimiento de entidades como vimos al inicio. Para ello
doc.ents
(3000, N.Y.C.)
# 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:
displacy.render(doc, style='ent', jupyter=True)
Notemos que hasta ahora, para als tareas que hemos llevado a cabo, el código empleado es muy poco.
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
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:
# 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.
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:
# Por ejemplo
pipeline = ["tok2vec", "tagger", "parser", "ner"]