Breaking

Post Top Ad

Your Ad Spot

miércoles, 10 de julio de 2019

Python para NLP: Crear un modelo TF-IDF desde cero

Este es el artículo número 14 de mi serie de artículos sobre Python para PNL. En mi artículo anterior , expliqué cómo convertir oraciones en vectores numéricos utilizando el método de bolsa de palabras . Para comprender mejor el enfoque de la bolsa de palabras, implementamos la técnica en Python.
En este artículo, nos basaremos en el concepto que aprendimos en el artículo anterior e implementaremos el esquema TF-IDF desde cero en Python. El término TF significa "frecuencia de término", mientras que el término IDF significa "frecuencia de documento inversa".

Problema con el modelo de bolsa de palabras

Antes de que veamos realmente el modelo TF-IDF, primero analicemos algunos problemas asociados con el modelo de bolsa de palabras.
En el último artículo, tuvimos las siguientes tres oraciones de ejemplo:
  • "Me gusta jugar al fútbol"
  • "¿Saliste a jugar al tenis?"
  • "John y yo jugamos al tenis"
El modelo resultante de la bolsa de palabras se veía así:
JugarTenisAyoFútbolHizoir
Frase 110111000
Frase 211100111
Frase 311010000
Uno de los principales problemas asociados con el modelo de bolsa de palabras es que asigna el mismo valor a las palabras, independientemente de su importancia. Por ejemplo, la palabra "juego" aparece en las tres oraciones, por lo tanto, esta palabra es muy común; por otro lado, la palabra "fútbol" solo aparece en una oración. Las palabras que son raras tienen más poder de clasificación en comparación con las palabras que son comunes.
La idea detrás del enfoque TF-IDF es que las palabras que son más comunes en una oración y menos comunes en otras oraciones deben tener un alto peso.

Teoría detrás de TF-IDF

Antes de implementar el esquema TF-IDF en Python, primero estudiemos la teoría. Usaremos las mismas tres oraciones que nuestro ejemplo que usamos en el modelo de bolsa de palabras.
  • "Me gusta jugar al fútbol"
  • "¿Saliste a jugar al tenis?"
  • "John y yo jugamos al tenis"

Paso 1: Tokenización

Al igual que la bolsa de palabras, el primer paso para implementar el modelo TF-IDF es la tokenización.
Frase 1Frase 2Frase 3
yoHizoJuan
me gustay
airyo
jugarfuera dejugar
fútbolatenis
jugar
tenis

Paso 2: Encuentra los valores de TF-IDF

Una vez que haya simbolizado las oraciones, el siguiente paso es encontrar el valor de TF-IDF para cada palabra en la oración.
Como se mencionó anteriormente, el valor de TF se refiere al término frecuencia y se puede calcular de la siguiente manera:
TF = (Frequency of the word in the sentence) / (Total number of words in the sentence)  
Por ejemplo, mira la palabra "juego" en la primera oración. El término frecuencia será 0.20 ya que la palabra "juego" aparece solo una vez en la oración y el número total de palabras en la oración es 5, por lo tanto, 1/5 = 0.20.
IDF se refiere a la frecuencia de documentos inversos y se puede calcular de la siguiente manera:
IDF: (Total number of sentences (documents))/(Number of sentences (documents) containing the word)  
Es importante mencionar que el valor IDF para una palabra permanece igual en todos los documentos, ya que depende del número total de documentos. Por otro lado, los valores de TF de una palabra difieren de un documento a otro.
Vamos a encontrar la frecuencia IDF de la palabra "jugar". Como tenemos tres documentos y la palabra "juego" aparece en los tres, el valor IDF de la palabra "juego" es 3/3 = 1.
Finalmente, los valores de TF-IDF se calculan multiplicando los valores de TF con sus valores correspondientes de IDF.
Para encontrar el valor de TF-IDF, primero debemos crear un diccionario de frecuencias de palabras como se muestra a continuación:
PalabraFrecuencia
yo2
me gusta1
a2
jugar3
fútbol1
Hizo1
1
ir1
fuera de1
tenis2
Juan1
y1
A continuación, ordenemos el diccionario en el orden descendente de la frecuencia como se muestra en la siguiente tabla.
PalabraFrecuencia
jugar3
tenis2
a2
yo2
fútbol1
Hizo1
1
ir1
fuera de1
me gusta1
Juan1
y1
Finalmente, filtraremos las 8 palabras más frecuentes.
Como dije anteriormente, ya que los valores de IDF se calculan utilizando todo el corpus. Podemos calcular el valor IDF para cada palabra ahora. La siguiente tabla contiene valores IDF para cada tabla.

  Palabra
  

  Frecuencia
  

  IDF
  

  jugar
  

  3
  

  3/3 = 1
  

  tenis
  

  2
  

  3/2 = 1.5
  

  a
  

  2
  

  3/2 = 1.5
  

  yo
  

  2
  

  3/2 = 1.5
  

  fútbol
  

  1
  

  3/1 = 3
  

  Hizo
  

  1
  

  3/1 = 3
  

  tú
  

  1
  

  3/1 = 3
  

  ir
  

  1
  

  3/1 = 3
  
Puede ver claramente que las palabras que son raras tienen valores IDF más altos en comparación con las palabras que son más comunes.
Ahora encontremos los valores de TF-IDF para todas las palabras en cada oración.

  Palabra
  

  Frase 1
  

  Frase 2
  

  Frase 3
  

  jugar
  

  0.20 x 1 = 0.20
  

  0.14 x 1 = 0.14
  

  0.20 x 1 = 0.20
  

  tenis
  

  0 x 1.5 = 0
  

  0.14 x 1.5 = 0.21
  

  0.20 x 1.5 = 0.30
  

  a
  

  0.20 x 1.5 = 0.30
  

  0.14 x 1.5 = 0.21 
  

  0 x 1.5 = 0
  

  yo
  

  0.20 x 1.5 = 0.30
  

  0 x 1.5 = 0
  

  0.20 x 1.5 = 0.30
  

  fútbol
  

  0.20 x 3 = 0.6
  

  0 x 3 = 0 
  

  0 x 3 = 0
  

  hizo
  

  0 x 3 = 0
  

  0.14 x 3 = 0.42
  

  0 x 3 = 0
  

  tú
  

  0 x3 = 0
  

  0.14 x 3 = 0.42
  

  0 x 3 = 0
  

  ir
  

  0x 3 = 0
  

  0.14 x 3 = 0.42
  

  0 x 3 = 0
  
Los valores en las columnas para la oración 1, 2 y 3 son los vectores TF-IDF correspondientes para cada palabra en las oraciones respectivas.
Tenga en cuenta el uso de la función de registro con TF-IDF.
Es importante mencionar que para mitigar el efecto de palabras muy raras y muy comunes en el cuerpo, el registro del valor de IDF se puede calcular antes de multiplicarlo con el valor de TF-IDF. En tal caso, la fórmula de la FID se convierte en:
IDF: log((Total number of sentences (documents))/(Number of sentences (documents) containing the word))  
Sin embargo, ya que solo teníamos tres oraciones en nuestro corpus, por simplicidad no usamos log. En la sección de implementación, usaremos la función de registro para calcular el valor final de TF-IDF.

Modelo TF-IDF desde cero en Python

Como se explica en la sección de teoría, los pasos para crear un diccionario ordenado de frecuencia de palabras son similares entre la bolsa de palabras y el modelo TF-IDF. Para comprender cómo creamos un diccionario ordenado de frecuencias de palabras, consulte mi último artículo . Aquí, sólo escribiré el código. El modelo TF-IDF se construirá sobre este código.
# -*- coding: utf-8 -*-
"""
Created on Sat Jul 6 14:21:00 2019

@author: usman
"""

import nltk  
import numpy as np  
import random  
import string

import bs4 as bs  
import urllib.request  
import re

raw_html = urllib.request.urlopen('https://en.wikipedia.org/wiki/Natural_language_processing')  
raw_html = raw_html.read()

article_html = bs.BeautifulSoup(raw_html, 'lxml')

article_paragraphs = article_html.find_all('p')

article_text = ''

for para in article_paragraphs:  
    article_text += para.text

corpus = nltk.sent_tokenize(article_text)

for i in range(len(corpus )):  
    corpus [i] = corpus [i].lower()
    corpus [i] = re.sub(r'\W',' ',corpus [i])
    corpus [i] = re.sub(r'\s+',' ',corpus [i])

wordfreq = {}  
for sentence in corpus:  
    tokens = nltk.word_tokenize(sentence)
    for token in tokens:
        if token not in wordfreq.keys():
            wordfreq[token] = 1
        else:
            wordfreq[token] += 1

import heapq  
most_freq = heapq.nlargest(200, wordfreq, key=wordfreq.get)  
En el guión anterior, primero eliminamos el artículo de Wikipedia sobre el procesamiento del lenguaje natural . Luego, lo procesamos previamente para eliminar todos los caracteres especiales y los múltiples espacios vacíos. Finalmente, creamos un diccionario de frecuencias de palabras y luego filtramos las 200 palabras principales que aparecen con mayor frecuencia.
El siguiente paso es encontrar los valores de IDF para las palabras que ocurren con mayor frecuencia en el corpus. El siguiente script hace eso:
word_idf_values = {}  
for token in most_freq:  
    doc_containing_word = 0
    for document in corpus:
        if token in nltk.word_tokenize(document):
            doc_containing_word += 1
    word_idf_values[token] = np.log(len(corpus)/(1 + doc_containing_word))
En el script anterior, creamos un diccionario vacío word_idf_valuesEste diccionario almacenará las palabras que aparecen con mayor frecuencia como claves y sus correspondientes valores IDF como valores del diccionario. A continuación, recorremos la lista de las palabras que aparecen con mayor frecuencia. Durante cada iteración, creamos una variable doc_containing_wordEsta variable almacenará el número de documentos en los que aparece la palabra. A continuación, iteramos a través de todas las frases en nuestro corpus. La oración es tokenizada y luego verificamos si la palabra existe en la oración o no, si la palabra existe, incrementamos ladoc_containing_word variable. Finalmente, para calcular el valor IDF, dividimos el número total de oraciones por el número total de documentos que contienen la palabra.
El siguiente paso es crear el diccionario TF para cada palabra. En el diccionario TF, la clave serán las palabras que aparecen con mayor frecuencia, mientras que los valores serán 49 vectores dimensionales ya que nuestro documento tiene 49 oraciones. Cada valor en el vector pertenecerá al valor TF de la palabra para la oración correspondiente. Mira el siguiente script:
word_tf_values = {}  
for token in most_freq:  
    sent_tf_vector = []
    for document in corpus:
        doc_freq = 0
        for word in nltk.word_tokenize(document):
            if token == word:
                  doc_freq += 1
        word_tf = doc_freq/len(nltk.word_tokenize(document))
        sent_tf_vector.append(word_tf)
    word_tf_values[token] = sent_tf_vector
En el script anterior, creamos un diccionario que contiene la palabra como la clave y una lista de 49 elementos como un valor ya que tenemos 49 oraciones en nuestro corpus. Cada elemento de la lista almacena el valor de TF de la palabra para la oración correspondiente. En el script de arriba word_tf_valuesestá nuestro diccionario. Para cada palabra, creamos una lista.sent_tf_vector .
Luego iteramos a través de cada oración en el corpus y tokenize la oración. La palabra del bucle externo coincide con cada palabra en la oración. Si se encuentra una coincidencia, la doc_freqvariable se incrementa en 1. Una vez, se iteran todas las palabras en la oración, doc_freqse divide por la longitud total de la oración para encontrar el valor de TF de la palabra para esa oración. Este proceso se repite para todas las palabras en la lista de palabras que aparece con mayor frecuencia. El word_tf_valuesdiccionario final contendrá 200 palabras como claves. Para cada palabra, habrá una lista de 49 elementos como el valor.
Si miras el word_tf_valuesdiccionario, se ve así:
Puede ver que wordes la clave, mientras que una lista de 49 elementos es el valor de cada clave.
Ahora tenemos los valores IDF de todas las palabras, junto con los valores TF de cada palabra en las oraciones. El siguiente paso es simplemente multiplicar los valores IDF con valores TF.
tfidf_values = []  
for token in word_tf_values.keys():  
    tfidf_sentences = []
    for tf_sentence in word_tf_values[token]:
        tf_idf_score = tf_sentence * word_idf_values[token]
        tfidf_sentences.append(tf_idf_score)
    tfidf_values.append(tfidf_sentences)
En el script anterior, creamos una lista llamada tfidf_valuesA continuación, iteramos a través de todas las claves en el word_tf_valuesdiccionario. Estas teclas son básicamente las palabras más frecuentes. Usando estas palabras, recuperamos la lista de 49 dimensiones que contiene los valores de TF para la palabra correspondiente a cada oración. A continuación, el valor de TF se multiplica por el valor IDF de la palabra y se almacena en la tf_idf_scorevariable. La variable se anexa a la tf_idf_sentenceslista. Finalmente, la tf_idf_sentenceslista se adjunta a la tfidf_valueslista.
Ahora, en este punto en el tiempo, tfidf_valueshay una lista de listas. Donde cada elemento es una lista de 49 dimensiones que contiene los valores TFIDF de una palabra en particular para todas las oraciones. Necesitamos convertir la lista bidimensional en una matriz numpy. Mira el siguiente script:
tf_idf_model = np.asarray(tfidf_values)  
Ahora, nuestra matriz numpy se ve así:
Sin embargo, todavía hay un problema con este modelo TF-IDF. La dimensión de la matriz es 200 x 49, lo que significa que cada columna representa el vector TF-IDF para la oración correspondiente. Queremos que las filas representen los vectores TF-IDF. Podemos hacerlo simplemente transponiendo nuestra matriz numpy de la siguiente manera:
tf_idf_model = np.transpose(tf_idf_model)  
Ahora tenemos una matriz numpy de 49 x 200 dimensiones donde las filas corresponden a los vectores TF-IDF, como se muestra a continuación:

Conclusión

El modelo TF-IDF es uno de los modelos más utilizados para la conversión de texto a numérico. En este artículo, revisamos brevemente la teoría detrás del modelo TF-IDF. Finalmente, implementamos un modelo TF-IDF desde cero en Python. En el siguiente artículo, veremos cómo implementar el modelo N-Gram desde cero en Python.

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

Post Top Ad

Your Ad Spot

Páginas