AI con Python - Paquete NLTK

En este capítulo, aprenderemos cómo comenzar con el paquete de herramientas de lenguaje natural.

Requisito previo

Si queremos crear aplicaciones con procesamiento de lenguaje natural, el cambio de contexto lo hace más difícil. El factor de contexto influye en cómo la máquina entiende una oración en particular. Por lo tanto, necesitamos desarrollar aplicaciones de lenguaje natural mediante el uso de enfoques de aprendizaje automático para que la máquina también pueda comprender la forma en que un humano puede comprender el contexto.

Para construir tales aplicaciones usaremos el paquete Python llamado NLTK (Paquete de herramientas de lenguaje natural).

Importando NLTK

Necesitamos instalar NLTK antes de usarlo. Se puede instalar con la ayuda del siguiente comando:

pip install nltk

Para construir un paquete conda para NLTK, use el siguiente comando:

conda install -c anaconda nltk

Ahora, después de instalar el paquete NLTK, necesitamos importarlo a través del símbolo del sistema de Python. Podemos importarlo escribiendo el siguiente comando en el símbolo del sistema de Python:

>>> import nltk

Descarga de datos de NLTK

Ahora, después de importar NLTK, necesitamos descargar los datos requeridos. Se puede hacer con la ayuda del siguiente comando en el símbolo del sistema de Python:

>>> nltk.download()

Instalación de otros paquetes necesarios

Para construir aplicaciones de procesamiento de lenguaje natural usando NLTK, necesitamos instalar los paquetes necesarios. Los paquetes son los siguientes:

gensim

Es una biblioteca robusta de modelado semántico que es útil para muchas aplicaciones. Podemos instalarlo ejecutando el siguiente comando:

pip install gensim

patrón

Se usa para hacer gensimel paquete funciona correctamente. Podemos instalarlo ejecutando el siguiente comando

pip install pattern

Concepto de tokenización, derivación y lematización

En esta sección, entenderemos qué es tokenización, derivación y lematización.

Tokenización

Puede definirse como el proceso de dividir el texto dado, es decir, la secuencia de caracteres en unidades más pequeñas llamadas tokens. Las fichas pueden ser palabras, números o signos de puntuación. También se llama segmentación de palabras. A continuación, se muestra un ejemplo simple de tokenización:

Input - Mango, plátano, piña y manzana son frutas.

Output -

El proceso de dividir el texto dado se puede realizar con la ayuda de localizar los límites de las palabras. El final de una palabra y el comienzo de una nueva se denominan límites de palabras. El sistema de escritura y la estructura tipográfica de las palabras influyen en los límites.

En el módulo Python NLTK, tenemos diferentes paquetes relacionados con la tokenización que podemos usar para dividir el texto en tokens según nuestros requisitos. Algunos de los paquetes son los siguientes:

paquete sent_tokenize

Como sugiere el nombre, este paquete dividirá el texto de entrada en oraciones. Podemos importar este paquete con la ayuda del siguiente código Python:

from nltk.tokenize import sent_tokenize

paquete word_tokenize

Este paquete divide el texto de entrada en palabras. Podemos importar este paquete con la ayuda del siguiente código Python:

from nltk.tokenize import word_tokenize

Paquete WordPunctTokenizer

Este paquete divide el texto de entrada en palabras y en los signos de puntuación. Podemos importar este paquete con la ayuda del siguiente código Python:

from nltk.tokenize import WordPuncttokenizer

Derivado

Al trabajar con palabras, nos encontramos con muchas variaciones debido a razones gramaticales. El concepto de variaciones aquí significa que tenemos que tratar con diferentes formas de las mismas palabras comodemocracy, democratic, y democratization. Es muy necesario que las máquinas comprendan que estas palabras diferentes tienen la misma forma básica. De esta forma, sería útil extraer las formas base de las palabras mientras analizamos el texto.

Podemos lograr esto mediante la derivación. De esta manera, podemos decir que la derivación es el proceso heurístico de extraer las formas base de las palabras cortando los extremos de las palabras.

En el módulo Python NLTK, tenemos diferentes paquetes relacionados con la derivación. Estos paquetes se pueden utilizar para obtener las formas básicas de la palabra. Estos paquetes utilizan algoritmos. Algunos de los paquetes son los siguientes:

Paquete PorterStemmer

Este paquete de Python utiliza el algoritmo de Porter para extraer el formulario base. Podemos importar este paquete con la ayuda del siguiente código Python:

from nltk.stem.porter import PorterStemmer

Por ejemplo, si le damos la palabra ‘writing’ como entrada a este lematizador, obtendremos la palabra ‘write’ después de la derivación.

Paquete LancasterStemmer

Este paquete de Python utilizará el algoritmo de Lancaster para extraer el formulario base. Podemos importar este paquete con la ayuda del siguiente código Python:

from nltk.stem.lancaster import LancasterStemmer

Por ejemplo, si le damos la palabra ‘writing’ como entrada a este lematizador, obtendremos la palabra ‘write’ después de la derivación.

Paquete SnowballStemmer

Este paquete de Python utilizará el algoritmo de la bola de nieve para extraer el formulario base. Podemos importar este paquete con la ayuda del siguiente código Python:

from nltk.stem.snowball import SnowballStemmer

Por ejemplo, si le damos la palabra ‘writing’ como entrada a este lematizador, obtendremos la palabra ‘write’ después de la derivación.

Todos estos algoritmos tienen diferentes niveles de rigor. Si comparamos estos tres lematizadores, Porter es el menos estricto y Lancaster es el más estricto. El tallador de bolas de nieve es bueno para usar en términos de velocidad y rigor.

Lematización

También podemos extraer la forma básica de las palabras mediante lematización. Básicamente, realiza esta tarea con el uso de un vocabulario y análisis morfológico de palabras, normalmente con el objetivo de eliminar solo las terminaciones flexivas. Este tipo de forma básica de cualquier palabra se llama lema.

La principal diferencia entre la derivación y la lematización es el uso del vocabulario y el análisis morfológico de las palabras. Otra diferencia es que la derivación más comúnmente colapsa las palabras derivadas, mientras que la lematización comúnmente solo colapsa las diferentes formas flexivas de un lema. Por ejemplo, si proporcionamos la palabra saw como palabra de entrada, la raíz podría devolver la palabra 's', pero la lematización intentaría devolver la palabra see o saw dependiendo de si el uso del token era un verbo o un sustantivo.

En el módulo Python NLTK, tenemos el siguiente paquete relacionado con el proceso de lematización que podemos usar para obtener las formas base de la palabra:

Paquete WordNetLemmatizer

Este paquete de Python extraerá la forma base de la palabra dependiendo de si se usa como sustantivo o como verbo. Podemos importar este paquete con la ayuda del siguiente código Python:

from nltk.stem import WordNetLemmatizer

Fragmentación: división de datos en fragmentos

Es uno de los procesos importantes en el procesamiento del lenguaje natural. El trabajo principal de fragmentar es identificar las partes del discurso y frases cortas como frases nominales. Ya hemos estudiado el proceso de tokenización, la creación de tokens. Básicamente, fragmentar es el etiquetado de esos tokens. En otras palabras, fragmentar nos mostrará la estructura de la oración.

En la siguiente sección, aprenderemos sobre los diferentes tipos de Chunking.

Tipos de fragmentación

Hay dos tipos de fragmentación. Los tipos son los siguientes:

Fragmentando

En este proceso de fragmentación, el objeto, las cosas, etc. avanzan hacia ser más generales y el lenguaje se vuelve más abstracto. Hay más posibilidades de acuerdo. En este proceso, nos alejamos. Por ejemplo, si dividimos la pregunta “¿para qué sirven los coches”? Es posible que obtengamos la respuesta "transporte".

Fragmentando

En este proceso de fragmentación, el objeto, las cosas, etc. se mueven hacia ser más específicos y el lenguaje se penetra más. La estructura más profunda se examinaría en fragmentos. En este proceso, nos acercamos. Por ejemplo, si reducimos la pregunta "Habla específicamente sobre un automóvil"? Obtendremos información más pequeña sobre el automóvil.

Example

En este ejemplo, haremos fragmentación de frases sustantivas, una categoría de fragmentación que encontrará los fragmentos de frases nominales en la oración, utilizando el módulo NLTK en Python:

Follow these steps in python for implementing noun phrase chunking −

Step 1- En este paso, necesitamos definir la gramática para fragmentar. Consistiría en las reglas que debemos seguir.

Step 2- En este paso, necesitamos crear un analizador de fragmentos. Analizaría la gramática y daría la salida.

Step 3 - En este último paso, la salida se produce en formato de árbol.

Importemos el paquete NLTK necesario de la siguiente manera:

import nltk

Ahora, necesitamos definir la oración. Aquí, DT significa el determinante, VBP significa el verbo, JJ significa el adjetivo, IN significa la preposición y NN significa el sustantivo.

sentence=[("a","DT"),("clever","JJ"),("fox","NN"),("was","VBP"),
          ("jumping","VBP"),("over","IN"),("the","DT"),("wall","NN")]

Ahora, tenemos que dar la gramática. Aquí, daremos la gramática en forma de expresión regular.

grammar = "NP:{<DT>?<JJ>*<NN>}"

Necesitamos definir un analizador que analizará la gramática.

parser_chunking = nltk.RegexpParser(grammar)

El analizador analiza la oración de la siguiente manera:

parser_chunking.parse(sentence)

A continuación, necesitamos obtener la salida. La salida se genera en la variable simple llamadaoutput_chunk.

Output_chunk = parser_chunking.parse(sentence)

Tras la ejecución del siguiente código, podemos dibujar nuestra salida en forma de árbol.

output.draw()

Modelo de bolsa de palabras (BoW)

Bag of Word (BoW), un modelo en el procesamiento del lenguaje natural, se usa básicamente para extraer las características del texto para que el texto se pueda usar en el modelado, como en los algoritmos de aprendizaje automático.

Ahora surge la pregunta de por qué necesitamos extraer las características del texto. Esto se debe a que los algoritmos de aprendizaje automático no pueden funcionar con datos sin procesar y necesitan datos numéricos para poder extraer información significativa de ellos. La conversión de datos de texto en datos numéricos se denomina extracción de características o codificación de características.

Cómo funciona

Este es un enfoque muy simple para extraer las características del texto. Supongamos que tenemos un documento de texto y queremos convertirlo en datos numéricos o decir que queremos extraer las características de él, luego, en primer lugar, este modelo extrae un vocabulario de todas las palabras del documento. Luego, utilizando una matriz de términos de documento, construirá un modelo. De esta manera, BoW representa el documento solo como una bolsa de palabras. Se descarta cualquier información sobre el orden o la estructura de las palabras en el documento.

Concepto de matriz de términos del documento

El algoritmo BoW construye un modelo utilizando la matriz de términos del documento. Como sugiere el nombre, la matriz de términos del documento es la matriz de varios recuentos de palabras que ocurren en el documento. Con la ayuda de esta matriz, el documento de texto se puede representar como una combinación ponderada de varias palabras. Al establecer el umbral y elegir las palabras que son más significativas, podemos construir un histograma de todas las palabras en los documentos que se pueden usar como vector de características. A continuación se muestra un ejemplo para comprender el concepto de matriz de términos de documento:

Example

Supongamos que tenemos las siguientes dos oraciones:

  • Sentence 1 - Estamos usando el modelo Bag of Words.

  • Sentence 2 - El modelo Bag of Words se utiliza para extraer las características.

Ahora, al considerar estas dos oraciones, tenemos las siguientes 13 palabras distintas:

  • we
  • are
  • using
  • the
  • bag
  • of
  • words
  • model
  • is
  • used
  • for
  • extracting
  • features

Ahora, necesitamos construir un histograma para cada oración usando el recuento de palabras en cada oración:

  • Sentence 1 - [1,1,1,1,1,1,1,1,0,0,0,0,0]

  • Sentence 2 - [0,0,0,1,1,1,1,1,1,1,1,1,1]

De esta forma, tenemos los vectores de características que se han extraído. Cada vector de características tiene 13 dimensiones porque tenemos 13 palabras distintas.

Concepto de Estadística

El concepto de las estadísticas se denomina Frecuencia de término-Frecuencia de documento inversa (tf-idf). Cada palabra es importante en el documento. Las estadísticas nos ayudan a comprender la importancia de cada palabra.

Frecuencia de término (tf)

Es la medida de la frecuencia con la que aparece cada palabra en un documento. Puede obtenerse dividiendo el recuento de cada palabra por el número total de palabras de un documento determinado.

Frecuencia de documento inverso (idf)

Es la medida de cuán única es una palabra para este documento en el conjunto de documentos dado. Para calcular idf y formular un vector de características distintivas, debemos reducir el peso de las palabras que aparecen comúnmente como y sopesar las palabras raras.

Construyendo un modelo de bolsa de palabras en NLTK

En esta sección, definiremos una colección de cadenas usando CountVectorizer para crear vectores a partir de estas oraciones.

Importamos el paquete necesario -

from sklearn.feature_extraction.text import CountVectorizer

Ahora defina el conjunto de oraciones.

Sentences = ['We are using the Bag of Word model', 'Bag of Word model is
           used for extracting the features.']

vectorizer_count = CountVectorizer()

features_text = vectorizer.fit_transform(Sentences).todense()

print(vectorizer.vocabulary_)

El programa anterior genera la salida como se muestra a continuación. Muestra que tenemos 13 palabras distintas en las dos oraciones anteriores:

{'we': 11, 'are': 0, 'using': 10, 'the': 8, 'bag': 1, 'of': 7,
 'word': 12, 'model': 6, 'is': 5, 'used': 9, 'for': 4, 'extracting': 2, 'features': 3}

Estos son los vectores de características (texto a forma numérica) que se pueden utilizar para el aprendizaje automático.

Resolviendo problemas

En esta sección, resolveremos algunos problemas relacionados.

Predicción de categoría

En un conjunto de documentos, no solo las palabras sino también la categoría de las palabras son importantes; en qué categoría de texto se encuentra una palabra en particular. Por ejemplo, queremos predecir si una oración determinada pertenece a la categoría correo electrónico, noticias, deportes, computadora, etc. En el siguiente ejemplo, usaremos tf-idf para formular un vector de características para encontrar la categoría de documentos. Usaremos los datos del conjunto de datos de 20 grupos de noticias de sklearn.

Necesitamos importar los paquetes necesarios -

from sklearn.datasets import fetch_20newsgroups
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer

Defina el mapa de categorías. Estamos utilizando cinco categorías diferentes denominadas Religión, Automóviles, Deportes, Electrónica y Espacio.

category_map = {'talk.religion.misc':'Religion','rec.autos''Autos',
   'rec.sport.hockey':'Hockey','sci.electronics':'Electronics', 'sci.space': 'Space'}

Crea el conjunto de entrenamiento -

training_data = fetch_20newsgroups(subset = 'train',
   categories = category_map.keys(), shuffle = True, random_state = 5)

Construya un vectorizador de conteo y extraiga el término conteo -

vectorizer_count = CountVectorizer()
train_tc = vectorizer_count.fit_transform(training_data.data)
print("\nDimensions of training data:", train_tc.shape)

El transformador tf-idf se crea de la siguiente manera:

tfidf = TfidfTransformer()
train_tfidf = tfidf.fit_transform(train_tc)

Ahora, defina los datos de prueba:

input_data = [
   'Discovery was a space shuttle',
   'Hindu, Christian, Sikh all are religions',
   'We must have to drive safely',
   'Puck is a disk made of rubber',
   'Television, Microwave, Refrigrated all uses electricity'
]

Los datos anteriores nos ayudarán a entrenar un clasificador multinomial Naive Bayes -

classifier = MultinomialNB().fit(train_tfidf, training_data.target)

Transforme los datos de entrada usando el vectorizador de conteo -

input_tc = vectorizer_count.transform(input_data)

Ahora, transformaremos los datos vectorizados usando el transformador tfidf -

input_tfidf = tfidf.transform(input_tc)

Predeciremos las categorías de salida:

predictions = classifier.predict(input_tfidf)

La salida se genera de la siguiente manera:

for sent, category in zip(input_data, predictions):
   print('\nInput Data:', sent, '\n Category:', \
      category_map[training_data.target_names[category]])

El predictor de categoría genera la siguiente salida:

Dimensions of training data: (2755, 39297)

Input Data: Discovery was a space shuttle
Category: Space

Input Data: Hindu, Christian, Sikh all are religions
Category: Religion

Input Data: We must have to drive safely
Category: Autos

Input Data: Puck is a disk made of rubber
Category: Hockey

Input Data: Television, Microwave, Refrigrated all uses electricity
Category: Electronics

Buscador de género

En este enunciado del problema, se capacitaría a un clasificador para encontrar el género (masculino o femenino) proporcionando los nombres. Necesitamos usar una heurística para construir un vector de características y entrenar al clasificador. Usaremos los datos etiquetados del paquete scikit-learn. A continuación se muestra el código de Python para construir un buscador de género:

Importamos los paquetes necesarios -

import random

from nltk import NaiveBayesClassifier
from nltk.classify import accuracy as nltk_accuracy
from nltk.corpus import names

Ahora necesitamos extraer las últimas N letras de la palabra de entrada. Estas letras actuarán como características:

def extract_features(word, N = 2):
   last_n_letters = word[-N:]
   return {'feature': last_n_letters.lower()}
	
if __name__=='__main__':

Cree los datos de entrenamiento utilizando nombres etiquetados (tanto masculinos como femeninos) disponibles en NLTK -

male_list = [(name, 'male') for name in names.words('male.txt')]
female_list = [(name, 'female') for name in names.words('female.txt')]
data = (male_list + female_list)

random.seed(5)
random.shuffle(data)

Ahora, los datos de prueba se crearán de la siguiente manera:

namesInput = ['Rajesh', 'Gaurav', 'Swati', 'Shubha']

Defina la cantidad de muestras utilizadas para entrenar y probar con el siguiente código

train_sample = int(0.8 * len(data))

Ahora, necesitamos iterar a través de diferentes longitudes para poder comparar la precisión:

for i in range(1, 6):
   print('\nNumber of end letters:', i)
   features = [(extract_features(n, i), gender) for (n, gender) in data]
   train_data, test_data = features[:train_sample],
features[train_sample:]
   classifier = NaiveBayesClassifier.train(train_data)

La precisión del clasificador se puede calcular de la siguiente manera:

accuracy_classifier = round(100 * nltk_accuracy(classifier, test_data), 2)
   print('Accuracy = ' + str(accuracy_classifier) + '%')

Ahora, podemos predecir la salida:

for name in namesInput:
   print(name, '==>', classifier.classify(extract_features(name, i)))

El programa anterior generará la siguiente salida:

Number of end letters: 1
Accuracy = 74.7%
Rajesh -> female
Gaurav -> male
Swati -> female
Shubha -> female

Number of end letters: 2
Accuracy = 78.79%
Rajesh -> male
Gaurav -> male
Swati -> female
Shubha -> female

Number of end letters: 3
Accuracy = 77.22%
Rajesh -> male
Gaurav -> female
Swati -> female
Shubha -> female

Number of end letters: 4
Accuracy = 69.98%
Rajesh -> female
Gaurav -> female
Swati -> female
Shubha -> female

Number of end letters: 5
Accuracy = 64.63%
Rajesh -> female
Gaurav -> female
Swati -> female
Shubha -> female

En el resultado anterior, podemos ver que la precisión en el número máximo de letras finales es dos y está disminuyendo a medida que aumenta la cantidad de letras finales.

Modelado de temas: identificación de patrones en datos de texto

Sabemos que generalmente los documentos se agrupan por temas. A veces necesitamos identificar los patrones en un texto que corresponden a un tema en particular. La técnica para hacer esto se llama modelado de temas. En otras palabras, podemos decir que el modelado de temas es una técnica para descubrir temas abstractos o estructuras ocultas en el conjunto de documentos dado.

Podemos utilizar la técnica de modelado de temas en los siguientes escenarios:

Clasificación de texto

Con la ayuda del modelado de temas, la clasificación se puede mejorar porque agrupa palabras similares en lugar de usar cada palabra por separado como característica.

Sistemas de recomendación

Con la ayuda del modelado de temas, podemos construir los sistemas de recomendación usando medidas de similitud.

Algoritmos para el modelado de temas

El modelado de temas se puede implementar mediante algoritmos. Los algoritmos son los siguientes:

Asignación de Dirichlet latente (LDA)

Este algoritmo es el más popular para el modelado de temas. Utiliza los modelos gráficos probabilísticos para implementar el modelado de temas. Necesitamos importar el paquete gensim en Python para usar LDA slgorithm.

Análisis semántico latente (LDA) o indexación semántica latente (LSI)

Este algoritmo se basa en álgebra lineal. Básicamente, utiliza el concepto de SVD (Descomposición de valores singulares) en la matriz de términos del documento.

Factorización de matriz no negativa (NMF)

También se basa en álgebra lineal.

Todos los algoritmos mencionados anteriormente para el modelado de temas tendrían la number of topics como parámetro, Document-Word Matrix como entrada y WTM (Word Topic Matrix) Y TDM (Topic Document Matrix) como salida.