Modelo de Bag of Words em Python: Um Guia Completo

Sacola de Palavras (BoW) é uma técnica no Processamento de Linguagem Natural (PLN). É amplamente utilizada para transformar dados textuais em formato legível por máquina, especificamente valores numéricos, sem considerar a gramática e a ordem das palavras. Entender BoW é importante para qualquer pessoa que trabalhe com dados textuais. Python fornece várias ferramentas e bibliotecas para implementar Sacola de Palavras de maneira eficaz.

Neste tutorial, vamos mergulhar no BoW, apresentar seus conceitos, abordar seus usos e fazer uma implementação detalhada em Python. No final deste tutorial, você será capaz de aplicar o modelo de Sacola de Palavras a problemas do mundo real. Se você é novo no PLN, confira nossa trilha de habilidades de Processamento de Linguagem Natural em Python para saber mais.

O que é Sacola de Palavras?

A Bolsa de Palavras é uma técnica para extrair características de dados textuais para tarefas de aprendizado de máquina, como classificação de texto e análise de sentimento. Isso é importante porque os algoritmos de aprendizado de máquina não conseguem processar dados textuais. O processo de conversão do texto em números é conhecido como extração de características ou codificação de características.

A Bolsa de Palavras é baseada na ocorrência de palavras em um documento. O processo começa com a busca do vocabulário no texto e a medição de suas ocorrências. É chamada de bolsa porque a ordem e a estrutura das palavras não são consideradas, apenas sua ocorrência.

O modelo de Bolsa de Palavras é diferente do Modelo de Bolsa de Palavras Contínua (CBOW), que aprende embeddings de palavras densas usando palavras ao redor para prever uma palavra-alvo, capturando relações semânticas entre palavras. O CBOW requer treinamento em um grande corpus e produz vetores de baixa dimensionalidade que são valiosos para aplicações complexas de PLN onde o contexto da palavra é importante.

Aspecto

BOW

CBOW

Propósito

Contabiliza ocorrências de cada palavra

Prediz a palavra-alvo com base no contexto

Tipo de Saída

Vetor de alta dimensão, esparsamente populado

Vetor de baixa dimensão, denso

Considera o Contexto

Não (ignora a ordem das palavras)

Sim (usa palavras circundantes)

Representação

Vetor de frequência esparso

Vetor denso capturando semântica

Complexidade

Baixo (não requer treinamento)

Alto (requer treinamento em grande corpus)

Aplicações Típicas

Classificação de texto, análise de sentimento

Embeddings de palavras, tarefas de NLP que precisam de contexto

Por que usar Bag of Words?

Bag of Words é útil em muitos tarefas de NLP, algumas razões para seu uso incluem:

  • Extração de características: Converte dados de texto não estruturados em dados estruturados, que podem ser usados como entrada para vários algoritmos de aprendizado de máquina.
  • Simplicidade e eficiência: O BOW é computacionalmente simples de implementar e funciona bem para pequenos a médios corpora de texto.
  • Similaridade entre documentos: Pode ser usado para calcular a similaridade entre documentos de texto usando técnicas como a similaridade cosseno.
  • Classificação de texto: Quando combinado com técnicas como Naive Bayes, BoW é eficaz para tarefas de classificação de texto, como classificação de spam, e análise de sentimento.

Porém,也存在一些缺点,如不考虑语义、词的结构或词的顺序。

Passos para Implementar Bag of Words em Python

Para criar um modelo de bolsa de palavras, pegamos todas as palavras em um corpus e criamos uma coluna com cada palavra. As linhas representam as frases. Se uma certa palavra existe na frase, ela é representada por um 1, e se a palavra não existe, é representada por um 0. Cada palavra na coluna representa um único recurso.

No final, obtemos uma matriz esparsa. Uma matriz esparsa é uma matriz com muitos zeros.

P preprocessamento de dados

Para criar um modelo de Bolsa de Palavras em Python, precisamos seguir alguns passos de preprocessamento. Esses passos incluem a tokenização e a remoção de stopwords.

A tokenização é o processo de divisão de um pedaço de texto em unidades menores, geralmente palavras. Você pode realizar a tokenização usando NLTK

Palavras de parada são palavras comuns em inglês, como “the,” “that” e “a”, que não contribuem para a polaridade de uma frase.

import nltk from nltk.corpus import stopwords from nltk.tokenize import word_tokenize # Baixe as palavras vedadas e o tokenizer, se ainda não o fez nltk.download("punkt") nltk.download("stopwords") # Frase de exemplo sentence = "This is an example showing how to remove stop words from a sentence." # Tokenize a frase em palavras words = word_tokenize(sentence) # Obtenha a lista de palavras vedadas em inglês stop_words = set(stopwords.words("english")) # Remova as palavras vedadas da frase filtered_sentence = [word for word in words if word.lower() not in stop_words] # Volte a juntar as palavras em uma frase filtered_sentence = " ".join(filtered_sentence) print(filtered_sentence)

Saída:

example showing remove stop words sentence.

Criando um vocabulário

Um vocabulário é uma coleção de palavras únicas encontradas em um corpus de texto. Construir um vocabulário envolve reunir todas as palavras únicas do corpus e contar suas ocorrências. Este vocabulário é útil para várias tarefas de PLN, como modelagem de linguagem, embeddings de palavras e classificação de texto.

Este código abaixo cria uma distribuição de frequência simples de palavras no corpus, útil para tarefas básicas de PLN, como construir um vocabulário ou entender o conteúdo do texto:

  • O corpus variável contém algumas frases de exemplo. Em aplicações reais, isso zaweria conjuntos de dados de texto maiores e mais variados.
  • vocab = defaultdict(int) simplifica a contagem de frequência de palavras, inicializando automaticamente qualquer nova palavra com um contador de 0, permitindo incrementos diretos sem verificações.
  • Cada frase é tokenizada convertendo-a para minúsculas e extraíndo palavras usando expressões regulares. O padrão \b\w+\b identifica palavras com caracteres alfanuméricos apenas, ignorando pontuação e outros símbolos.
  • A contagem de cada palavra é atualizada no vocab dicionário.
  • O vocabulário é ordenado por frequência em ordem decrescente, facilitando a visualização das palavras mais comuns no topo, e é exibido para referência.
import re Importar o módulo de expressões regulares para ajudar no processamento de texto from collections import ( defaultdict, ) Importar defaultdict para lidar facilmente com a contagem de frequência de palavras Corpus de exemplo de texto - um pequeno conjunto de dados de frases para analisar corpus = [ "Tokenization is the process of breaking text into words.", "Vocabulary is the collection of unique words.", "The process of tokenizing is essential in NLP.", ] Inicializar um defaultdict com valores inteiro para armazenar frequências de palavras defaultdict(int) inicializa cada nova chave com um valor inteiro padrão de 0 vocab = defaultdict(int) Percorrer cada frase no corpus para tokenizar e normalizar for sentence in corpus: Converter a frase para minúsculas para garantir consistência na contagem (por exemplo, 'Tokenization' e 'tokenization' são tratadas como a mesma palavra) Usar expressões regulares para encontrar palavras compostas apenas por caracteres alfanuméricos words = re.findall(r"\b\w+\b", sentence.lower()) Para cada palavra encontrada, incrementar sua contagem no dicionário vocab for word in words: vocab[word] += 1 Converter o defaultdict vocab para um dicionário regular para lidar com ele mais facilmente e fazer a ordenação Ordenar o dicionário pela frequência de palavras em ordem decrescente e convertê-lo para um novo dicionário sorted_vocab = dict(sorted(vocab.items(), key=lambda x: x[1], reverse=True)) Exibir o vocabulário ordenado com cada palavra e sua contagem de frequência print("Vocabulary with Frequencies:", sorted_vocab)

Saída:

Vocabulary with Frequencies: {'is': 3, 'the': 3, 'of': 3, 'process': 2, 'words': 2, 'tokenization': 1, 'breaking': 1, 'text': 1, 'into': 1, 'vocabulary': 1, 'collection': 1, 'unique': 1, 'tokenizing': 1, 'essential': 1, 'in': 1, 'nlp': 1}

Construir manualmente um vocabulário pode ser demorado, especialmente para grandes corpora. O CountVectorizer do Scikit-learn automatiza esse processo e permite um processamento de texto mais flexível, como veremos mais tarde.

Implementação do Bag of Words Using Python (Do Zero)

Vamos começar com uma implementação simples do Bag of Words do zero em Python. Isso ajudará você a entender os blocos de construção e a mecânica de como ele funciona por baixo dos panos.

Implementação manual

Passo 1: Pré-processamento dos dados de texto

Vamos começar definindo uma função simples para processar o texto, incluindo tokenização, conversão para minúsculas e remoção de pontuação.

from collections import defaultdict import string # Dados de texto de exemplo: frases corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Função para pré-processar o texto def preprocess(text): # Converter para minúsculas text = text.lower() # Remover pontuação text = text.translate(str.maketrans("", "", string.punctuation)) # Tokenizar: dividir o texto em palavras tokens = text.split() return tokens # Aplicar pré-processamento ao corpus de exemplo processed_corpus = [preprocess(sentence) for sentence in corpus] print(processed_corpus)

Saída:

[['python', 'is', 'amazing', 'and', 'fun'], ['python', 'is', 'not', 'just', 'fun', 'but', 'also', 'powerful'], ['learning', 'python', 'is', 'fun']]

Passo 2: Construir Vocabulário

Agora, precisamos varrer todos os documentos e construir uma lista completa de palavras únicas, que é nosso vocabulário.

Inicialize um conjunto vazio para o vocabulário vocabulary = set() Construa o vocabulário for sentence in processed_corpus: vocabulary.update(sentence) Converta em uma lista ordenada vocabulary = sorted(list(vocabulary)) print("Vocabulary:", vocabulary)

Passo 3: Calcule as Frequências de Palavras e Vetorize

Agora calcularemos a frequência de cada palavra no vocabulário para cada documento no corpus processado.

def create_bow_vector(sentence, vocab): vector = [0] * len(vocab) Inicialize um vetor de zeros for word in sentence: if word in vocab: idx = vocab.index(word) Encontre o índice da palavra no vocabulário vector[idx] += 1 Aumente a contagem nesse índice return vector

Neste ponto, você terá criado uma representação Bag of Words para cada documento no seu corpus.

Crie o vetor BoW para cada frase no corpus processado bow_vectors = [create_bow_vector(sentence, vocabulary) for sentence in processed_corpus] print("Bag of Words Vectors:") for vector in bow_vectors: print(vector)

Saída:

Bag of Words Vectors: [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1] [1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1] [0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]

Usando o CountVectorizer do Scikit-learn

Construir um modelo de Bag of Words manualmente é bom para aprendizado, mas para aplicações de produção, você vai querer usar bibliotecas eficientes e otimizadas como Scikit-learn.

A função Python que usamos para tokenização é CountVectorizer, que é importada do sklearn.feature_extraction.text. Uma das características do CountVectorizer é max_features, que representa o número máximo de palavras que você gostaria de ter no modelo de saco de palavras. Neste caso, usamos None, o que significa que todas as características serão usadas. 

Depois de criar uma instância de CountVectorizer, use o método .fit_transform() para criar o modelo de saco de palavras. Em seguida, use o .toarray() para converter o modelo de saco de palavras em arrays numpy que podem ser alimentados a um modelo de aprendizado de máquina.

Una vez instalado, CountVectorizer construiu um dicionário de índices de características. O valor do índice de uma palavra no vocabulário está ligado à sua frequência em todo o corpus de treinamento.

from sklearn.feature_extraction.text import CountVectorizer # Corpus original corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Criar um objeto CountVectorizer vectorizer = CountVectorizer() # Ajustar e transformar o corpus X = vectorizer.fit_transform(corpus) # Imprimir o vocabulário gerado print("Vocabulary:", vectorizer.get_feature_names_out()) # Imprimir a matriz de Bag-of-Words print("BoW Representation:") print(X.toarray())

Saída:

markdownVocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] BoW Representation: [[0 1 1 0 1 1 0 0 0 0 1] [1 0 0 1 1 1 1 0 1 1 1] [0 0 0 0 1 1 0 1 0 0 1]]

Exemplo: Aplicando Bag of Words

Agora vamos aplicar o modelo BoW a um pequeno corpus de texto composto por três avaliações de filmes para ilustrar todo o processo.

Vamos usar o CountVectorizer do Scikit-learn para aplicar o modelo BoW a este pequeno corpus de texto.

Aqui estão os passos que vamos tomar:

  • CountVectorizer tokeniza o texto, remove a pontuação e converte as palavras para minúsculas automaticamente.
  • .fit_transform(corpus) converte o corpus em uma matriz documento-termo, onde cada linha representa um documento e cada coluna representa uma palavra do vocabulário.
  • X_dense é a matriz densa que representa a frequência de cada palavra em cada documento.
from sklearn.feature_extraction.text import CountVectorizer # Corpus de exemplo de avaliações de filmes corpus = [ "I loved the movie, it was fantastic!", "The movie was okay, but not great.", "I hated the movie, it was terrible.", ] # Inicializar o CountVectorizer vectorizer = CountVectorizer() # Ajustar e transformar o corpus em uma matriz documento-termo X = vectorizer.fit_transform(corpus) # Converter a matriz documento-termo em um formato denso (opcional para visualização) X_dense = X.toarray() # Obter o vocabulário (mapeamento de palavras para posições de índice) vocab = vectorizer.get_feature_names_out() # Imprimir o vocabulário e a matriz documento-termo print("Vocabulary:", vocab) print("Document-Term Matrix:\n", X_dense)

Saída:

Vocabulary: ['but' 'fantastic' 'great' 'hated' 'it' 'loved' 'movie' 'not' 'okay' 'terrible' 'the' 'was'] Document-Term Matrix: [[0 1 0 0 1 1 1 0 0 0 1 1] # Primeira avaliação: "Adorei o filme, foi fantasticamente!" [1 0 1 0 1 0 1 1 1 0 1 1] # Segunda avaliação: "O filme estava bom, mas não ótimo." [0 0 0 1 1 0 1 0 0 1 1 1]] # Terceira avaliação: "Odeiei o filme, foi péssimo."

Aqui está como podemos interpretar a saída acima:

  • Cada palavra única no corpus é atribuída a um índice, e as palavras são ordenadas alfabeticamente. Por exemplo, “mas” está no índice 0, “fantasticamente” está no índice 1, “filme” está no índice 6, e assim por diante.
  • Cada linha na matriz de documentos representa uma avaliação de filme, e cada coluna corresponde a uma palavra do vocabulário. Os valores na matriz representam a frequência de cada palavra naquele documento específico.
    • Avaliação Primeira: [0 1 0 0 1 1 1 0 0 0 1 1] indica que:
      • A palavra “fantasticamente” aparece uma vez (1 no índice 1),
      • A palavra “adorei” aparece uma vez (1 no índice 5),
      • A palavra “filme” aparece uma vez (1 no índice 6),
      • A palavra “foi” aparece uma vez (1 no índice 4),
      • E assim por diante.

O vetor BoW pode ser interpretado da seguinte forma:

  • Cada documento é um vetor de números representando contagens de palavras. As dimensões do vetor são iguais ao tamanho do vocabulário. Neste caso, o vocabulário tem 12 palavras, então cada avaliação é transformada em um vetor de 12 dimensões.
  • A maioria das palavras em cada linha são zeros porque nem todos os documentos contêm todas as palavras do vocabulário. Portanto, modelos BoW são frequentemente esparsos, ou seja, têm muitos zeros.

Vantagens e Limitações do Bag of Words

Vamos agora abordar algumas das vantagens e limitações do modelo Bag of Words.

Vantagens

  1. Simples de implementar e interpretar: O modelo Bag of Words é uma das técnicas mais diretas de representação de texto, tornando-se ideal para iniciantes. Sua simplicidade permite uma implementação rápida sem a necessidade de pré-processamento complexo ou modelos especializados.
  2. Fácil de usar para tarefas de classificação de texto: Bag of Words é bem adaptado para tarefas básicas como classificação de texto, análise de sentimento e detecção de spam. Essas tarefas geralmente não exigem modelos de linguagem sofisticados, então uma representação BOW é suficiente e eficiente.

Limitações

  1. A tamanho do vocabulário afeta a esparsidade das representações: Quanto maior o vocabulário, mais esparsa e de alta dimensão torna-se a representação. Essa esparsidade pode dificultar a aprendizagem eficaz dos modelos e requer um ajuste cuidadoso do tamanho do vocabulário para evitar custos computacionais excessivos.
  2. Produz matrizes esparsas que são caras computacionalmente: Como cada documento é representado pela frequência de cada palavra em um vocabulário possivelmente grande, as matrizes resultantes são frequentemente compostas mostly de zeros, o que pode ser ineficiente para armazenamento e processamento em pipelines de aprendizado de máquina. Matrizes esparsas consomem muita memória e geralmente requerem ferramentas e bibliotecas especializadas para armazenamento e computação eficiente, especialmente com grandes conjuntos de dados.
  3. Perde significado e contexto: BOW ignora a ordem das palavras e a estrutura das sentenças, resultando na perda de relações gramaticais e de significado. Essa limitação o torna menos adequado para tarefas onde o contexto, a nuance e a ordem das palavras são importantes, como tradução ou detecção de sentimento em sentenças complexas.

As seguintes estratégias podem ser usadas para diminuir o tamanho do vocabulário no Bag of Words:

  • Ignorar maiúsculas e minúsculas. 
  • Remover pontuações. 
  • Remover stopwords, ou seja, palavras comuns como “the” e “a”. 
  • Garantir que todas as palavras estejam corretamente soletradas. 
  • Usar técnicas de stemming para reduzir palavras à sua forma raiz. 

Próximos Passos: Além do Bag of Words

Uma limitação do modelo Bag of Words é que ele trata todas as palavras igualmente. Infelizmente, isso pode levar a problemas onde algumas palavras são dadas mais importância simplesmente porque aparecem com frequência. 

TF-IDF (Frequência do Termo-Inverso da Frequência do Documento) é uma solução para esse problema, pois ajusta o peso das palavras com base na frequência com que elas aparecem em todos os documentos. 

TF-IDF: Uma Extensão ao Bag of Words

Frequência do Termo (TF) representa a frequência de um termo em um documento. Frequência Inversa do Documento (IDF) reduz o impacto de palavras que ocorrem comumente em vários documentos. A pontuação TF-IDF é calculada multiplicando-se as duas métricas.

Considere um documento contendo 200 palavras, onde a palavra amor aparece 5 vezes. A TF (Frequência de Termo) para amor é então (5 / 200) = 0,025. Supondo que tivéssemos um milhão de documentos e a palavra amor ocorre em mil desses, a frequência inversa do documento (ou seja, IDF) é calculada como log(1000000 / 1000) = 3. O peso TF-IDF é o produto dessas quantidades: 0,025 * 3 = 0,075.

No Scikit-learn, isso é relativamente fácil de calcular usando a classe TfidfVectorizer.

from sklearn.feature_extraction.text import TfidfVectorizer # Corpus de exemplo corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Criar o vetORIZADOR TF-IDF tfidf_vectorizer = TfidfVectorizer() # Ajustar e transformar o corpus X_tfidf = tfidf_vectorizer.fit_transform(corpus) # Mostrar o Vocabulário print("Vocabulary:", tfidf_vectorizer.get_feature_names_out()) # Mostrar a Matriz TF-IDF print("TF-IDF Representation:") print(X_tfidf.toarray())

saída:

Vocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] TF-IDF Representation: [[0. 0.57292883 0.57292883 0. 0.338381 0.338381 0. 0. 0. 0. 0.338381 ] [0.40667606 0. 0. 0.40667606 0.24018943 0.24018943 0.40667606 0. 0.40667606 0.40667606 0.24018943] [0. 0. 0. 0. 0.41285857 0.41285857 0. 0.69903033 0. 0. 0.41285857]]

A matriz TF-IDF implementada acima fornece uma medida ponderada em vez de frequências brutas.

Embora o modelo de Bolsa de Palavras tenha suas limitações, especialmente para conjuntos de dados maiores e mais complexos, ele ainda é um bloco essencial em muitas aplicações de PLN. Entender isso ajudará você ao explorar modelos mais avançados como embeddings de palavras e Transformers.

A partir daqui, você poderia experimentar com BoW em seus projetos, incluindo detecção de spam, análise de sentimento, clustering de documentos e mais.

Se você quiser melhorias além da Bolsa de Palavras, pode explorar métodos como Word2Vec e GloVe, ou modelos de aprendizado profundo como BERT.

Pensamentos Finais

A técnica da Bolsa de Palavras é uma técnica fundamental utilizada no Processamento de Linguagem Natural. Ela serve como uma forma simples, mas eficaz, de converter texto não estruturado em características numéricas utilizáveis por algoritmos de aprendizado de máquina. Neste tutorial, abordamos:

  • O que é o modelo de Bolsa de Palavras (BoW)?
  • Os benefícios do modelo de Bolsa de Palavras na construção de modelos de aprendizado de máquina.
  • Como implementar o modelo de Bolsa de Palavras em Python.
  • Vantagens e limitações da Bolsa de Palavras.
  • A teoria e a motivação por trás do modelo de Bolsa de Palavras.
  • A introdução do TF-IDF como uma melhoria em relação à abordagem tradicional da Bolsa de Palavras.

Confira nossa trilha de Habilidades de Processamento de Linguagem Natural em Python, para aprofundar-se no processamento de linguagem natural.

Source:
https://www.datacamp.com/tutorial/python-bag-of-words-model