DEV Community

Walter R P Cortes
Walter R P Cortes

Posted on • Originally published at blog.wvcode.com.br on

AI na Análise de Dados - Classificação de Texto com a API da OpenAI

Introdução

Olá, tudo bem?

A esta altura do ano de 2023, é quase impossível que você não tenha ouvido falar sobre o ChatGPT. E verdade seja dita, o ChatGPT é uma aplicação incrível, que permite sermos mais eficientes em diversas tarefas do dia dia-a-dia! Mas é importante salientar que ele é apenas uma aplicação, o que está por trás do ChatGPT e que chamamos de um LLM (Large Language Model) é o que realmente faz toda a mágica acontecer. Não iremos entrar em detalhes de como o modelo GPT (Generative Pretrained Transformer) funciona (veja os links no final do post), mas vamos explicar como podemos trazer todo esse poder para dentro de nossos códigos Python e criar scripts e aplicações que vão aumentar ainda mais nossa produtividade.

Este será o primeiro de uma série de artigos que visam auxiliar na compreensão de como as IAs podem ser assistentes poderosos para o Analista de Dados.

Classificação de Dados

Classificação de dados é uma tarefa de aprendizado supervisionado que envolve a categorização de uma determinada amostra de dados em uma das várias classes predefinidas. Cada amostra é atribuída a uma e somente uma classe, baseando-se nas características dessa amostra.

Por exemplo, imagine que você tem um conjunto de emails e você quer classificá-los como “spam” ou “não spam”. Nesse caso, “spam” e “não spam” são as classes, e cada email é uma amostra que será classificada em uma dessas classes.

A classificação é geralmente realizada utilizando algoritmos de aprendizado de máquina. Esses algoritmos aprendem a classificar novas amostras baseando-se em um conjunto de treinamento. O conjunto de treinamento é um conjunto de amostras para as quais as classes verdadeiras são conhecidas.

Os algoritmos de classificação incluem árvores de decisão, regressão logística, máquinas de vetores de suporte, redes neurais e muitos outros. A escolha do algoritmo depende de vários fatores, como a natureza dos dados, o número de classes, a necessidade de interpretabilidade e outros.

Mas e se não temos conjuntos de dados de treinamento?

Se você não tem um conjunto de dados de treinamento rotulado, ainda existem várias abordagens que você pode usar, tais como:

  1. Aprendizado não supervisionado
  2. Aprendizado semi-supervisionado
  3. Aprendizado por reforço
  4. Rotulagem manual
  5. Geração de rótulos sintéticos
  6. Processamento de Linguagem Natural

E é nesta última opção que podemos utilizar o GPT para nos ajudar, pois o modelo do GPT é gigantesco, tendo sido treinado com conteúdo de toda a internet.

GPT versus métodos mais tradicionais de classificação

Os modelos de linguagem como o GPT (Generative Pretrained Transformer) têm várias vantagens e desvantagens, especialmente quando comparados a outros métodos de análise de texto. Aqui estão algumas delas:

Vantagens:

  1. Compreensão Profunda da Linguagem: O GPT é treinado em enormes quantidades de texto, o que lhe permite aprender uma rica compreensão da linguagem natural. Isso inclui uma compreensão de sintaxe, semântica, e até mesmo alguns elementos de conhecimento do mundo real.

  2. Versatilidade: O GPT pode ser usado para uma ampla gama de tarefas de processamento de linguagem natural, incluindo tradução de texto, geração de texto, resumo de texto, análise de sentimento, resposta a perguntas e muito mais.

  3. Aprendizado Transferível: O GPT utiliza o aprendizado transferível, o que significa que o conhecimento aprendido durante o treinamento em um grande conjunto de dados pode ser aplicado a tarefas específicas com relativamente poucos dados de treinamento adicionais. Isso permite ao GPT se adaptar a uma ampla gama de tarefas com um desempenho impressionante.

  4. Modelagem de Contexto: A arquitetura do Transformer, utilizada pelo GPT, é especialmente boa para entender o contexto em uma sequência de texto, o que é crucial para muitas tarefas de processamento de linguagem natural.

Desvantagens:

  1. Necessidade de Grandes Quantidades de Dados de Treinamento: O GPT precisa de grandes quantidades de dados de treinamento para aprender efetivamente. Isso pode tornar o treinamento do modelo do zero proibitivamente caro em termos de tempo e recursos computacionais.

  2. Dificuldade de Interpretação: O GPT, como muitos modelos de aprendizado profundo, pode ser difícil de interpretar. Ele pode produzir resultados impressionantes, mas pode ser difícil entender por que fez uma determinada previsão.

  3. Sensibilidade ao Ruído e Erros: Embora o GPT seja robusto em muitos aspectos, ele pode ser sensível a ruído e erros no texto de entrada. Pequenas mudanças no texto de entrada podem às vezes levar a grandes mudanças nas previsões do modelo.

  4. Potencial de Viés: O GPT aprende com os dados em que é treinado, e se esses dados contêm viés, o modelo também pode exibir viés. Isso pode ser um problema significativo quando o modelo é usado em contextos sensíveis.

Ok, o GPT é legal e tudo o mais… Mas e daí?

E daí que, graças ao modelo GPT, podemos ter um classificador de texto super calibrado para nos ajudar em nossas tarefas, sem o ônus de treinar tal modelo. E podemos utilizar o GPT a partir da API da OpenAI, de maneira muito simples! Outra vantagem que vale ressaltar é que, ao contrário de modelos tradicionais de classificação, podemos atribuir múltiplas categorias ao nosso texto.

Vamos ver um exemplo?

Organizando um catálogo de artigos

Imagine o seguinte cenário: temos uma lista de todos os artigos que salvamos no site Medium. O problema desta lista é que o Medium não oferece nenhum tipo de categorização dos artigos. A única maneira de fazer isso é separando em várias listas, o que dificulta principalmente o processo de busca dos artigos. Além, é claro, de pressupor a classificação antes de ler o artigo.

Essa tarefa realmente não é trivial, e seria muito útil poder fazer isso de forma automatizada. E o primeiro problema que temos é que nossa lista tem apenas o título e a url dos artigos. Para que a classificação seja mais precisa, precisamos de pelo menos algum texto que nos ajude a ter mais contexto a respeito do artigo.

Então, vamos criar o nosso script classificador? Esse script vai executar as seguintes tarefas:

flowchart LR
  A[Carregar Lista de Arquivos] --> B
  B[Buscar Título e Resumo<br>dos Artigos] --> C
  C[Classificar Artigos] --> D[Salvar Lista de Artigos]


Inicializando o ambiente

Vamos utilizar as seguintes bibliotecas: - beautifulsoup4 - biblioteca para extrair a informação do HTML que contém a lista de artigos - openai - biblioteca para utilizar a API da openAI - requests - bibliotea para buscar informações da internet

import os
import openai
import bs4
import json

from dotenv import load_dotenv
from requests_html import HTMLSession # importando o objeto de sessão do html requests

A próxima etapa é carregar variáveis de ambiente. Lembrando que é necessário ter uma API key para usar a API da OpenAI.

load_dotenv()

openai.api_key = os.getenv("OPENAI_API_KEY")

Agora, precisamos carregar nossa lista de artigos, que está em um arquivo HTML, que podemos baixar lá no site do Medium. Vamos criar uma função, de forma que poderemos re-utilizar essa parte da rotina sempre que for necessário.

def retorna_lista(nomearquivo: str):
 html_artigos = bs4.BeautifulSoup(open(nomearquivo, "r"))
 list_artigos = html_artigos.find_all("li")

 artigos = []
 for item in list_artigos:
 record = {}
 record = {
 "titulo": item.a.text,
 "link": item.a["href"],
 "autores": None,
 "resumo": None,
 "categorias": None
 }
 artigos.append(record)
 return artigos

Este código define uma função chamada “retorna_lista” que recebe um único parâmetro chamado “nomearquivo” do tipo string. A função primeiro abre o arquivo especificado pela string “nomearquivo” usando a função “open”, lê o conteúdo e usa o método “find_all” do Beautiful Soup para procurar todos os elementos de lista no documento HTML e armazená-los na variável “list_artigos”. A função, então, inicializa uma lista vazia chamada “artigos”. Em um loop, ela itera sobre cada item da lista na variável “list_artigos” e cria um dicionário chamado “record” com três chaves: “titulo”, “link”, “autores”, “resumo” e “categorias”. Os valores para “titulo” e “link” são extraídos do texto da tag “a” e do atributo “href”, respectivamente. O valor das chaves “autores”, “resumo” e “categorias” são uma string vazia. O dicionário “record” completo é então adicionado à lista “artigos”. Depois que todos os itens da lista são processados, a função retorna a lista “artigos”.

Então, podemos utilizar essa função conforme abaixo:

artigos = retorna_lista("reading-list-medium.html")

print(f" Número de Artigos: {len(artigos)}.")
 Número de Artigos: 1865.

Vamos ver como ficou um registro:

print(json.dumps(artigos[0], indent=4))
{
    "titulo": "Prompting ChatGPT for Python Code Generation: An Effective Framework",
    "link": "https://medium.com/p/e323b2d24987",
    "autores": null,
    "resumo": null,
    "categorias": null
}

Perfeito! Estamos com os artigos preparados para buscarmos os dados extra que nos darão mais contexto para a categorização.

Para fazer isso, vamos utilizar a biblioteca requests-html. Novamente, criaremos uma função para reutilizar depois.

def retorna_campos(registro: dict):
 # Declaramos variaveis que contem seletores HTML
 # Esses seletores nos ajudarão a encontrar os elementos HTML que contém o 
 # conteúdo referente ao autor, data publicação, titulo e lead
 seletor_autor = [
 "#root > div > div > div:nth-child(3) > div > article > div > div > section > div > div:nth-child(3) > div > div > div:nth-child(2) > div > div > div > div > div > div > div > span > div > div > div > div > div > p > a", 
 "#root > div > div > div:nth-child(3) > div > article > div > div > section > div > div:nth-child(3) > div > div > div:nth-child(1) > div > div > div > div > div > div > div > span > div > div > div > div > div > p > a", 
 "#root > div > div > div:nth-child(2) > div > article > div > div > section > div > div:nth-child(2) > div > div > div > div > div > div > div > div > div > div > span > div > div > div > div > div > p > a", 
 "#root > div > div > div:nth-child(2) > div > article > div > div > section > div > div:nth-child(3) > div:nth-child(1) > div > div:nth-child(2) > div > div > div > div > div > div > div > span > div > div > div > div > div > p > a"
 ]
 seletor_titulo_lead = [
 "#root > div > div > div:nth-child(3) > div > article > div > div > section > div > div:nth-child(3) > div > div > div:nth-child(2)", "#root > div > div > div:nth-child(2) > div > article > div > div > section > div > div:nth-child(3) > div:nth-child(1) > div > div:nth-child(2)"
 ]
 
 # Inicializamos o objeto HTMLSession para fazer a coleta da informação dos artigos
 request = HTMLSession()
 try:
 print(registro["link"])
 conteudo_html = request.get(registro["link"])
 autor = "Not available"
 
 for item in seletor_autor:
 aux_autor = None
 aux_autor = conteudo_html.html.find(item, first=True)
 if aux_autor is not None:
 autor = aux_autor
 break

 head = "Not available"
 for item in seletor_titulo_lead:
 aux_head = None
 aux_head = conteudo_html.html.find(item, first=True)
 if aux_head:
 aux_lead = aux_head.find('h2', first=True)
 if aux_lead is not None:
 head = aux_lead.text
 
 registro["autores"] = autor.text
 registro["resumo"] = head
 
 return registro
 except:
 print('URL {0} com erro. Verifique.'.format(registro["link"]))
 return None

A função retorna_campos faz o scraping de dados de páginas da web, especificamente páginas de notícias ou artigos de blog do Medium. Ele pega um dicionário de “registro” como entrada, que parece conter um “link” para uma página da web.

Passo-a-Passo:

  1. Variáveis seletor_autor e seletor_titulo_lead são listas de seletores CSS. Seletores CSS são padrões usados para selecionar os elementos que você deseja estilizar. Aqui, eles são usados para identificar os elementos HTML onde as informações de autor e título/lead estão localizadas no HTML da página.

  2. A função então inicia uma sessão HTML usando o módulo HTMLSession() do pacote requests_html, que é uma biblioteca Python para fazer solicitações HTTP e para parsing de HTML.

  3. A função tenta fazer uma solicitação GET para a URL que está no campo “link” do dicionário de entrada.

  4. Em seguida, a função tenta encontrar o autor do artigo. Para isso, itera sobre a lista seletor_autor e, para cada seletor, tenta encontrar um elemento correspondente na página HTML. Se encontrar um autor, interrompe o loop e guarda o autor encontrado.

  5. Depois disso, a função tenta encontrar o título do artigo da mesma maneira, usando a lista seletor_titulo_lead.

  6. Os resultados são então adicionados ao dicionário de entrada no campo “autores” para o autor e “resumo” para o título.

  7. Se houver algum erro durante o processo, como um link quebrado ou se o seletor CSS não corresponder a nenhum elemento, a função exibe uma mensagem de erro e retorna None.

  8. Se tudo correr bem, a função retorna o dicionário de entrada, agora com informações adicionais sobre o autor e o resumo do artigo.

Agora vamos a execução da função para cada artigo em nossa lista. Observe que colocamos um limitador para fazer isso para 10 registros.

artigos_comp = []
i = 0
for item in artigos:
 artigos_comp.append(retorna_campos(item))
 i += 1
 if i == 10:
 break
https://medium.com/p/e323b2d24987
https://medium.com/p/9e9536ebd839
https://medium.com/p/bb7d31ed2e76
https://medium.com/p/2688e319e2a5
https://medium.com/p/7edae42a20b3
https://medium.com/p/f87419cb14cb
https://medium.com/p/d6169fc81204
https://medium.com/p/74361bc3b92e
https://medium.com/p/9dc1566d960d
https://medium.com/p/3c053357c47f

Agora temos os nossos artigos com título, autor e uma lead line, que vai nos ajudar no processo da categorização.

Vamos agora, a nossa rotina de categorização, usando a API do OpenAI.

def retorna_categorias(titulo, resumo):
 response = openai.Completion.create(
 engine="text-davinci-003",
 prompt=f"We have these categories: dbt, Python, DataViz, Tableau, PowerBI, and Generative AI. Given those categories, please classify the following text with those categories: {titulo} - {resumo}. You can use only the categories listed. You can classify with multiple categories. If you think that none of the categories applies, you can tag as Other.",
 temperature=0.8,
 max_tokens=20,
 )
 return response.choices[0].text.strip()

Este código define uma função chamada “retorna_categorias” que recebe dois parâmetros: “titulo” e “resumo”. A função utiliza a API OpenAI para classificar o título e o resumo com base em um conjunto de categorias previamente determinadas - dbt, Python, DataViz, Tableau, PowerBI e Generative AI. Em seguida, retorna o resultado da classificação como uma string.

A função retorna então a primeira (e única) escolha da resposta da API OpenAI, que é a string que representa a categoria que foi escolhida como a melhor correspondência para o texto de entrada. O método strip() é usado para remover qualquer espaço em branco inicial ou final da string retornada.

Observação: Para usar este código, o módulo openai precisa ser importado e uma chave de API OpenAI precisa ser obtida.

lista_final = []
for item in artigos_comp:
 item["categorias"] = retorna_categorias(item['titulo'], item['resumo'])
 lista_final.append(item)

Agora que executamos a rotina acima, podemos imprimir os três primeiros registros e verificar que agora, temos categorias.

for idx, item in enumerate(lista_final):
 print(json.dumps(item, indent=4))
 if idx == 2:
 break
{
    "titulo": "Prompting ChatGPT for Python Code Generation: An Effective Framework",
    "link": "https://medium.com/p/e323b2d24987",
    "autores": "John Loewen",
    "resumo": "I\u2019ve done the prompt engineering research so you don\u2019t have to",
    "categorias": "Python, Generative AI"
}
{
    "titulo": "Power BI: How I Started Using Python To Automate Tasks",
    "link": "https://medium.com/p/9e9536ebd839",
    "autores": "Gabe Araujo, M.Sc.",
    "resumo": "Not available",
    "categorias": "PowerBI, Python"
}
{
    "titulo": "Chat with your databases using LangChain",
    "link": "https://medium.com/p/bb7d31ed2e76",
    "autores": "Vishnu Sivan",
    "resumo": "Not available",
    "categorias": "Other"
}

E aí estão os nossos artigos, devidamente categorizados. Inclusive, podemos ver um artigo que foi classificado como “Other”, indicando que o texto que foi enviado não foi suficiente para classificar com as categorias selecionadas.

Obrigado por ler até aqui! Espero que este script seja útil para vocês!!!

Links Úteis

  1. Understanding GPT-3: OpenAI’s Language Generation AI: Blog oficial da OpenAI sobre GPT-3 - Apresenta uma explicação detalhada do GPT-3 e seu uso potencial
  2. Data Classification in Machine Learning - Este é um artigo do site GeeksforGeeks que explica o conceito básico de classificação de dados em aprendizado de máquina, os diferentes tipos de algoritmos de classificação e como eles funcionam.
  3. Bibliotecas Python utilizadas no artigo:
    1. requests-html
    2. openai
    3. BeautifulSoup4

Top comments (0)