Comenzando con spaCy para procesamiento de lenguaje natural
spaCy es una biblioteca de procesamiento de lenguaje natural Python diseñada específicamente con el objetivo de ser una biblioteca útil para implementar sistemas listos para producción. Es particularmente rápido e intuitivo, por lo que es un competidor superior para las tareas de procesamiento de lenguaje natural (PLN).
En una serie de publicaciones anteriores, hemos analizado algunas ideas generales relacionadas con las tareas de la ciencia de datos textuales, ya sea el procesamiento del lenguaje natural, la minería de textos o algo diferente pero estrechamente relacionado. En la más reciente de estas publicaciones , cubrimos un tutorial de preprocesamiento de datos de texto usando Python. Más específicamente, miramos un tutorial de preprocesamiento de texto usando Python y NLTK . Si bien no fuimos más allá del preprocesamiento de datos con NLTK, el kit de herramientas podría, teóricamente, ser utilizado para otras tareas de análisis.
Si bien NLTK es un gran lenguaje natural … bueno, el juego de herramientas (de ahí el nombre), no está optimizado para la construcción de sistemas de producción. Esto puede o no tener consecuencias si usa NLTK solo para preprocesar sus datos, pero si está planificando una solución PLN de extremo a extremo y está seleccionando una herramienta apropiada para construir dicho sistema, puede tener sentido preprocesar sus datos con lo mismo.
Si bien NLTK se creó teniendo en cuenta el aprendizaje de PLN, spaCy se diseñó específicamente con el objetivo de ser una biblioteca útil para implementar sistemas listos para producción.
spaCy está diseñado para ayudarlo a realizar un trabajo real: para crear productos reales o recopilar información real. La biblioteca respeta su tiempo y trata de evitar desperdiciarlo. Es fácil de instalar y su API es simple y productiva. Nos gusta pensar en spaCy como el Ruby on Rails del procesamiento del lenguaje natural.
spaCy es obstinado, ya que no permite mezclar y combinar lo que podría considerarse módulos de tuberías (pipelines) PLN, y el argumento es que los lemmatizadores particulares, por ejemplo, no están optimizados para funcionar bien con tokenizadores particulares. Si bien la compensación es menor flexibilidad en algunos aspectos de su canalización PLN, el resultado debería ser un mayor rendimiento.
Puede obtener una descripción general de SpaCy y algunas de sus filosofías de diseño y opciones en este video , una charla impartida por los desarrolladores de spa Matthew Matthew y Ines Montani , de una reunión de SF Machine Learning coorganizada por el Data Institute de USF.
spaCy se anuncia a sí mismo como “la mejor manera de preparar el texto para el aprendizaje profundo”. Como gran parte del tutorial anterior no usó NLTK (la eliminación del ruido dependiente de la tarea, así como algunos pasos en el proceso de normalización), no repetiremos todo el post aquí usando spaCy en lugar de NLTK en lugares específicos, ya que sería una pérdida de tiempo para todos. En su lugar, investigaremos cómo se podría lograr con SpaCy parte de la misma funcionalidad con la que trabajamos NLTK, y luego pasaremos a algunas tareas adicionales que podrían considerarse preprocesamiento, dependiendo de su objetivo final, pero que también pueden sangrar en los pasos subsiguientes de tareas de ciencia de datos textuales .
Empezando
Antes de hacer nada, debe tener SpaCy instalado, así como su modelo de idioma inglés.
$ pip3 install spacy
$ python3 -m spacy download en
Necesitamos una muestra de texto para usar:
sample = u"I can't imagine spending $3000 for a single bedroom apartment in N.Y.C."
Ahora importemos spaCy, junto con displaCy (para visualizar algunos de los modelos de spaCy) y una lista de palabras de finalización en inglés (las usaremos a continuación). También cargamos el modelo de idioma inglés como un Language
objeto (lo llamaremos 'nlp' fuera de la convención spaCy), y luego llamamos al objeto nlp en nuestro texto de muestra, que devuelve un Doc
objeto procesado (que inteligentemente llamamos 'doc').
import spacy
from spacy import displacy
from spacy.lang.en.stop_words import STOP_WORDSnlp = spacy.load('en')
doc = nlp(sample)
Y ahí lo tienes. De la documentación de spaCy :
A pesar de que a
Doc
se procesa, por ejemplo, se divide en palabras individuales y se anota, todavía contiene toda la información del texto original , como los caracteres en blanco. Siempre puede obtener el desplazamiento de un token en la cadena original, o reconstruir el original uniendo los tokens y sus espacios en blanco al final. De esta forma, nunca perderá ninguna información al procesar texto con spaCy.
Esto es esencial para la filosofía de diseño de spaCy; Te animo a mirar este video .
Ahora probemos algunas cosas. Tenga en cuenta qué tan poco código se requiere para realizar dichas cosas.
Tokenización
Imprimir tokens de nuestra muestra es sencillo:
# Print out tokens
for token in doc:
print(token)I
ca
n't
imagine
spending
$
3000
for
a
single
bedroom
apartment
in
N.Y.C.
Recuerde desde arriba que un Doc
objeto se procesa a medida que se pasa al Language
objeto, y así la tokenización ya se ha completado en este punto; solo estamos accediendo a los tokens existentes. De la documentación :
Un Doc es una secuencia de
Token
objetos. Acceda a oraciones y entidades con nombre, exporte anotaciones a matrices numpy, serialice sin pérdidas a cadenas binarias comprimidas. ElDoc
objeto contiene una matriz deTokenC
estructuras. El nivel de PythonToken
y losSpan
objetos son vistas de esta matriz, es decir, no son propietarios de los datos.
No discutimos los detalles de la implementación de spaCy, pero al conocer cómo es su código subyacente, específicamente cómo se escribió (y por qué), se obtiene la información necesaria para comprender por qué es tan rápido. Por tercera vez, te animo a mirar este video .
Aunque no es necesario, dadas las diferencias de diseño, si desea extraer estos tokens en una lista propia (similar a como lo hicimos en el tutorial NLTK):
# Store tokens as list, print out
tokens = [token for token in doc]
print(tokens)[I, ca, n't, imagine, spending, $, 3000, for, a, single, bedroom, apartment, in, N.Y.C.]
Identificando las StopWords (palabras muy comunes en el lenguaje sin significado importante)
Identifiquemos las StopWords. Importamos la lista de palabras anterior, por lo que solo se trata de iterar a través de los tokens almacenados en el Doc
objeto y realizar una comparación:
for word in doc:
if word.is_stop == True:
print(word)ca
for
a
in
Tenga en cuenta que no tocamos la lista de tokens creada anteriormente, y solo confiamos en el Doc
objeto preprocesado .
Etiquetado de parte de la voz
Un Doc
objeto contiene Token
objetos, y puede leer la Token
documentación para obtener una idea de qué datos posee cada ficha antes de que la solicitemos, y para obtener información específica sobre lo que se muestra a continuación.
for token in doc:
print(token.text, token.lemma_, token.pos_, token.tag_, token.dep_,
token.shape_, token.is_alpha, token.is_stop)I -PRON- PRON PRP nsubj X True False
ca can VERB MD aux xx True True
n't not ADV RB neg x'x False False
imagine imagine VERB VB ROOT xxxx True False
spending spend VERB VBG xcomp xxxx True False
$ $ SYM $ nmod $ False False
3000 3000 NUM CD dobj dddd False False
for for ADP IN prep xxx True True
a a DET DT det x True True
single single ADJ JJ amod xxxx True False
bedroom bedroom NOUN NN compound xxxx True False
apartment apartment NOUN NN pobj xxxx True False
in in ADP IN prep xx True True
N.Y.C. n.y.c. PROPN NNP pobj X.X.X. False False
Si bien esta es una gran cantidad de información tal como está, y podría ser útil en todo tipo de formas para un objetivo PLN determinado, visualicemos simplemente usando displaCy para obtener una vista más concisa:
displacy.render(doc, style='dep', jupyter=True, options={'distance': 70})
Reconocimiento de entidad con nombre
Un Doc
objeto ya ha procesado entidades con nombre también. Acceda a ellos con:
# Print out named entities
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
Como puede determinarse a partir del código anterior, primero se genera la entidad nombrada, seguido de su índice de caracteres inicial en el documento, luego su índice de carácter final y finalmente su tipo de entidad (etiqueta).
La visualización de displaCy es útil de nuevo, aquí:
displacy.render(doc, style='ent', jupyter=True)
Reitero: recorra esta publicación y observe qué tan poco código se requería para llevar a cabo las tareas que llevamos a cabo.
Esto solo araña la superficie de lo que queremos lograr con PLN o una herramienta tan poderosa como SpaCy. Como debería ser obvio, las tareas de preprocesamiento de PLN, así como las de otras formas de datos (junto con la manipulación de texto y cadena), a menudo se pueden lograr con una variedad de estrategias, herramientas y bibliotecas. En mi opinión, spaCy sobresale debido a su facilidad de uso y simplicidad API. Animo a todas las personas que han estado siguiendo estos mensajes relacionados con la PLN que he estado escribiendo a que consulten SpaCy si se toman en serio el procesamiento del lenguaje natural.
Para obtener más información sobre spaCy, recomiendo estos recursos:
- spaCy 101: Everything you need to know
- Language Processing Pipelines
- Increasing data science productivity; founders of spaCy & Prodigy (SF Machine Learning meetup talk)
- Matthew Honnibal — Designing spaCy: Industrial-strength NLP (PyData Berlin 2016 talk)
Originalmente publicado en inglés en KDnuggets.