A Bolsa 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 de texto. O Python oferece várias ferramentas e bibliotecas para implementar a Bolsa de Palavras de maneira eficaz.
Neste tutorial, vamos mergulhar na 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 Bolsa de Palavras a problemas do mundo real. Se você é novo em PLN, confira nossa trilha de habilidades de Processamento de Linguagem Natural em Python para saber mais.
What is Bag of Words?
Bag of Words é 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 sentimentos. Isso é importante porque os algoritmos de aprendizado de máquina não conseguem processar dados textuais. O processo de converter o texto em números é conhecido como extração de características ou codificação de características.
Um Bag of Words é baseado na ocorrência de palavras em um documento. O processo começa com a identificação do vocabulário no texto e a medição de sua ocorrência. É chamado de “bag” porque a ordem e a estrutura das palavras não são consideradas, apenas sua ocorrência.
O modelo Bag of Words é diferente do modelo Continuous Bag of Words (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 dimensão que são valiosos para aplicações complexas de NLP onde o contexto das palavras é importante.
Aspecto |
BOW |
CBOV |
Propósito |
Contabiliza a ocorrência de cada palavra |
Prediz palavra-alvo com base no contexto |
Tipo de Saída |
<diy17 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 um grande corpus) |
Aplicações Típicas |
Classificação de texto, análise de sentimento |
Embeddings de palavras, tarefas de PLN que precisam de contexto |
Por que Usar Bag of Words?
Bag of Words é útil em muitos tarefas de PLN, 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 corpora de textos de pequeno a médio porte.
- Similaridade entre documentos: Pode ser usado para calcular a similaridade entre documentos de texto usando técnicas como a similaridade de 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, também há desvantagens, como não considerar a semântica, a estrutura das palavras ou a ordem das palavras.
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 pré-processamento. 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 fez isso 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] # Junte as palavras de volta 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 conteria dados textuais 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 apenas com caracteres alfanuméricos, ignorando pontuação e outros símbolos. - A contagem de cada palavra é atualizada no vocab dicionário.
- O vocabulário é ordenado pela 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 facilitar o manuseio da contagem de frequência de palavras Corpus de texto de exemplo - um pequeno conjunto 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 de inteiro para armazenar frequências de palavras defaultdict(int) inicializa cada nova chave com um valor de 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 comum para facilitar o manuseio e 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 trabalhoso, 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 Usando 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
Etapa 1: Pré-processamento dos Dados de Texto
Vamos começar definindo uma função simples para processar 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: sentenças corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Função para pré-processar 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']]
Etapa 2: Construir Vocabulário
Agora, precisamos varrer todos os documentos e construir uma lista completa de palavras únicas, que será 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)
Etapa 3: Calcule as Frequências de Palavras e Vectorize
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 Incremente a contagem naquele índice return vector
Neste ponto, você terá criado uma Representação de Bag of Words para cada documento no seu corpus.
Crie um 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 a 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 eficazes e otimizadas como Scikit-learn.
A função de 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 bolsa de palavras. Neste caso, usamos None, o que significa que todas as características serão usadas.
Após criar uma instância de CountVectorizer
, use o método .fit_transform(
) para criar o modelo de bolsa de palavras. Em seguida, use o .toarray()
para converter o modelo de bolsa 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 recursos. O valor do índice de uma palavra no vocabulário está vinculado à 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 seguir:
CountVectorizer
tokeniza o texto, remove pontuação e converte automaticamente as palavras para minúsculas..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 fantástico!" [1 0 1 0 1 0 1 1 1 0 1 1] # Segunda avaliação: "O filme estava bem, mas não foi ó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, “fantástico” está no índice 1, “filme” está no índice 6, e assim por diante.
- Cada linha na matriz do documento 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.
- Primeira Avaliação: [0 1 0 0 1 1 1 0 0 0 1 1] indica que:
- A palavra “fantástico” 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, os modelos BoW são frequentemente esparsos, ou seja, têm muitos zeros.
Vantagens e Limitações da Bolsa de Palavras
Vamos agora abordar algumas das vantagens e limitações do modelo Bolsa de Palavras.
Vantagens
- Simples de implementar e interpretar: O modelo Bolsa de Palavras é uma das técnicas de representação de texto mais diretas, tornando-o ideal para iniciantes. Sua simplicidade permite uma implementação rápida sem a necessidade de preprocessamento complexo ou modelos especializados.
- Fácil de usar para tarefas de classificação de texto: Bolsa de Palavras é bem adequada para tarefas básicas como classificação de texto, análise de sentimentos e detecção de spam. Essas tarefas frequentemente não requerem modelos de linguagem sofisticados, então uma representação BOW é suficiente e eficiente.
Limitações
- O tamanho do vocabulário afeta a esparsidade das representações: Quanto maior o vocabulário, mais esparsa e alta-dimensional se torna a representação. Essa esparsidade pode dificultar o aprendizado efetivo dos modelos e requer um ajuste cuidadoso do tamanho do vocabulário para evitar custos computacionais excessivos.
- Produz matrizes esparsas que são computacionalmente caras: Como cada documento é representado pela frequência de cada palavra em um vocabulário potencialmente grande, as matrizes resultantes são frequentemente compostas mostly por zeros, o que pode ser ineficiente para armazenar e processar em pipelines de aprendizado de máquina. Matrizes esparsas consomem muita memória e frequentemente requerem ferramentas e bibliotecas especializadas para armazenamento e computação eficiente, especialmente com grandes conjuntos de dados.
- Perde significado e contexto: BOW desconsidera a ordem das palavras e a estrutura da frase, o que resulta na perda de relações gramaticais e significado. Esta limitação torna-o menos adequado para tarefas onde o contexto, a nuances e a ordem das palavras importam, como tradução ou detecção de sentimento em frases complexas.
As seguintes estratégias podem ser utilizadas para reduzir o tamanho do vocabulário na Bolsa de Palavras:
- Ignorar maiúsculas e minúsculas.
- Remover pontuação.
- Remover stopwords, ou seja, palavras comuns como “o” e “um”.
- Garantir que todas as palavras estejam corretamente escritas.
- Usar técnicas de derivação para reduzir palavras à sua forma radical.
Próximos Passos: Além da Bolsa de Palavras
Uma limitação do modelo de Bolsa de Palavras é que ele trata todas as palavras de maneira igual. Infelizmente, isso pode levar a problemas onde algumas palavras recebem mais importância simplesmente porque aparecem com frequência.
TF-IDF (Frequência do Termo-Inversa da Frequência do Documento) é uma solução para esse problema, pois ajusta o peso das palavras com base em quão frequentemente elas aparecem em todos os documentos.
TF-IDF: Uma Extensão à Bolsa de Palavras
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 comuns em múltiplos documentos. A pontuação TF-IDF é calculada multiplicando as duas métricas.
Considere um documento contendo 200 palavras, onde a palavra amor aparece 5 vezes. A TF 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.
Em 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 vectorizador 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 lhe fornece uma medida ponderada em vez de frequências brutas.
Embora o modelo de Sacola 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ê pode 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 Sacola de Palavras, pode explorar métodos como Word2Vec e GloVe, ou modelos de aprendizado profundo como BERT.
Pensamentos Finais
A técnica do Saco de Palavras é uma técnica fundamental utilizada no Processamento de Linguagem Natural. Ela serve como uma maneira simples, porém eficaz, de converter texto não estruturado em características numéricas utilizáveis por algoritmos de aprendizado de máquina. Neste tutorial, abordamos:
- Como é o modelo de Saco de Palavras (BoW)?
- Os benefícios do modelo de Saco de Palavras na construção de modelos de aprendizado de máquina.
- Como implementar o modelo de Saco de Palavras em Python.
- Vantagens e limitações do Saco de Palavras.
- A teoria e motivação por trás do modelo de Saco de Palavras.
- A introdução do TF-IDF como uma melhoria em relação à abordagem tradicional do Saco 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