curso
Modelo de saco de palavras Python: Um guia completo
Bag of Words (BoW) é uma técnica de processamento de linguagem natural (NLP). É amplamente usado 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 a BoW é importante para qualquer pessoa que trabalhe com dados de texto. O Python oferece várias ferramentas e bibliotecas para que você implemente o Bag of Words com eficiência.
Neste tutorial, vamos nos aprofundar no BoW, apresentar seus conceitos, cobrir seus usos e fazer uma implementação detalhada em Python. Ao final deste tutorial, você poderá aplicar o modelo Bag of Words a problemas do mundo real. Se você é novo em PNL, confira nosso Processamento de linguagem natural em Python para que você saiba mais.
O que é o Bag of Words?
Bag of Words é uma técnica para extrair recursos de dados de texto 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 podem processar dados textuais. O processo de conversão do texto em números é conhecido como extração de recursos ou codificação de recursos.
Um Bag of Words é baseado na ocorrência de palavras em um documento. O processo começa com a localização do vocabulário no texto e a medição de sua ocorrência. Ele é 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 CBOW (Continuous Bag of Words Model), que aprende a incorporar palavras densas usando palavras ao redor para prever uma palavra-alvo, capturando relações semânticas entre as palavras. O CBOW requer treinamento em um grande corpus e produz vetores de baixa dimensão que são valiosos para aplicativos complexos de NLP em que o contexto da palavra é importante.
Aspecto |
BOW |
CBOW |
Finalidade |
Conta as ocorrências de cada palavra |
Prevê a palavra-alvo com base no contexto |
Tipo de saída |
Vetor esparso de alta dimensão |
Incorporação densa e de baixa dimensão |
Considera o contexto |
Não (ignora a ordem das palavras) |
Sim (usa palavras ao redor) |
Representação |
Vetor de frequência esparso |
Semântica de captura de vetor denso |
Complexidade |
Baixo (não é necessário treinamento) |
Alta (requer treinamento em um grande corpus) |
Aplicações típicas |
Classificação de texto, análise de sentimentos |
Embeddings de palavras, tarefas de PNL que precisam de contexto |
Por que usar o Bag of Words?
O Bag of Words é útil em muitas tarefas de tarefas de PNLAlguns motivos para seu uso incluem:
- Extração de recursos: Ele 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 texto de pequeno e médio porte.
- Similaridade de documentos: Ele 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, o BoW é eficaz para tarefas de classificação de texto, como classificação de spam e análise de sentimentos.
No entanto, também há desvantagens, como o fato de não considerar a semântica, a estrutura das palavras ou a ordem das palavras.
Etapas para implementar o Bag of Words em Python
Para criar um modelo de saco de palavras, pegamos todas as palavras em um corpus e criamos uma coluna com cada palavra. As linhas representam as frases. Se uma determinada palavra existir na frase, ela será representada por um 1 e, se a palavra não existir, será 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.
Pré-processamento de dados
Para criar um modelo Bag of Words em Python, precisamos realizar algumas etapas de pré-processamento. Essas etapas incluem a tokenização e a remoção de palavras de parada.
A tokenização é o processo de dividir um trecho de texto em unidades menores, geralmente palavras. Você pode realizar a tokenização usando o NLTK.
Stop words 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
# Download stopwords and tokenizer if you haven't already
nltk.download("punkt")
nltk.download("stopwords")
# Example sentence
sentence = "This is an example showing how to remove stop words from a sentence."
# Tokenize the sentence into words
words = word_tokenize(sentence)
# Get the list of stop words in English
stop_words = set(stopwords.words("english"))
# Remove stop words from the sentence
filtered_sentence = [word for word in words if word.lower() not in stop_words]
# Join the words back into a sentence
filtered_sentence = " ".join(filtered_sentence)
print(filtered_sentence)
Saída:
example showing remove stop words sentence.
Criação de um vocabulário
Um vocabulário é uma coleção de palavras únicas encontradas em um corpus de texto. A criação de um vocabulário envolve a coleta de todas as palavras exclusivas do corpus e a contagem de suas ocorrências. Esse vocabulário é útil para várias tarefas de PNL, como modelagem de linguagem, incorporação de palavras e classificação de texto.
O código abaixo cria uma distribuição de frequência simples de palavras no corpus, útil para tarefas básicas de NLP, como a criação de um vocabulário ou a compreensão do conteúdo do texto:
- A variável docorpus contém algumas frases de exemplo. Em aplicativos reais, isso conteria dados de texto maiores e mais variados.
- vocab =
defaultdict(int)
simplifica a contagem de frequência de palavras, inicializando automaticamente qualquer palavra nova com uma contagem de 0, permitindo a incrementação direta sem verificações. - Cada frase é tokenizada, convertendo-a em letras minúsculas e extraindo palavras usando expressões regulares. O padrão
\b\w+\b
identifica palavras apenas com caracteres alfanuméricos, ignorando a pontuação e outros símbolos. - A contagem de cada palavra é atualizada no vocab dicionário.
- O vocabulário é classificado por frequência em ordem decrescente, facilitando a visualização das palavras mais comuns na parte superior, e é exibido para referência.
import re
# Import the regular expressions module to help with text processing
from collections import (
defaultdict,
)
# Import defaultdict to easily handle word frequency counting
# Sample corpus of text - a small dataset of sentences to analyze
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.",
]
# Initialize a defaultdict with integer values to store word frequencies
# defaultdict(int) initializes each new key with a default integer value of 0
vocab = defaultdict(int)
# Loop through each sentence in the corpus to tokenize and normalize
for sentence in corpus:
# Convert the sentence to lowercase to ensure consistency in counting (e.g., 'Tokenization' and 'tokenization' are treated as the same word)
# Use regular expressions to find words composed of alphanumeric characters only
words = re.findall(r"\b\w+\b", sentence.lower())
# For each word found, increment its count in the vocab dictionary
for word in words:
vocab[word] += 1
# Convert the defaultdict vocab to a regular dictionary for easier handling and sorting
# Sort the dictionary by word frequency in descending order and convert it to a new dictionary
sorted_vocab = dict(sorted(vocab.items(), key=lambda x: x[1], reverse=True))
# Display the sorted vocabulary with each word and its frequency count
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}
A criação manual de um vocabulário pode consumir muito tempo, especialmente em corpora grandes. O CountVectorizer do Scikit-learn automatiza esse processo e permite um processamento de texto mais flexível, como veremos mais adiante.
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 do capô.
Implementação manual
Etapa 1: Pré-processamento dos dados de texto
Começaremos definindo uma função simples para processar o texto, incluindo tokenização, letras minúsculas e remoção de pontuação.
from collections import defaultdict
import string
# Sample text data: sentences
corpus = [
"Python is amazing and fun.",
"Python is not just fun but also powerful.",
"Learning Python is fun!",
]
# Function to preprocess text
def preprocess(text):
# Convert to lowercase
text = text.lower()
# Remove punctuation
text = text.translate(str.maketrans("", "", string.punctuation))
# Tokenize: split the text into words
tokens = text.split()
return tokens
# Apply preprocessing to the sample corpus
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: Criar vocabulário
Agora, precisamos examinar todos os documentos e criar uma lista completa de palavras exclusivas, que é o nosso vocabulário.
# Initialize an empty set for the vocabulary
vocabulary = set()
# Build the vocabulary
for sentence in processed_corpus:
vocabulary.update(sentence)
# Convert to a sorted list
vocabulary = sorted(list(vocabulary))
print("Vocabulary:", vocabulary)
Etapa 3: Calcular frequências de palavras e vetorizar
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) # Initialize a vector of zeros
for word in sentence:
if word in vocab:
idx = vocab.index(word) # Find the index of the word in the vocabulary
vector[idx] += 1 # Increment the count at that index
return vector
Neste ponto, você terá criado uma representação do Bag of Words para cada documento do seu corpus.
# Create BoW vector for each sentence in the processed corpus
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
Criar um modelo de saco de palavras manualmente é bom para o aprendizado, mas para aplicativos de produção, você deverá usar bibliotecas eficientes e otimizadas, como Scikit-learn.
A função Python que usamos para a tokenização é CountVectorizerque é importada do site sklearn.feature_extraction.text
. Um dos recursos do CountVectorizer
é max_features
, que representa o número máximo de palavras que você gostaria de ter no modelo de saco de palavras. Nesse caso, usamos None, o que significa que todos os recursos serão usados.
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 site .toarray()
para converter o modelo de saco de palavras em matrizes numpy que podem ser alimentadas em um modelo de aprendizado de máquina.
Uma vez ajustado, o CountVectorizer criou 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
# Original corpus
corpus = [
"Python is amazing and fun.",
"Python is not just fun but also powerful.",
"Learning Python is fun!",
]
# Create a CountVectorizer Object
vectorizer = CountVectorizer()
# Fit and transform the corpus
X = vectorizer.fit_transform(corpus)
# Print the generated vocabulary
print("Vocabulary:", vectorizer.get_feature_names_out())
# Print the Bag-of-Words matrix
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 o Bag of Words
Vamos agora aplicar o modelo BoW a um pequeno corpus de texto composto por três resenhas de filmes para ilustrar todo o processo.
Usaremos o CountVectorizer do Scikit-learn para aplicar o modelo BoW a esse pequeno corpus de texto.
Aqui estão as etapas que você seguirá:
CountVectorizer
tokeniza o texto, remove a pontuação e coloca as palavras em letras minúsculas automaticamente..fit_transform(corpus)
converte o corpus em uma matriz documento-termo, em que 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
# Sample corpus of movie reviews
corpus = [
"I loved the movie, it was fantastic!",
"The movie was okay, but not great.",
"I hated the movie, it was terrible.",
]
# Initialize the CountVectorizer
vectorizer = CountVectorizer()
# Fit and transform the corpus to a document-term matrix
X = vectorizer.fit_transform(corpus)
# Convert the document-term matrix into a dense format (optional for visualization)
X_dense = X.toarray()
# Get the vocabulary (mapping of words to index positions)
vocab = vectorizer.get_feature_names_out()
# Print the vocabulary and document-term matrix
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] # First review: "I loved the movie, it was fantastic!"
[1 0 1 0 1 0 1 1 1 0 1 1] # Second review: "The movie was okay, but not great."
[0 0 0 1 1 0 1 0 0 1 1 1]] # Third review: "I hated the movie, it was terrible."
Veja como podemos interpretar o resultado acima:
- Cada palavra única no corpus recebe um índice, e as palavras são ordenadas alfabeticamente. Por exemplo, "but" está no índice 0, "fantastic" está no índice 1, "movie" está no índice 6 e assim por diante.
- Cada linha da matriz de documentos representa uma crítica de filme, e cada coluna corresponde a uma palavra do vocabulário. Os valores na matriz representam a frequência de cada palavra nesse documento específico.
- Primeira revisão: [0 1 0 0 0 1 1 1 0 0 0 0 1 1] indica que:
- A palavra "fantastic" aparece uma vez (1 no índice 1),
- A palavra "loved" aparece uma vez (1 no índice 5),
- A palavra "movie" aparece uma vez (1 no índice 6),
- A palavra "it" 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 que representa a contagem de palavras. As dimensões do vetor são iguais ao tamanho do vocabulário. Nesse caso, o vocabulário tem 12 palavras, portanto, cada revisão é transformada em um vetor de 12 dimensões.
- A maioria das palavras em cada linha é zero porque nem todo documento contém todas as palavras do vocabulário. Por isso, os modelos BoW geralmente são 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
- Simples de implementar e interpretar: O modelo Bag of Words é uma das técnicas de representação de texto mais simples, o que o torna ideal para iniciantes. Sua simplicidade permite a implementação rápida sem a necessidade de pré-processamento complexo ou modelos especializados.
- Fácil de usar para tarefas de classificação de texto: O Bag of Words é adequado para tarefas básicas, como classificação de texto, análise de sentimentos e detecção de spam. Essas tarefas geralmente não requerem modelos de linguagem sofisticados, portanto, 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 de alta dimensão se torna a representação. Essa dispersão pode dificultar o aprendizado eficaz dos modelos e exige 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 geralmente são, em sua maioria, zeros, o que pode ser ineficiente para armazenar e processar em pipelines de aprendizado de máquina. As matrizes esparsas consomem muita memória e geralmente exigem ferramentas e bibliotecas especializadas para armazenamento e computação eficientes, especialmente com grandes conjuntos de dados.
- Você perde o significado e o contexto: A BOW desconsidera a ordem das palavras e a estrutura das frases, o que resulta na perda das relações gramaticais e do significado. Essa limitação o torna menos adequado para tarefas em que o contexto, a nuance e a ordem das palavras são importantes, como a tradução ou a detecção de sentimentos em frases complexas.
As estratégias a seguir podem ser usadas para diminuir o tamanho do vocabulário no Bag of Words:
- Ignorando o caso.
- Remoção de pontuações.
- Remoção de stopwords, ou seja, palavras comuns, como the e a.
- Garantir que todas as palavras sejam escritas corretamente.
- Usar técnicas de stemming para reduzir as palavras à sua forma de raiz.
Próximas etapas: Além do saco de palavras
Uma limitação do modelo Bag of Words é que ele trata todas as palavras da mesma forma. Infelizmente, isso pode levar a problemas em que algumas palavras recebem mais importância simplesmente porque aparecem com frequência.
O TF-IDF (Term Frequency-Inverse Document Frequency) é 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 do Bag of Words
A frequência de termos (TF) representa a frequência de um termo em um documento. A Frequência Inversa de Documentos (IDF) reduz o impacto das palavras que ocorrem comumente em vários documentos. A pontuação TF-IDF é calculada pela multiplicação das duas métricas.
Considere um documento com 200 palavras, em que a palavra amor aparece 5 vezes. A TF para amor é então (5 / 200) = 0,025. Supondo que tenhamos um milhão de documentos e que a palavra love ocorra em mil deles, a frequência inversa de documentos (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
# Sample corpus
corpus = [
"Python is amazing and fun.",
"Python is not just fun but also powerful.",
"Learning Python is fun!",
]
# Create the Tf-idf vectorizer
tfidf_vectorizer = TfidfVectorizer()
# Fit and transform the corpus
X_tfidf = tfidf_vectorizer.fit_transform(corpus)
# Show the Vocabulary
print("Vocabulary:", tfidf_vectorizer.get_feature_names_out())
# Show the TF-IDF Matrix
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 a você uma medida ponderada em vez de frequências brutas.
Embora o modelo Bag of Words tenha suas limitações, especialmente para conjuntos de dados maiores e mais complexos, ele ainda é um componente essencial em muitos aplicativos de NLP. Entendê-lo ajudará você a explorar modelos mais avançados, como word embeddings e Transformers.
A partir daí, você pode experimentar o BoW em seus projetos, incluindo detecção de spam, análise de sentimentos, agrupamento de documentos e muito mais.
Se quiser melhorar ainda mais além do Bag of Words, você pode explorar métodos como Word2Vec e GloVe, ou modelos de aprendizagem profunda como o BERT.
Considerações finais
A técnica Bag of Words é uma técnica fundamental usada no processamento de linguagem natural. Ele serve como uma maneira simples e eficaz de converter texto não estruturado em recursos numéricos utilizáveis por algoritmos de aprendizado de máquina. Neste tutorial, abordamos o assunto:
- O que é o modelo Bag of Words (BoW)?
- Os benefícios do modelo Bag of Word na criação de modelos de aprendizado de máquina.
- Como implementar o modelo Bag of Words em Python.
- Vantagens e limitações do Bag of Words.
- A teoria e a motivação por trás do modelo Bag of Words.
- Apresentando o TF-IDF como um aprimoramento da abordagem tradicional do Bag of Words.
Confira nosso curso de habilidades em Processamento de linguagem natural em Python para se aprofundar no processamento de linguagem natural.
Principais cursos da DataCamp
programa
Natural Language Processing
curso
Feature Engineering for NLP in Python
tutorial
Stemming e lematização em Python
tutorial
Desenvolvimento de back-end em Python: Um guia completo para iniciantes
Oluseye Jeremiah
26 min
tutorial
Tutorial de análise de sentimentos com NLTK para iniciantes
tutorial
Entendendo a classificação de textos em Python
tutorial
Tutorial de compreensão de dicionário Python
tutorial