Machine Learning: Fundamentos de NLP

Última atualização: 2026-08-26

Por trás de cada avaliação há uma emoção — NLP permite que as máquinas leiam a raiva, decepção e alegria ocultas no feedback dos clientes.

1. O que você vai aprender


2. A história real de um gerente de atendimento ao cliente de e-commerce

(1) O problema: 5 mil avaliações por dia, impossíveis de analisar à mão

A plataforma do Bob recebe 5 mil avaliações de produtos todos os dias — positivas, negativas e sugestões, todas misturadas. Sua equipe de atendimento consegue analisar apenas 1% por amostragem, perdendo um grande número de problemas de qualidade. No mês passado, um lote defeituoso gerou 2 mil avaliações negativas, mas só foi descoberto 3 semanas depois, quando já havia causado 500 mil USD em perdas com devoluções. Dados massivos de texto são tanto uma mina de ouro quanto um campo minado.

(2) A solução com NLP

NLP pode analisar automaticamente o sentimento das avaliações, extrair palavras-chave de problemas e monitorar tendências de avaliações negativas em tempo real.

PYTHON
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline

pipe = Pipeline([
    ("tfidf", TfidfVectorizer(max_features=5000, ngram_range=(1, 2))),
    ("clf", LogisticRegression(max_iter=500)),
])
pipe.fit(X_train_reviews, y_train_sentiment)
print(f"Acurácia do sentimento: {pipe.score(X_test, y_test):.3f}")

(3) O resultado: problemas encontrados em 3 dias, taxa de devolução caiu 40%

Depois que o Bob começou a usar NLP para analisar avaliações automaticamente, o tempo entre descobrir um problema de qualidade e responder caiu de 3 semanas para 3 dias, a taxa de devolução caiu 40%, e ele economiza cerca de 1 milhão de USD por ano.


3. Pré-processamento de texto

(1) Tokenização e limpeza

▶ Exemplo: Pipeline de pré-processamento de texto

PYTHON
import re
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer, WordNetLemmatizer

import nltk
nltk.download("punkt_tab", quiet=True)
nltk.download("stopwords", quiet=True)
nltk.download("wordnet", quiet=True)

def preprocess_text(text):
    # Minúsculas
    text = text.lower()
    # Remover caracteres especiais e números
    text = re.sub(r"[^a-zA-Z\s]", "", text)
    # Tokenizar
    tokens = word_tokenize(text)
    # Remover stopwords
    stop_words = set(stopwords.words("english"))
    tokens = [t for t in tokens if t not in stop_words and len(t) > 2]
    # Stemming
    stemmer = PorterStemmer()
    tokens_stemmed = [stemmer.stem(t) for t in tokens]
    return " ".join(tokens_stemmed)

# Teste
reviews = [
    "This product is absolutely amazing! Best purchase ever.",
    "Terrible quality, broke after 2 days. Very disappointed.",
    "Decent product for the price, but shipping was slow.",
]

for review in reviews:
    cleaned = preprocess_text(review)
    print(f"Original: {review}")
    print(f"Limpo:  {cleaned}\n")

Saída:

TEXT 📖 Somente leitura
# Função definida com sucesso

▶ Exemplo: Tokenização de palavras (NLTK)

PYTHON
# Tokenização de palavras com NLTK
# import nltk
# nltk.download('punkt')
# from nltk.tokenize import word_tokenize
# text = "This product has great quality and fast shipping"
# tokens = word_tokenize(text)
# print(tokens)  # ['This', 'product', 'has', 'great', 'quality', 'and', 'fast', 'shipping']

# Para avaliações em português (cenário internacional)
from sklearn.feature_extraction.text import CountVectorizer

reviews = [
    "Ótimo notebook desempenho rápido",
    "Qualidade de tela terrível",
    "Bom preço entrega rápida",
]

vectorizer = CountVectorizer()
X_bow = vectorizer.fit_transform(reviews)
print(f"Vocabulário: {vectorizer.vocabulary_}")
print(f"Shape da matriz BoW: {X_bow.shape}")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso
Passo de pré-processamento Inglês Português
Tokenização NLTK/spaCy (divisão por espaços) NLTK/spaCy (com regras para acentos)
Stopwords NLTK stopwords NLTK stopwords (português)
Stemming PorterStemmer RSLPStemmer (removedor de sufixos)
Lemmatização WordNetLemmatizer spaCy lemmatizer (português)

4. Métodos de Representação de Texto

Transformar texto de uma "string" em um "vetor numérico" requer um pipeline de transformação de representação:

100%
graph LR
    TEXT[Texto Bruto] --> TOKEN[Tokenizar<br/>split / jieba] --> REMOVE[Remover Stopwords] --> STEM[Stem/Lematizar] --> BOW[Bag-of-Words<br/>Vetor de Contagem] --> TFIDF[TF-IDF<br/>Vetor Ponderado] --> EMBED[Word2Vec<br/>Embedding Denso]
    style BOW fill:#fff3cd
    style TFIDF fill:#d1ecf1
    style EMBED fill:#d4edda

(1) Bag-of-Words e TF-IDF

▶ Exemplo: Comparando três representações de texto

PYTHON
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
import numpy as np

reviews = [
    "great product fast delivery happy customer",
    "terrible quality broke disappointed waste money",
    "great quality decent price fast shipping",
    "awful product terrible experience never buy again",
    "excellent quality great value fast delivery",
]

labels = [1, 0, 1, 0, 1]  # 1=positivo, 0=negativo

# Método 1: Bag-of-Words (contagem)
bow = CountVectorizer()
X_bow = bow.fit_transform(reviews)
print(f"Tamanho do vocabulário BoW: {len(bow.vocabulary_)}")

# Método 2: TF-IDF
tfidf = TfidfVectorizer(max_features=1000)
X_tfidf = tfidf.fit_transform(reviews)
print(f"Shape TF-IDF: {X_tfidf.shape}")

# Método 3: N-gram (capturando frases)
tfidf_ngram = TfidfVectorizer(ngram_range=(1, 2), max_features=1000)
X_ngram = tfidf_ngram.fit_transform(reviews)
print(f"Shape TF-IDF com bigramas: {X_ngram.shape}")
print(f"Top bigramas: {[w for w in tfidf_ngram.get_feature_names_out() if ' ' in w][:10]}")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso
Representação Informação Dimensionalidade Caso de uso
BoW (frequência) Baixa Alta Classificação simples
TF-IDF Média Alta Padrão para classificação de texto
N-gram Média Muito alta Captura frases
Word2Vec Alta Baixa (100-300) Tarefas semânticas

(2) Intuição do TF-IDF


5. Embeddings de Palavras com Word2Vec

(1) Como o Word2Vec funciona

Word2Vec aprende vetores de palavras prevendo palavras de contexto (CBOW) ou prevendo contexto a partir de uma palavra (Skip-gram), de modo que palavras semanticamente similares terminem com vetores próximos.

▶ Exemplo: Treinando Word2Vec e similaridade de palavras

PYTHON
from gensim.models import Word2Vec
import numpy as np

# Treinar Word2Vec em corpus de exemplo
# Na prática, use corpus real de avaliações
sentences = [
    ["great", "product", "fast", "delivery", "happy"],
    ["terrible", "quality", "broke", "disappointed"],
    ["great", "quality", "decent", "price"],
    ["awful", "product", "terrible", "experience"],
    ["excellent", "quality", "great", "value"],
    ["fast", "shipping", "good", "price", "recommend"],
    ["poor", "quality", "slow", "delivery", "angry"],
    ["amazing", "product", "best", "purchase", "happy"],
]

model = Word2Vec(sentences, vector_size=50, window=3, min_count=1, workers=4, epochs=50)

# Similaridade de palavras
print("Similar a 'great':")
for word, sim in model.wv.most_similar("great", topn=5):
    print(f"  {word}: {sim:.3f}")

# Vetor de palavra
print(f"\nVetor para 'quality': {model.wv['quality'][:5]}... (50-dim)")

# Analogia: great - good + terrible = ?
# result = model.wv.most_similar(positive=["terrible"], negative=["good"], topn=3)

Saída:

TEXT 📖 Somente leitura
Similar a 
Parâmetro Significado Valor recomendado
vector_size Dimensionalidade do vetor 100-300
window Tamanho da janela de contexto 5
min_count Frequência mínima da palavra 5
sg 0=CBOW, 1=Skip-gram 1 (poucos dados)

▶ Exemplo: Visualizando embeddings de palavras

PYTHON
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

words = ["great", "terrible", "happy", "angry", "fast", "slow",
         "quality", "price", "product", "delivery"]

vectors = [model.wv[w] for w in words]
vectors_2d = PCA(n_components=2).fit_transform(vectors)

fig, ax = plt.subplots(figsize=(10, 8))
ax.scatter(vectors_2d[:, 0], vectors_2d[:, 1], s=100)
for i, word in enumerate(words):
    ax.annotate(word, (vectors_2d[i, 0], vectors_2d[i, 1]), fontsize=12)
ax.set_title("Visualização de Embeddings Word2Vec")
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("word2vec_vis.png", dpi=150)

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso

6. Análise de Sentimento em Avaliações de Produtos na Prática

▶ Exemplo: Fluxo completo de classificação de sentimento

PYTHON
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np

# Simular avaliações de produtos
rng = np.random.default_rng(42)

positive_templates = [
    "great product love it highly recommend",
    "excellent quality fast delivery satisfied",
    "amazing value best purchase ever happy",
    "good product decent price works well",
    "love this item perfect condition great",
]

negative_templates = [
    "terrible quality broke after one day",
    "awful product waste money very disappointed",
    "poor quality slow delivery never again",
    "worst purchase defective product angry",
    "bad product cheap material not recommend",
]

# Gerar 2000 avaliações
reviews = []
labels = []
for _ in range(1000):
    reviews.append(rng.choice(positive_templates))
    labels.append(1)
    reviews.append(rng.choice(negative_templates))
    labels.append(0)

X_train, X_test, y_train, y_test = train_test_split(reviews, labels, test_size=0.2, random_state=42)

# Pipeline TF-IDF + Regressão Logística
pipe = Pipeline([
    ("tfidf", TfidfVectorizer(max_features=5000, ngram_range=(1, 2), min_df=2)),
    ("clf", LogisticRegression(max_iter=500, C=1.0)),
])

pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)

print(f"Acurácia: {pipe.score(X_test, y_test):.4f}")
print(f"\nRelatório de Classificação:\n{classification_report(y_test, y_pred, target_names=['Negativo', 'Positivo'])}")

# Extrair palavras mais importantes para cada sentimento
feature_names = pipe.named_steps["tfidf"].get_feature_names_out()
coefs = pipe.named_steps["clf"].coef_[0]
top_positive = np.argsort(coefs)[-10:][::-1]
top_negative = np.argsort(coefs)[:10]

print("\nTop palavras positivas:")
for idx in top_positive:
    print(f"  {feature_names[idx]:20s}: {coefs[idx]:.3f}")

print("\nTop palavras negativas:")
for idx in top_negative:
    print(f"  {feature_names[idx]:20s}: {coefs[idx]:.3f}")

Saída:

TEXT 📖 Somente leitura
Top palavras positivas:
Top palavras negativas:
📌 Ponto-chave: As palavras com os maiores coeficientes são os indicadores mais fortes de sentimento positivo, enquanto as palavras com os menores coeficientes (mais negativos) são os indicadores mais fortes de sentimento negativo. Bob pode usar essas palavras-chave para monitorar tendências de avaliações e detectar rapidamente problemas de qualidade do produto.


❓ Perguntas Frequentes

P: Devo usar TF-IDF ou Word2Vec? R: Use TF-IDF para classificação de texto (simples, eficaz e interpretável); use Word2Vec para tarefas semânticas (similaridade/analogia); use embeddings pré-treinados (BERT, etc.) para aprendizado profundo. Comece com TF-IDF como iniciante.

P: Como escolher n para N-grams? R: Para classificação de texto, use (1,2), ou seja, unigramas + bigramas; bigramas importam muito para análise de sentimento (por exemplo, "não bom"); n maior (3+) geralmente não vale a pena (a dimensionalidade explode e os dados ficam esparsos).

P: Que ferramentas devo usar para tokenização em português? R: NLTK (com suporte para português), spaCy (com modelo pt_core_news_sm), ou Stanza. Para avaliações de e-commerce, adicione nomes de marcas e termos de domínio com um dicionário personalizado.

P: Quanta dados o Word2Vec precisa para treinar? R: Pelo menos 10 milhões de palavras para aprender vetores significativos. Com poucos dados, use vetores pré-treinados (por exemplo, Word2Vec do NILC) ou fique com TF-IDF.

P: Que acurácia conta como boa para análise de sentimento? R: Para classificação binária simples (positivo/negativo), TF-IDF + regressão logística normalmente alcança 80-85%; modelos profundos como BERT podem chegar a 90-95%. Mas em configurações de negócio reais com muitos dados ruidosos, 70-80% já é utilizável.

P: Como lidar com sarcasmo e negação implícita? R: Modelos simples (TF-IDF) têm dificuldade com isso. Você precisa — 1) adicionar mais features de N-gram; 2) usar modelos de linguagem pré-treinados (BERT); 3) anotar manualmente amostras sarcásticas para treinar um modelo dedicado.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Use TfidfVectorizer para vetorizar 5 avaliações de produtos, depois imprima o vocabulário e a matriz TF-IDF. Dica: consulte o exemplo na Seção 4.
  2. Intermediário (Dificuldade ⭐⭐): Construa um pipeline TF-IDF + LogisticRegression de classificação de sentimento e compare a diferença de F1 score entre apenas unigrama e (1,2)-grama. Dica: ngram_range=(1,1) vs (1,2).
  3. Desafio (Dificuldade ⭐⭐⭐): Implemente o sistema de insights de avaliações do Bob — depois de treinar o classificador de sentimento, extraia as top 20 palavras-chave negativas, ordene por frequência e produza um ranking de "problemas mais urgentes a corrigir". Dica: ordene coef_ + mapeie para nomes de features + conte frequências.

← Lição Anterior: Redução de Dimensionalidade | Próxima Lição: Introdução ao Aprendizado Profundo →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%