[Algoritmo] [PLN#3] Term Frequency (TF) e Term Frequency - Inverse Document Frequency (TF-IDF)


É bastante comum quando utilizamos o Processamento de Linguagem Natural (PLN) termos de escolher quais são as abordagens que iremos utilizar. Atualmente existem três caminhos disponíveis. O primeiro deles é utilizar algoritmos estatísticos; O segundo é a utilização de algoritmos linguísticos. Por fim, podemos buscar aproveitar o melhor de dois mundos e utilizar abordagens híbridas. 

Este tema já foi previamente discutido neste post. Vale a pena ler, caso você ainda não está familiarizado com este assunto.

A abordagem utilizada no algoritmo de Term Frequency (TF) e Term Frequency - Inverse Document Frequency (TF-IDF) é estatística. De forma geral os dois algoritmos estão conectados pois o TF-IDF é uma extensão do TF. 

Term Frequency

A tradução do nome deste algoritmo já nos dá uma dica do que ele trata. A "frequência dos termos" é o processo de encontrar quantas vezes um termo foi repetido em uma sentença. 
Veja um exemplo bastante simples:

Linda é linda.

Nesta sentença podemos afirmar que:
 - Existem 3 de termos nesta sentença;
 - A frequência da palavra "Linda" é de 2/3;
 - A frequência da palavra "é" é de 1/3;


Veja este algoritmo implementado na linguagem JAVA:


import Model.Word;
import Util.StringUtils;
import java.util.ArrayList;
import java.util.LinkedHashSet;

public class TermFrequency {
    //Gera um ArrayList de palavras
    public ArrayList<Word> getTermFrequency(String textToParse) {
        ArrayList<String> words =            
                         stringToArrayOfWords(textToParse);
        ArrayList<Word> retorno = new ArrayList<>();
        
        //Popula o array
        for (String s : words) {
            double count = 0;
            for (String i : words) {
                if (s.equals(i)) {
                    count++;
                }
            }
            if (!s.isEmpty()) {
                double a = count/words.size();
                retorno.add(new Word(s,count/words.size()));
            }
        }

        //Remove palavras repetidas usando HashSet

        LinkedHashSet<Word> temp = new LinkedHashSet<>();
        temp.addAll(retorno);
        retorno.clear();
        retorno.addAll(temp);
        return retorno;
    }

 //AUXILIAR METHODS
    public static ArrayList<String> stringToArrayOfWords(String contentToConvert) {
        ArrayList<String> words = new ArrayList<>();
        if (contentToConvert != null) {
            for (String s : contentToConvert.split(" ")) {
                words.add(s);
            }
        }
        return words;

    }

}

//Classe palavras

public class Word{

    private String word;
    private double frequency;

    public Word(String word, double frequency) {
        this.word = word;
        this.frequency = frequency;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }

    public double getFrequency() {
        return frequency;
    }

    public void setFrequency(double frequency) {
        this.frequency = frequency;

    }
}


Term Frequency - Inverse Document Frequency


Este algoritmo utiliza o mesmo conceito de frequência de termos, porém ele trabalha com uma adaptação visando melhorar o seu desempenho. Esta modificação foi pensada para tratar as palavras existentes no corpus analisado que não significam nada para o conjunto. Veja o exemplo abaixo:

Documento 1:  Eu sou homem.
Documento 2:  Eu sou médico.
Documento 3: Como um bom médico, eu fiz vários cursos de especialização.

Se utilizarmos o algoritmo de TF (sem pré-processamento) podemos perceber que é possível que uma palavra ocorra em todos os documentos. Ex: "Eu". Ao contrário disso também é possível, ou seja, é perfeitamente possível que uma palavra só ocorra em um documento. Ex: "fiz". 

Ao analisar estes fatos é possível concluir que estes dois extremos são ruins para classificação de documentos. Se uma palavra ocorre em todos eles, não é possível dizer que aquela palavra é um diferencial. O mesmo podemos dizer se a palavra ocorre pouquíssimas vezes.

Para isso o algoritmo utiliza uma razão inversa para calcular a frequência destes termos. Observe o algoritmo:

TF * IDF

TF(t) = (Número de vezes que t aparece no documento) / (Número total de termos no documento).

IDF(t) = log_e(Número total de termos do documento/ Número de documentos que possuem o termo t).


Desta forma, tendem a se aproximar de zero, todos os termos que se repetem em todos os documentos ou aqueles que aparecem em apenas um documento.


Veja o algoritmo implementado em JAVA:


import Model.Word;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

public class TermFrequencyIdf {

    public ArrayList<Word> 
                    getTermFrequencyIdf(
                          ArrayList<ArrayList<String>> docs, 
                          String textToParse) {
        
        ArrayList<String> wordsToParse =                    
                                stringToArrayOfWords(textToParse);
        ArrayList<Word> retorno = new ArrayList<>();
        
        //Contabiliza os termos
        for (String s : wordsToParse) {
            double count = 0;
            retorno.add(new Word(s,tfIdf(wordsToParse, docs, s)));
        }

        //Remove termos repetidos
        LinkedHashSet<Word> temp = new LinkedHashSet<>();
        temp.addAll(retorno);
        retorno.clear();
        retorno.addAll(temp);
        return retorno;
    }

  
    public double tf(ArrayList<String> doc, String term) {
        double result = 0;
        for (String word : doc) {
            if (term.equalsIgnoreCase(word)) {
                result++;
            }
        }
        return result / doc.size();
    }

    //Faz a contagem de acordo com a relação inversa dos documentos
    public double idf(ArrayList<ArrayList<String>> docs, String term) {
        double n = 0;
        for (List<String> doc : docs) {
            for (String word : doc) {
                if (term.equalsIgnoreCase(word)) {
                    n++;
                    break;
                }
            }
        }
        return Math.log(docs.size() / n);
    }

    //Retorna o valor do TF-IDF
    public double tfIdf(
                ArrayList<String> doc, 
                ArrayList<ArrayList<String>> docs, 
                String term) {
        return tf(doc, term) * idf(docs, term);

    }

}


Estes dois algoritmos são muito interessantes, porém é importante que para utiliza-los você tenha estudado um pouco de Pre-processamento. Visto que existem muitas palavras que são consideradas "lixo" por serem não significativas. Estes ruídos podem prejudicar a aplicação dos algoritmos descritos acima.




[Algoritmo] [PLN#3] Term Frequency (TF) e Term Frequency - Inverse Document Frequency (TF-IDF) [Algoritmo] [PLN#3] Term Frequency (TF) e Term Frequency - Inverse Document Frequency (TF-IDF) Reviewed by Vinicius dos Santos on 07:04:00 Rating: 5

Nenhum comentário

Escreve ai sua opinião!