Python para PNL: Creaci贸n del modelo TF-IDF desde cero

    Este es el decimocuarto art铆culo de mi serie de art铆culos sobre Python para PNL. En mi art铆culo anterior, expliqu茅 c贸mo convertir oraciones en vectores num茅ricos usando el bolsa de palabras Acercarse. 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 TF-IDF esquema 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 ver realmente el modelo TF-IDF, analicemos primero algunos problemas asociados con el modelo de la bolsa de palabras.

    En el 煤ltimo art铆culo, ten铆amos 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 de bolsa de palabras resultante se ve铆a as铆:

    Jugar al tenis al f煤tbol 驴Fuiste?

    Oraci贸n 110111000
    Oraci贸n 211100111
    Oraci贸n 311010000

    Uno de los principales problemas asociados con el modelo de la bolsa de palabras es que asigna el mismo valor a las palabras, independientemente de su importancia. Por ejemplo, la palabra “jugar” 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 recibir un mayor 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 de nuestro ejemplo que usamos en el modelo de la bolsa de palabras.

    • “Me gusta jugar al f煤tbol”
    • “驴Saliste a jugar 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.

    Oraci贸n 1 Oraci贸n 2 Oraci贸n 3

    yoHizoJohn
    me gustaUdsy
    aVamosyo
    jugarfuera dejugar
    f煤tbol americanoatenis
    jugar
    tenis

    Paso 2: Encuentre valores TF-IDF

    Una vez que haya tokenizado las oraciones, el siguiente paso es encontrar el valor TF-IDF para cada palabra de la oraci贸n.

    Como se discuti贸 anteriormente, el valor de TF se refiere a la frecuencia del t茅rmino 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, observe la palabra “jugar” en la primera oraci贸n. Su frecuencia de t茅rmino ser谩 0.20 ya que la palabra “jugar” 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 inversa de los documentos 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 de 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.

    Encontremos la frecuencia IDF de la palabra “jugar”. Como tenemos tres documentos y la palabra “reproducir” aparece en los tres, el valor IDF de la palabra “reproducir” es 3/3 = 1.

    Finalmente, los valores de TF-IDF se calculan multiplicando los valores de TF con sus correspondientes valores de IDF.

    Para encontrar el valor TF-IDF, primero necesitamos crear un diccionario de frecuencias de palabras como se muestra a continuaci贸n:

    Frecuencia de palabras

    yo2
    me gusta1
    a2
    jugar3
    f煤tbol americano1
    Hizo1
    Uds1
    Vamos1
    fuera de1
    tenis2
    John1
    y1

    A continuaci贸n, clasifiquemos el diccionario en orden descendente de frecuencia como se muestra en la siguiente tabla.

    Frecuencia de palabras

    jugar3
    tenis2
    a2
    yo2
    f煤tbol americano1
    Hizo1
    Uds1
    Vamos1
    fuera de1
    me gusta1
    John1
    y1

    Finalmente, filtraremos las 8 palabras m谩s frecuentes.

    Como dije anteriormente, dado que los valores de IDF se calculan utilizando todo el corpus. Ahora podemos calcular el valor IDF para cada palabra. 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 americano 1 3/1 = 3
    Hizo 1 3/1 = 3
    Uds 1 3/1 = 3
    Vamos 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.

    Busquemos ahora los valores TF-IDF para todas las palabras en cada oraci贸n.

    Palabra

    Oraci贸n 1

    Oraci贸n 2

    Oraci贸n 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 americano 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
    Uds 0 x3 = 0 0,14 x 3 = 0,42 0 x 3 = 0
    Vamos 0x 3 = 0 0,14 x 3 = 0,42 0 x 3 = 0

    Los valores de las columnas para las frases 1, 2 y 3 son los vectores TF-IDF correspondientes para cada palabra en las frases respectivas.

    Nota 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 corpus, se puede calcular el logaritmo del valor IDF antes de multiplicarlo por el valor TF-IDF. En tal caso, la f贸rmula de IDF se convierte en:

    IDF: log((Total number of sentences (documents))/(Number of sentences (documents) containing the word))
    

    Sin embargo, dado 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 explic贸 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铆, solo escribir茅 el c贸digo. El modelo TF-IDF se basar谩 en 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 script anterior, primero extraemos el art铆culo de Wikipedia sobre Procesamiento natural del lenguaje. Luego lo preprocesamos para eliminar todos los caracteres especiales y m煤ltiples espacios vac铆os. Por 煤ltimo, creamos un diccionario de frecuencias de palabras y luego filtramos las 200 palabras m谩s frecuentes.

    El siguiente paso es encontrar los valores IDF para las palabras que aparecen con m谩s 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_values. Este diccionario almacenar谩 las palabras m谩s frecuentes como claves y sus valores IDF correspondientes como valores de diccionario. A continuaci贸n, recorremos la lista de palabras que aparecen con mayor frecuencia. Durante cada iteraci贸n, creamos una variable doc_containing_word. Esta variable almacenar谩 el n煤mero de documentos en los que aparece la palabra. A continuaci贸n, iteramos a trav茅s de todas las oraciones de nuestro corpus. La oraci贸n se tokeniza y luego verificamos si la palabra existe en la oraci贸n o no, si la palabra existe, incrementamos el doc_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 gui贸n:

    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 clave y una lista de 49 elementos como valor ya que tenemos 49 oraciones en nuestro corpus. Cada elemento de la lista almacena el valor TF de la palabra para la oraci贸n correspondiente. En el gui贸n de arriba word_tf_values es nuestro diccionario. Para cada palabra, creamos una lista. sent_tf_vector.

    Luego iteramos a trav茅s de cada oraci贸n en el corpus y la convertimos en token. La palabra del bucle exterior se corresponde con cada palabra de la oraci贸n. Si se encuentra una coincidencia, doc_freq La variable se incrementa en 1. Una vez que se repiten todas las palabras de la oraci贸n, doc_freq se divide por la longitud total de la oraci贸n para encontrar el valor TF de la palabra para esa oraci贸n. Este proceso se repite para todas las palabras de la lista de palabras que aparecen con m谩s frecuencia. El final word_tf_values El diccionario contendr谩 200 palabras como claves. Para cada palabra, habr谩 una lista de 49 elementos como valor.

    Si miras el word_tf_values diccionario, se ve as铆:

    Puedes ver que el word es 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 por los 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_values. Luego iteramos a trav茅s de todas las claves en el word_tf_values diccionario. Estas claves son b谩sicamente las palabras que aparecen con m谩s frecuencia. Usando estas palabras, recuperamos la lista de 49 dimensiones que contiene los valores TF para la palabra correspondiente a cada oraci贸n. A continuaci贸n, el valor TF se multiplica por el valor IDF de la palabra y se almacena en el tf_idf_score variable. Luego, la variable se agrega al tf_idf_sentences lista. Finalmente, el tf_idf_sentences La lista se adjunta al tfidf_values lista.

    Ahora, en este momento, el tfidf_values es una lista de listas. Donde cada elemento es una lista de 49 dimensiones que contiene valores TFIDF de una palabra en particular para todas las oraciones. Necesitamos convertir la lista bidimensional en una matriz numpy. Mira el siguiente gui贸n:

    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 num茅rica 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 pr贸ximo art铆culo veremos c贸mo implementar el modelo N-Gram desde cero en Python.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *