Python para NLP: tokenización, derivación y lematización con la biblioteca SpaCy

En el artículo anterior, comenzamos nuestra discusión sobre cómo hacer procesamiento de lenguaje natural con Python. Vimos cómo leer y escribir archivos de texto y PDF. En...

En el Artículo anterior, comenzamos nuestra discusión sobre cómo hacer procesamiento de lenguaje natural con Python. Vimos cómo leer y escribir archivos de texto y PDF. En este artículo, comenzaremos a trabajar con la biblioteca spacey para realizar algunas tareas más básicas de NLP, como [tokenización](https://en.wikipedia.org/wiki/ Lexical_analysis#Tokenization), derivación y lematización.

Introducción a SpaCy

La biblioteca spaCy es una de las bibliotecas NLP más populares junto con NLTK. La diferencia básica entre las dos bibliotecas es el hecho de que NLTK contiene una amplia variedad de algoritmos para resolver un problema, mientras que spaCy contiene solo uno, pero es el mejor algoritmo para resolver un problema.

NLTK se lanzó en 2001, mientras que spaCy es relativamente nuevo y se desarrolló en 2015. En esta serie de artículos sobre PNL, nos ocuparemos principalmente de spaCy, debido a su naturaleza de vanguardia. Sin embargo, también tocaremos NLTK cuando sea más fácil realizar una tarea usando NLTK en lugar de spaCy.

Instalación de spaCy {#instalación de spacy}

Si usa el instalador de pip para instalar sus bibliotecas de Python, vaya a la línea de comando y ejecute la siguiente instrucción:

1
$ pip install -U spacy

De lo contrario, si está utilizando Anaconda, debe ejecutar el siguiente comando en el indicador de Anaconda:

1
$ conda install -c conda-forge spacy

Una vez que descargue e instale spaCy, el siguiente paso es descargar el modelo de idioma. Usaremos el modelo de idioma inglés. El modelo de lenguaje se usa para realizar una variedad de tareas de PNL, que veremos en una sección posterior.

El siguiente comando descarga el modelo de lenguaje:

1
$ python -m spacy download en

Funcionalidad básica

Antes de profundizar en las diferentes funciones de spaCy, veamos brevemente cómo trabajar con él.

Como primer paso, debe importar la biblioteca spacy de la siguiente manera:

1
import spacy

A continuación, necesitamos cargar el modelo de lenguaje spaCy.

1
sp = spacy.load('en_core_web_sm')

En el script anterior, usamos la función load de la biblioteca spacy para cargar el modelo básico en inglés. El modelo se almacena en la variable sp.

Ahora vamos a crear un pequeño documento usando este modelo. Un documento puede ser una oración o un grupo de oraciones y puede tener una longitud ilimitada. El siguiente script crea un documento spaCy simple.

1
sentence = sp(u'Manchester United is looking to sign a forward for $90 million')

SpaCy divide automáticamente su documento en tokens cuando se crea un documento utilizando el modelo.

Un token simplemente se refiere a una parte individual de una oración que tiene algún valor semántico. Veamos qué tokens tenemos en nuestro documento:

1
2
for word in sentence:
    print(word.text)

La salida del script anterior se ve así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Manchester
United
is
looking
to
sign
a
forward
for
$
90
million

Puede ver que tenemos los siguientes tokens en nuestro documento. También podemos ver las partes de la oración de cada uno de estos tokens usando el atributo .pos_ que se muestra a continuación:

1
2
for word in sentence:
    print(word.text,  word.pos_)

Producción:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Manchester PROPN
United PROPN
is VERB
looking VERB
to PART
sign VERB
a DET
forward NOUN
for ADP
$ SYM
90 NUM
million NUM

Puede ver que a cada palabra o símbolo de nuestra oración se le ha asignado una parte del discurso. Por ejemplo, "Manchester" se ha etiquetado como nombre propio, "Looking" se ha etiquetado como verbo, etc.

Finalmente, además de las partes del discurso, también podemos ver las dependencias.

Vamos a crear otro documento:

1
sentence2 = sp(u"Manchester United isn't looking to sign any forward.")

Para el análisis de dependencias, el atributo dep_ se usa como se muestra a continuación:

1
2
for word in sentence2:
    print(word.text,  word.pos_, word.dep_)

La salida se ve así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Manchester PROPN compound
United PROPN nsubj
is VERB aux
n't ADV neg
looking VERB ROOT
to PART aux
sign VERB xcomp
any DET advmod
forward ADV advmod
. PUNCT punct

A partir de la salida, puede ver que spaCy es lo suficientemente inteligente como para encontrar la dependencia entre los tokens, por ejemplo, en la oración teníamos una palabra is'nt. El analizador de dependencia lo ha dividido en dos palabras y especifica que n't es en realidad la negación de la palabra anterior.

Para obtener una comprensión detallada del análisis de dependencias, consulte Este artículo.

Además de imprimir las palabras, también puede imprimir oraciones de un documento.

1
document = sp(u'Hello from wikihtp. The site with the best Python Tutorials. What are you looking for?')

Ahora, podemos iterar a través de cada oración usando el siguiente script:

1
2
for sentence in document.sents:
    print(sentence)

La salida del script se ve así:

1
2
3
Hello from wikihtp.
The site with the best Python Tutorials.
What are you looking for?

También puede verificar si una oración comienza con un token en particular o no. Puede obtener tokens individuales usando un índice y los corchetes, como una matriz:

1
document[4]

En el script anterior, estamos buscando la quinta palabra en el documento. Tenga en cuenta que el índice comienza desde cero y el período cuenta como un token. En la salida deberías ver:

1
The

Ahora, para ver si alguna oración en el documento comienza con The, podemos usar el atributo is_sent_start como se muestra a continuación:

1
document[4].is_sent_start

En la salida, verá Verdadero ya que el token El se usa al comienzo de la segunda oración.

En esta sección, vimos algunas operaciones básicas de la biblioteca spaCy. Profundicemos ahora y veamos tokenización, derivación y lematización en detalle.

Tokenización

Como se explicó anteriormente, la tokenización es el proceso de dividir un documento en palabras, signos de puntuación, dígitos numéricos, etc.

Veamos la tokenización de spaCy en detalle. Cree un nuevo documento usando el siguiente script:

1
2
sentence3 = sp(u'"They\'re leaving U.K. for U.S.A."')
print(sentence3)

Puede ver que la oración contiene comillas al principio y al final. También contiene signos de puntuación en las abreviaturas "U.K" y "U.S.A."

Veamos cómo spaCy tokeniza esta oración.

1
2
for word in sentence3:
    print(word.text)

Producción:

1
2
3
4
5
6
7
8
"
They
're
leaving
U.K.
for
U.S.A.
"

En el resultado, puede ver que spaCy ha tokenizado las comillas dobles iniciales y finales. Sin embargo, es lo suficientemente inteligente como para no tokenizar el punto de puntuación utilizado entre las abreviaturas como U.K. y U.S.A.

Veamos otro ejemplo de tokenización:

1
2
sentence4 = sp(u"Hello, I am non-vegetarian, email me the menu at [correo electrónico protegido]")
print(sentence4)

Aquí, en la oración anterior, tenemos un guión en la palabra "no vegetariano" y en la dirección de correo electrónico. Veamos cómo spaCy tokenizará esto:

1
2
for word in sentence4:
    print(word.text)

Producción:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Hello
,
I
am
non
-
vegetarian
,
email
me
the
menu
at
[correo electrónico protegido]

Es evidente a partir de la salida que spaCy fue capaz de detectar el correo electrónico y no lo tokenizó a pesar de tener un "-". Por otro lado, se tokenizó la palabra "no vegetariano".

Veamos ahora cómo podemos contar las palabras en el documento:

1
len(sentence4)

En la salida, verá 14, que es el número de tokens en la sentence4.

Detección de entidades

Además de tokenizar los documentos a palabras, también puede averiguar si la palabra es una entidad como una empresa, un lugar, un edificio, una moneda, una institución, etc.

Veamos un ejemplo simple de reconocimiento de entidad nombrada:

1
sentence5 = sp(u'Manchester United is looking to sign Harry Kane for $90 million')  

Primero intentemos tokenizarlo:

1
2
for word in sentence5:
    print(word.text)

Producción:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Manchester
United
is
looking
to
sign
Harry
Kane
for
$
90
million

Sabemos que "Manchester United" es una sola palabra, por lo tanto, no debe dividirse en dos palabras. Del mismo modo, "Harry Kane" es el nombre de una persona, y "$90 millones" es el valor de una moneda. Estos tampoco deben tokenizarse.

Aquí es donde entra en juego reconocimiento de entidad nombrada. Para obtener las entidades nombradas de un documento, debe usar el atributo ents. Recuperemos las entidades nombradas de la oración anterior. Ejecute el siguiente script:

1
2
for entity in sentence.ents:
    print(entity.text + ' - ' + entity.label_ + ' - ' + str(spacy.explain(entity.label_)))

En el script anterior, imprimimos el texto de la entidad, la etiqueta de la entidad y el detalle de la entidad. La salida se ve así:

Producción:

1
2
3
Manchester United - ORG - Companies, agencies, institutions, etc.
Harry Kane - PERSON - People, including fictional
$90 million - MONEY - Monetary values, including unit

Puede ver que el reconocedor de entidades nombradas de spaCy ha reconocido con éxito "Manchester United" como organización, "Harry Kane" como persona y "$90 millones" como valor monetario.

Sustantivos de detección {#sustantivos de detección}

Además de detectar entidades con nombre, también se pueden detectar sustantivos. Para ello se utiliza el atributo noun_chunks. Considere la siguiente oración:

1
sentence5 = sp(u'Latest Rumours: Manchester United is looking to sign Harry Kane for $90 million')  

Tratemos de encontrar los sustantivos de esta oración:

1
2
for noun in sentence5.noun_chunks:
    print(noun.text)

Producción:

1
2
3
Latest Rumours
Manchester United
Harry Kane

A partir de la salida, puede ver que un sustantivo también puede ser una entidad nombrada y viceversa.

Derivación

Stemming se refiere a reducir una palabra a su forma raíz. Mientras realiza tareas de procesamiento de lenguaje natural, encontrará varios escenarios en los que encontrará diferentes palabras con la misma raíz. Por ejemplo, computar, computadora, computación, computado, etc. Es posible que desee reducir las palabras a su forma raíz por motivos de uniformidad. Aquí es donde entra en juego la derivación.

Puede que le sorprenda, pero spaCy no contiene ninguna función para la lematización, ya que se basa únicamente en la lematización. Por lo tanto, en esta sección, usaremos NLTK para derivación.

Hay dos tipos de stemmers en NLTK: Stemmer de portero y Taladores de bola de nieve . Ambos han sido implementados usando diferentes algoritmos.

Voces de portero {#voces de portero}

Veamos a Porter Stemmer en acción:

1
2
3
import nltk

from nltk.stem.porter import *

Vamos a crear una clase de PorterStemmer.

1
stemmer = PorterStemmer()

Supongamos que tenemos la siguiente lista y queremos reducir estas palabras a stem:

1
tokens = ['compute', 'computer', 'computed', 'computing']

El siguiente script encuentra la raíz de las palabras en la lista usando lematizador porter:

1
2
for token in tokens:
    print(token + ' --> ' + stemmer.stem(token))

La salida es la siguiente:

1
2
3
4
compute --> comput
computer --> comput
computed --> comput
computing --> comput

Puede ver que las 4 palabras se han reducido a "computar", que en realidad no es una palabra en absoluto.

Votos de bola de nieve {#votos de bola de nieve}

El destalonador Snowball es una versión ligeramente mejorada del destalonador Porter y, por lo general, se prefiere a este último. Veamos a Snowball Stemmer en acción:

1
2
3
4
5
6
7
8
from nltk.stem.snowball import SnowballStemmer

stemmer = SnowballStemmer(language='english')

tokens = ['compute', 'computer', 'computed', 'computing']

for token in tokens:
    print(token + ' --> ' + stemmer.stem(token))

En el script anterior, usamos Snowball stemmer para encontrar la raíz de las mismas 4 palabras que usamos con porter stemmer. La salida se ve así:

1
2
3
4
compute --> comput
computer --> comput
computed --> comput
computing --> comput

Puedes ver que los resultados son los mismos. Todavía tenemos "comput" como raíz. Nuevamente, esta palabra "computar" en realidad no es una palabra del diccionario.

Aquí es donde la lematización es útil. La lematización reduce la palabra a su raíz tal como aparece en el diccionario. Las raíces devueltas a través de la lematización son palabras reales del diccionario y están semánticamente completas, a diferencia de las palabras devueltas por el lematizador.

Lematización

Aunque no pudimos realizar la lematización con spaCy, podemos realizar la lematización con spaCy.

Para hacerlo, necesitamos usar el atributo lemma_ en el documento spaCy. Supongamos que tenemos la siguiente oración:

1
sentence6 = sp(u'compute computer computed computing')

Podemos encontrar las raíces de todas las palabras usando la lematización spaCy de la siguiente manera:

1
2
for word in sentence6:
    print(word.text,  word.lemma_)

La salida del script anterior se ve así:

1
2
3
4
compute compute
computer computer
computed compute
computing computing

Puede ver que, a diferencia de la derivación donde la raíz que obtuvimos fue "computar", las raíces que obtuvimos aquí son palabras reales en el diccionario.

La lematización convierte palabras en la segunda o tercera forma a sus variantes de primera forma. Mira el siguiente ejemplo:

1
2
3
4
sentence7 = sp(u'A letter has been written, asking him to be released')

for word in sentence7:
    print(word.text + '  ===>', word.lemma_)

Producción:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
A ===> a
letter ===> letter
has ===> have
been ===> be
written ===> write
, ===> ,
asking ===> ask
him ===> -PRON-
to ===> to
be ===> be
released ===> release

Puede ver claramente en la salida que las palabras en la segunda y tercera forma, como "escrito", "lanzado", etc. se han convertido a la primera forma, es decir, "escribir" y "liberar\ “.

Yendo más lejos: proyecto de extremo a extremo portátil

¿Tu naturaleza inquisitiva te hace querer ir más allá? Recomendamos consultar nuestro Proyecto guiado: ["Subtítulos de imágenes con CNN y Transformers con Keras"](https://wikihtp.com/courses/image-captioning-with-cnns-and -transformadores-con-keras/#cta){target="_blank”}.

En este proyecto guiado, aprenderá a crear un modelo de subtítulos de imágenes, que acepta una imagen como entrada y produce un subtítulo de texto como salida.

Aprenderás a:

  • Preprocesar texto
  • Vectorizar la entrada de texto fácilmente
  • Trabaje con la API tf.data y cree conjuntos de datos de alto rendimiento
  • Cree Transformers desde cero con TensorFlow/Keras y KerasNLP: la adición horizontal oficial a Keras para crear modelos NLP de última generación
  • Cree arquitecturas híbridas donde la salida de una red se codifica para otra

¿Cómo enmarcamos los subtítulos de las imágenes? La mayoría lo considera un ejemplo de aprendizaje profundo generativo, porque estamos enseñando a una red a generar descripciones. Sin embargo, me gusta verlo como una instancia de traducción automática neuronal: estamos traduciendo las características visuales de una imagen en palabras. A través de la traducción, estamos generando una nueva representación de esa imagen, en lugar de simplemente generar un nuevo significado. Verlo como traducción, y solo por generación de extensión, enfoca la tarea bajo una luz diferente y la hace un poco más intuitiva.

Enmarcar el problema como uno de traducción hace que sea más fácil averiguar qué arquitectura querremos usar. Los transformadores solo de codificador son excelentes para comprender el texto (análisis de opinión, clasificación, etc.) porque los codificadores codifican representaciones significativas. Los modelos de solo decodificador son excelentes para la generación (como GPT-3), ya que los decodificadores pueden inferir representaciones significativas en otra secuencia con el mismo significado. La traducción generalmente se realiza mediante una arquitectura de codificador-decodificador, donde los codificadores codifican una representación significativa de una oración (o imagen, en nuestro caso) y los decodificadores aprenden a convertir esta secuencia en otra representación significativa que es más interpretable para nosotros (como una oración).

Conclusión

La tokenización, la derivación y la lematización son algunas de las tareas de procesamiento de lenguaje natural más fundamentales. En este artículo, vimos cómo podemos realizar tokenización y lematización usando la biblioteca spaCy. También vimos cómo se puede usar NLTK para derivación. En el próximo artículo, comenzaremos nuestra discusión sobre Vocabulario y Coincidencia de frases en Python. n.