Desmistificando PLN e NLTK: Um guia passo a passo para iniciantes

Atualmente, onde todos os principais setores, desde saúde até finanças e de comércio eletrônico até manufatura, dependem de ciência de dados e inteligência artificial, compreender a linguagem humana surgiu como uma tarefa crucial. O Processamento de Linguagem Natural (PLN) ainda está na vanguarda dessa fronteira nebulosa entre linguística e ciência da computação.

🕒 Tempo estimado de leitura: 15 minutos

O Processamento de Linguagem Natural (PLN) é um campo fascinante na intersecção entre ciência da computação, inteligência artificial e linguística. Ele permite que os computadores entendam, interpretem e gerem linguagem humana. Para qualquer um que queira mergulhar no PLN usando Python, o Natural Language Toolkit (NLTK) é um excelente ponto de partida. Aqui, mostraremos os tópicos em PLN usando NLTK e terminaremos com um exemplo prático de análise de sentimentos.

Todos os exemplos também são explicados aqui 👨‍🔬, um notebook Google Colab para tornar seu aprendizado ainda mais interativo.

Entendendo o Processamento de Linguagem Natural (PLN)

PLN é um domínio dentro da inteligência artificial (IA) que se concentra na interação entre computadores e linguagens humanas. Ele permite que máquinas leiam, decifrem, entendam e produzam linguagem humana de uma forma valiosa. O PLN combina linguística computacional — modelagem baseada em regras da linguagem humana — com modelos estatísticos, de aprendizado de máquina e de deep learning.

O PLN abrange vários métodos e algoritmos que permitem que uma máquina entenda 🤖 e interprete as nuances da linguagem humana 🗣️. Os principais objetivos incluem:

  • Permitir que máquinas entendam a linguagem humana.

  • Construir sistemas que podem traduzir 🌐, resumir 📝 e mapear relacionamentos entre diferentes idiomas 💬.

  • Automatizar tarefas como classificação de texto 📚, análise de sentimentos 😊😢 e geração de linguagem.

Aplicações do mundo real de PLN

  • Otimização de mecanismos de busca (SEO): mecanismos de busca usam algoritmos de PLN para entender consultas de pesquisa e conteúdo da web, fornecendo assim os resultados mais relevantes.

  • Tradução automática: ferramentas como o Google Translate empregam PLN para traduzir texto de um idioma para outro com precisão impressionante.

  • Chatbots e assistentes virtuais: Siri, Alexa e outros assistentes baseados em IA aproveitam a PLN para entender as solicitações do usuário e fornecer respostas apropriadas.

  • Análise de sentimentos: isso é usado em mídias sociais para avaliar como as pessoas se sentem sobre diferentes produtos, serviços ou eventos.

  • Detecção de spam: provedores de e-mail usam PLN para identificar e filtrar mensagens de spam de forma eficaz.

  • Reconhecimento de fala: converte palavras faladas em texto, um recurso essencial em sistemas ativados por voz.

  • Classificação de texto: categoriza documentos em categorias específicas, como artigos de notícias ou tíquetes de suporte ao cliente.

  • Reconhecimento de Entidade Nomeada (NER): Identifica e categoriza entidades como nomes, datas e locais dentro do texto.

Terminologias essenciais em PLN

Antes de se aprofundar, é útil se familiarizar com alguns termos críticos em PLN:

  • Tokenização: Dividir o texto em unidades menores, normalmente palavras ou frases.

  • Raiz e lematização: Reduzir palavras à sua forma base ou raiz.

  • Reconhecimento de entidade nomeada (NER): Identificar e classificar informações-chave (entidades) no texto.

  • Corpus: Um conjunto grande e estruturado de textos usados ​​para treinamento e teste.

Apresentando o Natural Language Toolkit (NLTK)

Para navegar no intrincado labirinto do Processamento de Linguagem Natural (NLP), ferramentas sofisticadas são essenciais, e o NLTK (Natural Language Toolkit) se destaca como um ativo significativo no ecossistema de programação Python.

Esta biblioteca de código aberto simplifica várias tarefas de processamento de texto, oferecendo recursos para tokenização, stemming, lematização e muito mais. O NLTK é equipado com diversos corpora e recursos lexicais, como o WordNet, e suporta uma variedade de algoritmos de classificação de texto úteis para aplicativos como análise de sentimentos e detecção de spam

O NLTK é um rico recurso educacional, fornecendo extensa documentação e tutoriais, tornando-o um excelente ponto de entrada para iniciantes. A flexibilidade da biblioteca acomoda necessidades básicas e sofisticadas de processamento de texto, escalando com a experiência do usuário.

Introdução ao NLTK

Para começar a usar o NLTK, você precisará instalá-lo. Isso pode ser feito facilmente com pip:

# Primeiro, precisamos importar os módulos necessários da biblioteca NLTK.
!pip install nltk

Após concluir a instalação, você precisará baixar os dados NLTK necessários. Você pode fazer isso por meio de um script Python ou de um shell interativo.

import nltk # Importando a biblioteca nltk, que significa Natural Language Toolkit

# Baixando todo o conjunto de dados nltk. Isso inclui muitos recursos diferentes, como corpora, tokenizadores, modelos treinados, etc.
# É útil para várias tarefas de processamento de linguagem natural (NLP).
nltk.download('all')

Tokenização

A tokenização é o processo de dividir um texto em unidades menores chamadas tokens, que podem ser palavras, subpalavras ou caracteres. Este é o primeiro passo na PLN e é crucial porque converte o texto de entrada em pedaços gerenciáveis ​​que podem ser processados ​​posteriormente. Sem a tokenização, o texto é apenas uma sequência de caracteres, o que não é útil para a maioria das tarefas de processamento de linguagem. Ela permite que o sistema entenda e trabalhe em cada palavra ou token individualmente, tornando possível a análise subsequente.

# Importando módulos necessários do pacote Natural Language Toolkit (nltk).
import nltk
from nltk.tokenize import word_tokenize, sent_tokenize

# Definindo uma variável de string 'text' que contém o texto que queremos processar.
text = "NLTK é uma plataforma de ponta para criar software Python que processa dados de linguagem humana."

# A função sent_tokenize de nltk.tokenize divide o texto em uma lista de frases.
sentences = sent_tokenize(text)

# Imprimindo a lista de frases obtidas após a tokenização.
print("Sentenças:", sentences)

# A função word_tokenize de nltk.tokenize divide o texto em uma lista de palavras.
words = word_tokenize(texto, language='portuguese')

# Imprimindo a lista de palavras obtidas após a tokenização.
print("Palavras:", words)

Executar o código acima produzirá a seguinte saída.

Sentenças: ['NLTK é uma plataforma de ponta para criar software Python que processa dados de linguagem humana.']
Palavras: ['Os', 'meninos', 'estão', 'brincando', 'no', 'parque', '.', 'As', 'meninas', 'brincariam', 'também', 'se', 'não', 'estivesse', 'chovendo', '.']

Removendo Stopwords

Stopwords são palavras comuns em um idioma (como "o", "é", "em", etc.) que carregam muito pouca informação útil para certas tarefas como classificação de texto. Remover stopwords ajuda a reduzir a dimensionalidade dos dados e melhora a eficiência dos algoritmos. Isso permite que o sistema se concentre nas palavras mais significativas que provavelmente contribuirão com informações mais significativas para tarefas como análise de sentimento ou modelagem de tópicos.

from nltk.corpus import stopwords # Importe o módulo stopwords do Natural Language Toolkit (nltk)

# Stop words são palavras comuns como 'um', 'uma', 'à', etc., que geralmente são filtradas no processamento de texto
# Crie um conjunto de stop words em Português usando a lista predefinida do nltk
stop_words = set(stopwords.words('portuguese')) 

# Uma compreensão de lista que mantém apenas as palavras não encontradas no conjunto de stop words
filtered_words = [word for word in words if word.lower() not in stop_words]

# Imprima a lista de palavras filtradas
print("Palavras filtradas:", filtered_words) 

Executar o código acima produzirá a seguinte saída.

Palavras filtradas: ['NLTK', 'plataforma', 'ponta', 'criar', 'software', 'Python', 'processa', 'dados', 'linguagem', 'humana', '.']

Stemming

Stemming é o processo de reduzir palavras à sua forma base ou raiz. Por exemplo, "brincando" se torna "brinc". Isso é importante porque diferentes formas de uma palavra devem ser idealmente reconhecidas como a mesma palavra em muitas tarefas de PLN. Ao reduzir palavras às suas raízes, podemos tratar "brincando", "brincar" e "brincadeira" como instâncias do mesmo conceito base, o que melhora a consistência dos dados e aprimora o desempenho dos modelos de aprendizado de máquina.

# Importar as bibliotecas necessárias
from nltk.tokenize import word_tokenize
from nltk.stem import RSLPStemmer
import nltk

texto = "Os meninos estão brincando no parque. As meninas brincariam também se não estivesse chovendo."

# Tokenize o texto em palavras individuais usando a função 'word_tokenize'
# Isso divide a frase em uma lista de palavras e sinais de pontuação
palavras = word_tokenize(texto, language='portuguese')

# Inicializar o stemmer para Português (RSLPStemmer)
stemmer = RSLPStemmer()

# Aplicar a stemização em cada palavra
palavras_stemizadas = [stemmer.stem(palavra) for palavra in palavras]

# Imprima as listas de palavras
print("Palavras originais:", palavras)
print("Palavras stemizadas:", palavras_stemizadas)

Executar o código acima produzirá a seguinte saída.

Palavras originais: ['Os', 'meninos', 'estão', 'brincando', 'no', 'parque', '.', 'As', 'meninas', 'brincariam', 'também', 'se', 'não', 'estivesse', 'chovendo', '.']
Palavras stemizadas: ['os', 'menin', 'est', 'brinc', 'no', 'parqu', '.', 'as', 'menin', 'brinc', 'também', 'se', 'não', 'estiv', 'chov', '.']

Marcação de Partes do Discurso (POS)

A marcação de POS envolve rotular cada palavra em uma frase com sua parte do discurso correspondente (por exemplo, substantivo, verbo, adjetivo). Isso é importante porque fornece informações sintáticas que podem ser cruciais para entender a estrutura e o significado das frases. Por exemplo, saber se "gosto" é usado como substantivo ou verbo pode mudar como a frase é analisada e entendida. A marcação de POS é fundamental para tarefas como análise sintática, reconhecimento de entidade nomeada e análise de sentimentos.

Exemplo:

  • Como verbo: Eu gosto de chocolate.

  • Como substantivo: O gosto do chocolate é maravilhoso.

⚠️ O NLTK não possui, por padrão, um tagger nativo para Português. No entanto, podemos utilizar a biblioteca spacy que possui um modelo para Português, ou ainda adicionar um tagger treinado para a NLTK, como o MacMorpho.

Abaixo está um exemplo utilizando nltk com um tagger treinado em Português com base no corpus MacMorpho:

# Importar as funções necessárias do nltk
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import mac_morpho
from nltk.tag import UnigramTagger

# Baixar os recursos necessários uma única vez (se ainda não tiver feito)
nltk.download('mac_morpho')
nltk.download('punkt')

# Texto para ser analisado
texto = "NLTK é uma plataforma líder para construção de programas Python."

# Tokenizar o texto em palavras individuais
tokens = word_tokenize(texto, language='portuguese')

# Treinar um tagger unigram usando o corpus MacMorpho
train_sents = mac_morpho.tagged_sents()
unigram_tagger = UnigramTagger(train_sents)

# Aplicar a marcação de classe gramatical à lista de tokens
tagged_tokens = unigram_tagger.tag(tokens)

# Imprimir a lista de tuplas com tokens e suas tags POS no console
print(tagged_tokens)

Executar o código acima produzirá a seguinte saída.

[('NLTK', None), ('é', 'V'), ('uma', 'ART'), ('plataforma', 'N'), ('líder', 'N'), ('para', 'PREP'), ('construção', 'N'), ('de', 'PREP'), ('programas', 'N'), ('Python', 'NPROP'), ('.', '.')]

Aqui está o que cada tag POS representa:

  • ('NLTK', None): NLTK não foi identificado no corpus de treinamento, por isso não recebeu nenhuma tag (None).

  • ('é', 'V'): é foi identificado como um verbo (V).

  • ('uma', 'ART'): uma foi identificado como um artigo (ART).

  • ('plataforma', 'N'): plataforma foi identificado como um substantivo (N).

  • ('líder', 'N'): líder foi identificado como um substantivo (N).

  • ('para', 'PREP'): para foi identificado como uma preposição (PREP).

  • ('construção', 'N'): construção foi identificado como um substantivo (N).

  • ('de', 'PREP'): de foi identificado como uma preposição (PREP).

  • ('programas', 'N'): programas foi identificado como um substantivo (N).

  • ('Python', 'NPROP'): Python foi identificado como um nome próprio (NPROP).

  • ('.', '.'): . foi identificado como um ponto final (.)

Named Entity Recognition (NER)

NER é a tarefa de identificar e classificar nomes próprios em texto em categorias predefinidas, como nomes de pessoas, organizações, locais, etc. Isso é essencial para extrair informações estruturadas de dados de texto não estruturados. Por exemplo, em um artigo de notícias, identificar menções de empresas, datas e lugares pode ajudar a entender o contexto e as especificidades do artigo. É vital para recuperação de informações, sistemas de resposta a perguntas e representação de conhecimento.

⚠️ Infelizmente a função ne_chunk do NLTK não funciona diretamente com o Português. É necessário usar uma ferramenta diferente ou um pacote adicional que suporte NER em Português. Um dos pacotes amplamente utilizados para esse propósito é o spaCy, que tem suporte robusto para múltiplos idiomas, incluindo o Português.

# "spacy download" é ​​o comando fornecido pelo pacote SpaCy para baixar um de seus modelos de linguagem pré-treinados.
# "pt_core_news_sm" é o identificador para o modelo de linguagem específico que você está baixando. Neste caso,
# é o pequeno ("sm") modelo português ("pt") voltado para texto de notícias ("core").
!python -m spacy download pt_core_news_sm
# Importar spacy e baixar o modelo de linguagem português se necessário
import spacy

# Baixe o modelo português se você ainda não tiver
# Você deve executar esta linha de comando em seu terminal para baixar o modelo:
# python -m spacy download pt_core_news_sm

# Carregar o modelo de linguagem português
nlp = spacy.load('pt_core_news_sm')

# O texto no qual queremos executar o NER.
text = "O Google está sediado em Mountain View, Califórnia."

# Processar o texto para reconhecimento de entidade nomeada
doc = nlp(text)

# Imprimir as entidades nomeadas encontradas no texto
for ent in doc.ents:
    print(ent.text, ent.label_)

Executar o código acima produzirá a seguinte saída.

Google ORG
Mountain View LOC
Califórnia LOC

One-Hot Encoding

One-Hot Encoding é uma técnica para representar dados categóricos como vetores binários. Em PLN, é frequentemente usada para representar palavras de uma forma que as máquinas possam entender. Cada palavra no vocabulário é representada como um vetor com todos os zeros, exceto um único um no índice correspondente a essa palavra. Isso é importante porque os modelos de aprendizado de máquina exigem entrada numérica, e a codificação one-hot fornece uma maneira direta de converter texto em formato numérico. No entanto, vale a pena notar que a codificação one-hot pode não ser viável para vocabulários muito grandes devido a restrições de memória, e técnicas como incorporações de palavras são frequentemente usadas em seu lugar.

Existem também técnicas sofisticadas como Word2Vec ou GloVe que podem ser usadas para incorporações de palavras. Vamos mergulhar em uma demonstração direta de como a codificação one-hot pode ser implementada em Python:

# Defina uma sequência de texto de exemplo
text = "Este é um exemplo simples de codificação one-hot."

# Divida o texto em uma lista de palavras, usando espaços como delimitador
words = text.split()

# Crie um conjunto de palavras exclusivas da lista de palavras para formar o vocabulário.
# `set` remove automaticamente quaisquer palavras duplicadas.
vocab = set(words)

# Inicialize um dicionário vazio para manter as codificações one-hot para cada palavra
one_hot_encoding = {}

# Itere sobre o vocabulário usando enumerate para obter tanto o índice (i) quanto a palavra
for i, word in enumerate(vocab):
  # Crie uma codificação one-hot para a palavra atual.
  # Esta é uma lista de 0s e 1s onde apenas a posição correspondente ao
  # índice da palavra é 1, e todas as outras posições são 0.
  # [1 if i == j else 0 for j in range(len(vocab))] é uma compreensão de lista
  # que gera o vetor one-hot.
  one_hot_encoding[word] = [1 if i == j else 0 for j in range(len(vocab))]

# Imprima a codificação one-hot para cada palavra no vocabulário
# O formato `f"{word}: {encoding}"` é uma f-string para formatação de string mais fácil
for word, encoding in one_hot_encoding.items():
  print(f"{word}: {encoding}")

Executar o código acima produzirá a seguinte saída.

um: [1, 0, 0, 0, 0, 0, 0, 0]
Este: [0, 1, 0, 0, 0, 0, 0, 0]
simples: [0, 0, 1, 0, 0, 0, 0, 0]
de: [0, 0, 0, 1, 0, 0, 0, 0]
codificação: [0, 0, 0, 0, 1, 0, 0, 0]
exemplo: [0, 0, 0, 0, 0, 1, 0, 0]
é: [0, 0, 0, 0, 0, 0, 1, 0]
one-hot.: [0, 0, 0, 0, 0, 0, 0, 1]
Explicação:
  • Divisão de texto: O texto é dividido em palavras individuais.

  • Criação de vocabulário: Identifique e liste as palavras únicas do texto.

  • Codificação One-Hot: Atribua um vetor de codificação one-hot exclusivo a cada palavra no vocabulário. Este vetor terá um comprimento igual ao número de palavras no vocabulário. Ele conterá um 1 na posição correspondente à palavra e 0s em outros lugares.

  • Exibição de resultados: Imprima cada palavra junto com seu vetor de codificação one-hot correspondente.

Observações:
  • Limitações: A codificação one-hot resulta em vetores esparsos, que não capturam as relações semânticas entre as palavras.

  • Métodos alternativos: Técnicas como Word2Vec, GloVe ou modelos pré-treinados como BERT oferecem representações vetoriais densas que encapsulam o significado semântico e o contexto das palavras.

Projeto em Ação: Da Teoria à Prática

Agora que você aprendeu os tópicos em PLN usando NLTK, vamos juntar tudo em um projeto. Criaremos uma ferramenta básica de análise de sentimentos que classifica o texto como positivo ou negativo. Exploraremos como executar a análise de sentimentos com a biblioteca Hugging Face Transformers usando a função pipeline.

A biblioteca Transformers do Hugging Face oferece modelos pré-treinados acessíveis para inúmeras tarefas de processamento de linguagem natural, como análise de sentimentos. Neste guia, utilizaremos a função pipeline para analisar o sentimento de algum texto de amostra.

Etapa 1: Instale a biblioteca Transformers

Para começar, você precisará instalar a biblioteca Transformers:

# Importar componentes necessários da biblioteca de transformadores
from transformers import pipeline

Etapa 2: Coleta de dados

Para simplificar, usaremos um pequeno conjunto de dados composto por avaliações positivas e negativas de filmes.

Conjunto de dados de críticas de filmes.
👍 (Polegar para cima - Positivo) | 👎 (Polegar para baixo - Negativo)

Etapa 3: Análise de sentimento

Deixe-me mostrar como utilizar a função pipeline para executar análise de sentimento:

from transformers import pipeline, AutoModelForSequenceClassification, AutoTokenizer

# Para melhorar o código para trabalhar com a língua portuguesa, você precisa usar um modelo pré-treinado que suporte português.
# Um desses modelos é o "nlptown/bert-base-multilingual-uncased-sentiment", que é um modelo de análise de sentimentos multilíngue.
# Ele prevê o sentimento da avaliação como um número de estrelas (entre 1 e 5).
model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
model = AutoModelForSequenceClassification.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Inicializar o pipeline de análise de sentimentos
# A função 'pipeline' da biblioteca transformers cria um pipeline para uma tarefa específica.
# Aqui, 'sentiment-analysis' é a tarefa em que estamos interessados.
# O pipeline baixará e inicializará automaticamente os modelos pré-treinados apropriados.
sentiment_pipeline = pipeline('sentiment-analysis', model=model, tokenizer=tokenizer)

# Texto de exemplo
# Supondo que 'reviews_df' seja um DataFrame que contém uma coluna chamada 'Review'
# Convertemos esta coluna em uma lista de revisões de texto.
text = reviews_df['Texto'].tolist()

# Executar análise de sentimentos
# Usamos o sentiment_pipeline inicializado para analisar o sentimento de cada revisão na lista de textos.
# O pipeline pega uma lista de textos e retorna uma lista de resultados de análise de sentimentos.
results = sentiment_pipeline(text)

# Imprimir os resultados
# Iteramos sobre os resultados para exibir o sentimento e a pontuação de confiança para cada revisão.
for i, result in enumerate(results):
  # Imprima o texto original da lista de texto
  print(f"Texto: {text[i]}")

  # Imprima o rótulo do sentimento (por exemplo, "POSITIVO" ou "NEGATIVO") e a pontuação de confiança arredondada para 2 casas decimais
  print(f"Sentimento: {result['label']}, Confiança: {result['score']:.2f}")
  print() # Imprima uma linha em branco para melhor legibilidade

Executar o código acima produzirá a seguinte saída.

Texto: Uma história absolutamente cativante com atuações incríveis.
Sentimento: 1 star, Confiança: 0.69

Texto: Direção terrível e um enredo que não fazia sentido.
Sentimento: 1 star, Confiança: 0.54

Texto: Uma obra-prima visual que me deixou encantado do início ao fim.
Sentimento: 5 stars, Confiança: 0.61

Texto: A atuação foi abaixo da média e o diálogo foi constrangedor.
Sentimento: 2 stars, Confiança: 0.49

Texto: Um dos filmes mais instigantes que já vi.
Sentimento: 5 stars, Confiança: 0.68

Texto: Um filme chato e sem inspiração que pareceu uma perda de tempo.
Sentimento: 2 stars, Confiança: 0.47

Texto: Cinematografia excelente e uma trilha sonora memorável.
Sentimento: 5 stars, Confiança: 0.76

Texto: Um filme mal executado com atuações sem brilho do elenco.
Sentimento: 1 star, Confiança: 0.70

Texto: Uma experiência profundamente emocional que ressoou comigo em muitos níveis.
Sentimento: 5 stars, Confiança: 0.72

Texto: Um filme superestimado que não correspondeu às expectativas.
Sentimento: 1 star, Confiança: 0.78

Explicação:

  1. Primeiro, configuramos a ferramenta de análise de sentimentos usando a função de pipeline da biblioteca transformers.

  2. Começamos inicializando o processo de análise de sentimentos com a função de pipeline fornecida pela biblioteca transformers.

  3. Em seguida, criamos uma lista de frases de amostra que queremos analisar para sentimento.

  4. Em seguida, usamos o pipeline para processar essas frases. Ele avalia o texto e retorna o sentimento (positivo 👍 ou negativo 👎) junto com uma pontuação de confiança.

  5. Finalmente, imprimimos os resultados, que incluem o sentimento e a pontuação de confiança para cada uma das frases.

Conclusão

Mergulhando no Processamento de Linguagem Natural usando NLTK pode abrir muitas portas em análise de texto, IA e aprendizado de máquina. Dominar o NLTK envolve aprendizado gradual — começando com conjuntos de dados pré-construídos e evoluindo para a criação de modelos personalizados. Com maior proficiência, pode-se desenvolver aplicativos avançados capazes de interpretar e gerar linguagem humana, preenchendo a lacuna entre a tecnologia e as complexidades da comunicação humana.

Ao seguir este guia e os exemplos práticos, você agora deve ter uma base sólida em PLN usando NLTK. O trabalho do projeto final ajuda você a colocar todos os conceitos aprendidos em prática, reforçando sua compreensão e preparando você para tarefas mais complexas. Boa codificação!

🔔 Assine o InfinitePy Newsletter para mais recursos e uma abordagem passo a passo para aprender Python, e fique atualizado com as últimas tendências e dicas práticas.

InfinitePy Newsletter - Sua fonte de aprendizado e inspiração em Python.