Alura > Cursos de Dados > Cursos de Exploração de Dados > Conteúdos de Exploração de Dados > Primeiras aulas do curso Projeto ciência de dados: plataforma de análise de reviews com chatbot

Projeto ciência de dados: plataforma de análise de reviews com chatbot

Módulo 01: Primeiras passos e analise de dados - Apresentação do Curso e Objetivos

Apresentando o projeto integrador

Olá! É um prazer estar aqui novamente. Vamos iniciar nosso projeto integrador: plataforma de análise de reviews (avaliações).

Ao longo deste projeto, integraremos conceitos vistos nos cursos anteriores em um único projeto. Construiremos um dashboard (painel) no qual será possível utilizar um chatbot (robô de conversa) que fará consultas aos dados e trará respostas com base em análises de reviews (avaliações) da Amazon.

Apresentando o instrutor

Meu nome é Julio Smitoro. Sou homem branco, tenho barba e estou vestindo uma camisa verde.

Audiodescrição: Julio é um homem branco, com barba, vestindo uma camisa verde.

Estruturando o treinamento em módulos

Nosso treinamento será estruturado em quatro módulos.

No primeiro módulo, apresentaremos os dados, a fundação de dados e a análise exploratória. Identificaremos quais são os dados que utilizaremos. Já adiantamos que são dados de avaliações de produtos feitas por pessoas compradoras.

No módulo 2, trataremos de embeddings (incorporações vetoriais) e análise de sentimento. Abordaremos a conversão de texto em vetor e desenvolveremos um modelo de análise de sentimento baseado em XGBoost para associar um texto a um sentimento positivo, negativo ou neutro.

No módulo 3, construiremos o chatbot (robô de conversa) com RAG (recuperação aumentada por geração) e function calling (chamada de função).

No módulo 4, desenvolveremos o dashboard (painel), que adotaremos como produto final deste projeto integrador.

Definindo requisitos e ferramentas

Sobre os requisitos, desenvolveremos o projeto utilizando o Visual Studio Code.

Vamos utilizar Pandas, SQLite, Sentence Transformers, LangChain e Streamlit; os LLMs (grandes modelos de linguagem) serão consumidos via Grok. Estamos utilizando o Visual Studio Code, mas é possível utilizar o Antigravity ou o Cursor. Utilizaremos o Visual Studio Code com a extensão Cloud Code.

O objetivo é simular um cenário real em que utilizamos um coding agent (agente de codificação) para auxiliar no processo de desenvolvimento dos projetos.

Detalhando a estrutura e execução da aplicação

A estrutura do projeto que vamos desenvolver será organizada ao longo de alguns notebooks (cadernos de código). O nosso chatbot será implementado em módulos de Python, e desenvolveremos um front-end (camada de apresentação) com o Streamlit.

Para executar a aplicação, utilizamos o comando python -m streamlit run app.

No terminal, você pode executar:

python -m streamlit run app.py

Apresentando o produto final

Este é o produto final do projeto. A interface está carregando. Disponibilizamos dois modos: o modo de consulta SQL com busca e o modo de RAG (recuperação aumentada por geração). Explicaremos ao longo do curso o que cada recurso faz. Por exemplo, poderemos enviar uma consulta como: quantas reviews (avaliações) negativas, neutras e positivas existem. Nesse caso, o chatbot utilizará uma tool (ferramenta) de consulta SQL com base na pergunta, gerará a query (consulta) SQL e executará a chamada no banco de dados.

Esse é o objetivo do treinamento. Ao longo de quatro módulos, construiremos a base até chegar a esse produto final.

Nos encontramos na próxima aula. [♪]

Módulo 01: Primeiras passos e analise de dados - Setup Incial de Projeto

Apresentando o módulo e o dataset

Vamos iniciar o módulo 01, Fundação de Dados e Análise Exploratória. Como mencionado anteriormente, o dataset (conjunto de dados) que vamos estudar ao longo deste treinamento é o Amazon Reviews de 2023. Trata-se de uma série de avaliações feitas por pessoas consumidoras da Amazon.

Ao comprar um produto, normalmente verificamos as avaliações. Na Amazon, as avaliações recebem notas de uma a cinco estrelas e podem incluir um comentário. É exatamente isso que temos neste dataset (conjunto de dados): o comentário da pessoa consumidora e a nota atribuída ao produto. Este é um grande conjunto público de avaliações de produtos da Amazon, compilado por um grupo de pesquisa de uma universidade, e reúne muitos dados, o que ficará mais claro quando apresentarmos o dataset (conjunto de dados).

Estávamos avaliando comprar um fone de ouvido, que inclusive compramos. Esse tipo de situação ilustra bem como as avaliações funcionam e por que são relevantes para análise.

Os objetivos deste primeiro módulo são:

Utilizando os materiais do módulo

Vamos iniciar o projeto do zero. No entanto, utilizaremos os materiais de referência. Esses são os materiais que vocês receberão ao longo do treinamento. Para cada um dos quatro módulos, haverá um material específico. Desde o primeiro momento, haverá acesso ao projeto final, que deve ser usado como referência. Recomendamos acompanhar o fluxo de desenvolvimento apresentado ao longo das aulas.

Neste primeiro momento, vamos utilizar os materiais do módulo 01. Aqui temos:

Configurando o ambiente de desenvolvimento

Podemos copiar os arquivos para o diretório do projeto. Em seguida, precisamos preparar o ambiente que vamos utilizar.

Vamos abrir um terminal.

Especificamos a versão do Python 3.11 e criamos um ambiente virtual utilizando o módulo de ambientes virtuais. Essas informações estão apresentadas no arquivo README. No terminal, fazemos isso com o comando:

python3.11 -m venv .venv

Como estamos utilizando macOS, ativamos o ambiente virtual com o comando apropriado para esse sistema. Se estivermos no Windows, utilizamos o comando correspondente. No macOS, o comando é:

source .venv/bin/activate

No README, trazemos um resumo do projeto, a estrutura final do projeto e o passo a passo para executar.

Na sequência, fazemos a instalação das dependências do projeto. No arquivo requirements.txt, descrevemos as bibliotecas necessárias para o ambiente: pandas, NumPy, Matplotlib, tqdm e huggingface_hub. Abaixo está o conteúdo do arquivo:

# modulo 01 - EDA
pandas
numpy
matplotlib
tqdm
huggingface_hub

Poderíamos remover NumPy, pois, ao instalar pandas, NumPy já é instalado como dependência. No README, indicamos o uso do gerenciador pip para instalar as dependências a partir do requirements.txt. Para isso, executamos:

pip install -r requirements.txt

Em seguida, executamos a instalação, que prepara tudo o que é necessário para a execução deste projeto.

Concluímos a configuração do ambiente; tudo está pronto para iniciar a execução do projeto.

Antecipando a próxima aula

Na aula seguinte, vamos iniciar com o primeiro Jupyter Notebook, GetData.

Pessoal, dito isso, eu te encontro na próxima aula.

Módulo 01: Primeiras passos e analise de dados - Aquisição de Dados

Iniciando a execução dos notebooks

Olá!

Agora que concluímos a configuração do nosso ambiente, podemos seguir com as etapas de execução dos nossos notebooks.

Temos o nosso ambiente virtual configurado, com as dependências instaladas e tudo pronto.

Vamos executar o nosso primeiro Jupyter Notebook, GetData.ipynb. Nesse notebook, o objetivo será realizar a aquisição dos dados.

Apresentando o conjunto de dados amazon reviews 2023

Antes de prosseguir, vamos esclarecer quais são os dados que estamos analisando ao longo deste projeto. Trata-se do conjunto Amazon Reviews 2023. Podemos facilmente localizar esse material no Google, procurando pela plataforma Hugging Face. Ao buscar por Hugging Face e Amazon Reviews 2023, encontramos o conjunto de dados que precisamos analisar neste momento.

Na página do conjunto de dados, há um link para a página oficial das pessoas desenvolvedoras, com mais detalhes. Entre as informações, estão os anos contemplados: 2013, 2014, 2018 e 2023. A quantidade de avaliações é bastante grande; por exemplo, em 2023 há 571,54 milhões de avaliações. Também há a divisão por categorias, uma vez que, dentro da Amazon, existem diversos tipos de produtos, agrupados por categoria. Entre elas, encontramos All Beauty, Amazon Fashion, Appliances e Automotive, entre outras. É possível baixar as avaliações e os dados diretamente pela página, mas faremos isso utilizando linhas de código em Python.

Definindo o recorte dos dados

Voltando ao nosso ambiente, o objetivo será buscar os dados do conjunto de dados disponível no Hugging Face. Como recorte, usaremos a categoria All Beauty. Desse conjunto, vamos extrair as avaliações e armazená-las em um banco de dados local no formato .db, por exemplo, no arquivo reviews.db.

Para este exercício, vamos trabalhar com uma única categoria (All Beauty) e com o ano de 2021. Vamos obter todas as avaliações dessa categoria referentes ao ano de 2021. É possível adotar outras estratégias, como incluir mais categorias ou ampliar o recorte do conjunto de dados, mas isso exigiria mais memória para treinar o modelo. Por esse motivo, vamos fixar o ano de 2021 e a categoria All Beauty.

Configurando parâmetros no arquivo config.py

Antes de executar o Jupyter Notebook, vamos tratar da estrutura do projeto. Uma boa prática é centralizar, em um arquivo de configuração ou em variáveis de ambiente, as informações que podemos querer ajustar ao longo da execução do projeto. No arquivo config.py, reunimos uma série de configurações, como:

Veja um exemplo de como centralizamos essas configurações em config.py:

import os

REPO_ID = 'McAuley-Lab/Amazon-Reviews-2023'
CATEGORIA = 'All_Beauty'
REVIEW_COLS = ["rating", "title", "text", "parent_asin", "user_id", 
               "timestamp", "helpful_vote", "verified_purchase"]
META_COLS = ["parent_asin", "title", "main_category", 
             "average_rating", "rating_number", "price", "store"]

# Aquisição: uma categoria, um ano inteiro, sem amostragem.
ANO_ALVO = 2021
MIN_CARACTERES = 20

DB_PATH = 'data/reviews.db'

Alguns pontos podem gerar dúvidas, como, por exemplo, o significado das colunas. Para entendê-las melhor, podemos abrir a página do conjunto de dados no Hugging Face, acessar a aba Files and Versions (Arquivos e versões) e, em seguida, Raw (bruto). Ali, nas seções correspondentes a avaliações (por exemplo, Review Categories), são listadas as colunas disponíveis. Como estamos trabalhando com a categoria All Beauty, esse é o arquivo que vamos buscar. O arquivo é do tipo JSON Lines (JSON por linhas). Portanto, especificamos em config.py quais colunas vamos extrair desse formato para cada categoria. Essa configuração pode parecer intuitiva para quem já utiliza conjuntos de dados do Hugging Face, mas vamos avançar no desenvolvimento e, depois, voltamos a esses detalhes conforme necessário.

Preparando o notebook e as importações

Com a categoria e o ano definidos, criamos as variáveis correspondentes em config.py. Para executar o Jupyter Notebook, precisamos selecionar o kernel, isto é, o kernel associado ao nosso ambiente virtual. No nosso caso, usaremos o ambiente virtual .venv. Com isso selecionado, podemos executar as funções normalmente.

Do config.py, importamos informações como ano-alvo, categoria, DB_PATH, as colunas e o REPO_ID. No arquivo utils.py, criamos uma função para executar consultas SQL. Explicaremos esse ponto mais adiante; por ora, vamos até comentar o trecho associado, para que ocorra um erro mais à frente e possamos retomar a explicação no momento oportuno.

Primeiro, fazemos as importações gerais: sqlite3, pandas e utilitários do pacote huggingface_hub (vamos apelidar hf_hub_download como hf para facilitar). O snippet abaixo mostra essas importações, além de carregar as configurações do config.py:

import os
import sqlite3

import pandas as pd
from huggingface_hub import hf_hub_download as hf

from config import (ANO_ALVO, CATEGORIA, DB_PATH, META_COLS, MIN_CARACTERES,
                    REPO_ID, REVIEW_COLS)
from utils.sql import query_sql

Como mencionado, vamos comentar temporariamente a importação da função de utilitários para que possamos demonstrar o erro e, depois, corrigi-lo no momento oportuno:

from config import (ANO_ALVO, CATEGORIA, DB_PATH, META_COLS, MIN_CARACTERES,
                    REPO_ID, REVIEW_COLS)
# from utils.sql import query_sql

Em seguida, limpamos todos os resultados anteriores e executamos a primeira célula. Será solicitado que instalemos o pacote do kernel para o Jupyter dentro do ambiente virtual (por exemplo, o pacote ipykernel). Concluída essa etapa, o notebook estará pronto para uso.

Neste ponto, importamos sqlite3, pandas e utilitários do pacote huggingface_hub (por exemplo, a função hf_hub_download), que será utilizada para realizar o download (transferência) do conjunto de dados. Podemos apelidar o módulo/função, conforme a conveniência do código, para facilitar as chamadas.

Para baixar os arquivos brutos, criaremos uma função auxiliar. Em linhas gerais, ela recebe:

O repo_id corresponde ao identificador do nosso conjunto de dados (informação exibida no topo da página do repositório). O filename é o caminho do arquivo que será baixado. Por exemplo, podemos navegar até a raiz do repositório e, então, especificar o caminho dentro de raw (bruto): primeiro a pasta, como "review_categories" ou "meta_categories", e depois o nome do arquivo (relacionado à categoria de interesse). Assim, a função recebe a pasta e o nome, localiza o arquivo na pasta específica e o baixa para a máquina local.

Podemos implementar e usar essa função assim:

def baixar(pasta: str, nome: str) -> str:
    
    return hf(repo_id=REPO_ID, repo_type="dataset", 
              filename=f"raw/{pasta}/{nome}.jsonl", cache_dir="data/hf_cache")


arquivo_reviews = baixar("review_categories", CATEGORIA)
arquivo_meta = baixar("meta_categories", f"meta_{CATEGORIA}")
print("arquivos prontos")

Para baixar os arquivos de avaliações, chamaremos a função auxiliar informando "review_categories" e a categoria (which comporá o filename). Ao executar, o processo de download (transferência) é iniciado e os arquivos passam a ser armazenados dentro da pasta "data". Dentro de "data", o Hugging Face utiliza uma estrutura de cache (memória de cache), por exemplo, "hf_cache", para gerenciar os arquivos baixados localmente.

Após a conclusão, a ferramenta informa que o download (transferência) foi realizado. Se verificarmos o conteúdo do cache, veremos diretórios como "datasets" e "snapshots" (instantâneos), que registram os artefatos baixados.

Aqui, ReviewCategory e MetaCategory.

Em ReviewCategory, temos o arquivo em formato JSON Lines, exatamente aquele arquivo que estávamos verificando.

Temos uma série de colunas.

Agora, vamos filtrar as colunas de interesse. Foi por isso que definimos essas colunas em config.py.

Por exemplo, temos rating, title e text.

Essas são as informações necessárias dentro das revisões para que possamos treinar nosso modelo de análise de sentimento no módulo seguinte.

Neste momento, já conseguimos baixar as revisões do Hugging Face, utilizando o Hugging Face Hub e o processo de download.

Precisamos agora realizar algumas filtragens, porque o arquivo traz todos os dados e, portanto, vamos especificar as informações que queremos.

Convertendo JSONL em dataframe

A primeira função vai apenas receber o JSON Lines e retornar um DataFrame. Aqui não há nada muito robusto. Vamos, inclusive, comentar esse trecho de código.

Para isso, começamos implementando a função que lê o JSONL em pedaços e devolve um DataFrame com apenas as colunas selecionadas. Em seguida, carregamos as reviews inicialmente:

def jsonl_to_dataframe(arquivo: str, cols: list[str]) -> pd.DataFrame:
    
    # Como o arquivo JSONL pode ser grande, vamos ler em pedaços (chunks)
    dfs = []
    with pd.read_json(arquivo, lines=True, chunksize=100_000) as reader:
        for chunk in reader:
            dfs.append(chunk[cols])
    return pd.concat(dfs, ignore_index=True)


reviews = jsonl_to_dataframe(arquivo_reviews, REVIEW_COLS)

print(f"reviews na categoria: len({reviews})")

Por ora, deixamos os passos de transformação comentados, mantendo apenas a leitura e a seleção das colunas:

reviews = jsonl_to_dataframe(arquivo_reviews, REVIEW_COLS)

# print(f"reviews na categoria: len({reviews})")

# reviews = reviews.rename(columns={"parent_asin": "product_id", "timestamp": "review_date"})
# reviews["review_date"] = pd.to_datetime(reviews["review_date"], unit='ms')

# # Filtros
# reviews = reviews[(reviews["review_date"].dt.year == ANO_ALVO) 
#                   & (reviews["text"].str.len() >= MIN_CARACTERES)]
# reviews = reviews.drop_duplicates(subset=["user_id", "text"])

# reviews["review_date"] = reviews["review_date"].astype(str)
# reviews["verified_purchase"] = reviews["verified_purchase"].astype(int)
# reviews["helpful_vote"] = reviews["helpful_vote"].fillna(0).astype(int)

# reviews = reviews.sort_values("review_date").reset_index(drop=True)
# reviews.insert(0, 'review_id', range(1, len(reviews) + 1))
# print(f"reviews no ano {ANO_ALVO} após filtros: {len(reviews)}")

# reviews.head()

Se executarmos e verificarmos Reviews depois, basicamente, o que era JSON Lines agora está no formato DataFrame. É simples chegar a essa conclusão quando percebemos que a saída é de fato um DataFrame.

Passamos o arquivo, especificamos quais são as colunas e ele retorna como DataFrame. É exatamente isso que está sendo feito. Passamos REVIEW_COLS, filtramos dentro do JSON Lines somente as colunas de interesse e obtemos um DataFrame contendo apenas os dados necessários.

Aplicando transformações e filtros

Agora, vamos realizar outras alterações nesse DataFrame que já convertemos a partir do JSON Lines.

Primeiro, vamos fazer um renomeamento. A coluna parent_asin ficará como product_id, timestamp será convertida para review_date e review_date será convertido para o tipo DateTime.

Esse ajuste de nomes e a conversão de review_date para DateTime são necessários porque agora aplicaremos alguns filtros.

review_date deverá ser igual ao AnoAlvo, que é 2021. Assim, traremos apenas dados de 2021.

Também verificaremos se o tamanho dos textos dos nossos reviews é maior ou igual ao mínimo de caracteres definido anteriormente.

Vamos remover duplicatas: verificamos se o text atribuído a um user_id foi repetido; em caso afirmativo, mantemos somente o primeiro.

Em seguida, convertemos review_date novamente para string.

No caso da verificação de compra, o campo verified_purchase, que é booleano (True/False), será convertido para 0/1.

No campo de voto útil, helpful_vote, valores None serão convertidos para 0. Essa é uma decisão que pode impactar o resultado.

Aplicaremos um sort_values baseado em review_date.

Depois de executar, teremos o DataFrame final com as configurações dos nossos reviews, contendo review_id, rating, title, text, product_id e demais informações necessárias.

Podemos agora aplicar todas essas transformações:

reviews = jsonl_to_dataframe(arquivo_reviews, REVIEW_COLS)

print(f"reviews na categoria: len({reviews})")

reviews = reviews.rename(columns={"parent_asin": "product_id", "timestamp": "review_date"})
reviews["review_date"] = pd.to_datetime(reviews["review_date"], unit='ms')

# Filtros
reviews = reviews[(reviews["review_date"].dt.year == ANO_ALVO) 
                  & (reviews["text"].str.len() >= MIN_CARACTERES)]
reviews = reviews.drop_duplicates(subset=["user_id", "text"])

reviews["review_date"] = reviews["review_date"].astype(str)
reviews["verified_purchase"] = reviews["verified_purchase"].astype(int)
reviews["helpful_vote"] = reviews["helpful_vote"].fillna(0).astype(int)

reviews = reviews.sort_values("review_date").reset_index(drop=True)
reviews.insert(0, 'review_id', range(1, len(reviews) + 1))
print(f"reviews no ano {ANO_ALVO} após filtros: {len(reviews)}")

reviews.head()

Tratando os metadados do produto

Agora, vamos tratar dos metadados do produto.

Basicamente, usaremos a mesma função para processar os arquivos de metadados, META_COLS.

Faremos o renomeamento e alguns outros processamentos, incluindo a remoção de duplicatas com base em product_id.

Podemos imprimir para inspecionar. Ao executar, teremos product_id, title, main_category, a nota média (average_rating), rating_number e price.

products = jsonl_to_dataframe(arquivo_meta, META_COLS)

products = (products.rename(columns={"parent_asin": "product_id"})
            .assign(price=pd.to_numeric(products["price"], errors='coerce'))
            .dropna(subset=['price', 'store'])
            .drop_duplicates(subset=["product_id"]))

print(f"produtos no metadado: len({products})")
products.head(3)

Com base nisso, conseguimos associar essas duas tabelas, pois ambas possuem product_id. Portanto, conseguimos realizar um JOIN entre as duas.

Processamos os produtos e também os nossos reviews.

Convertendo e enviando para sqlite

Agora, vamos converter e enviar tudo para um banco SQLite.

Como primeiro passo, criamos uma conexão com sqlite3.connect, passando dbpath.

Lembrando: dbpath é o que definimos em config.py.

Em seguida, executamos um script no qual passamos a query SQL.

Esse script, primeiro, remove as tabelas Review e Produto, caso existam. Em seguida, cria a tabela Produto, com as colunas ProductId (chave primária), Title, MainCategory, AverageRating, RatingNumber, Price e Store.

Também criamos a tabela Reviews, com ReviewId, ProductId, UserId, ASIN, Rating, Title, Text, ReviewDate, HelpfulVote e VerifiedPurchase.

Veja como isso fica no código (note que os nomes das tabelas/colunas no script estão em inglês, seguindo o padrão do nosso código):

conn = sqlite3.connect(DB_PATH)
cur = conn.cursor()

# DROP TABLE IF EXISTS produtos;
# DROP TABLE IF EXISTS reviews;
cur.executescript('''
CREATE TABLE products (
    product_id     TEXT PRIMARY KEY,
    title          TEXT,
    main_category  TEXT,
    average_rating REAL,
    rating_number  INTEGER,
    price          REAL,
    store          TEXT
);

CREATE TABLE reviews (
    review_id      INTEGER PRIMARY KEY,
    product_id     TEXT NOT NULL REFERENCES products(product_id),
    user_id        TEXT NOT NULL,
    asin           TEXT,
    rating         REAL NOT NULL,
    title          TEXT,
    text           TEXT,
    review_date    TEXT NOT NULL,
    helpful_vote   INTEGER,
    verified_purchase INTEGER
);

CREATE INDEX idx_review_product ON reviews(product_id);
CREATE INDEX idx_review_date ON reviews(review_date);
''')

# products.to_sql("products", conn, if_exists="append", index=False)
# reviews.to_sql("reviews", conn, if_exists="append", index=False)
# conn.commit()

# print("banco gravado")

Depois de criar as tabelas, comentamos o trecho de código específico e executamos o comando para verificar o resultado. Dentro da pasta "Data", foi criado o arquivo Reviews.db. Nele, constam as estruturas para produtos e reviews.

Agora, pegamos os DataFrames criados anteriormente, Products e Reviews, usamos to_sql para converter cada DataFrame para SQL e enviamos para dentro do nosso Reviews.db.

CREATE INDEX idx_review_product ON reviews(product_id);
CREATE INDEX idx_review_date ON reviews(review_date);
''')

products.to_sql("products", conn, if_exists="append", index=False)
reviews.to_sql("reviews", conn, if_exists="append", index=False)
conn.commit()

print("banco gravado")

Ao executar, teremos a tabela de produtos e a tabela de reviews devidamente persistidas.

Com isso, concluímos a primeira demanda: buscar os dados no Hugging Face e armazená-los em Reviews.db.

Consultando o banco e definindo query_sql

Podemos fazer uma breve conferência. Se executarmos uma consulta agora, pode ocorrer um erro. A origem desse erro é a função QuerySql.

Adotamos aqui uma boa prática que utilizamos em nossos projetos: como estamos trabalhando com um banco SQLite e precisaremos executar QuerySql repetidamente, criamos dentro da pasta "utils" um módulo Python sql com a função QuerySql. Essa função recebe a conexão e a query e retorna o resultado no formato DataFrame. Precisamos importá-la.

Para começar a checagem, tentamos rodar consultas usando query_sql — lembrando que deixamos a importação comentada anteriormente, justamente para evidenciar o erro:

# from utils.sql import query_sql

resumo = query_sql(conn, '''
SELECT COUNT(*)                     AS n_reviews,
       ROUND(AVG(rating), 2)        AS nota_media,
       ROUND(100.0 * AVG(verified_purchase), 2) AS pct_verificados,
       MIN(review_date)             AS primeira,
       MAX(DATE(review_date))       AS ultima
FROM reviews
''')

print(resumo.to_string(index=False))

per_mes = query_sql(conn, '''
SELECT strftime('%m', review_date) AS mes, COUNT(*) AS n, ROUND(AVG(rating), 2) AS nota
FROM reviews GROUP BY mes
''')

# conn.close()
per_mes

Como esperado, sem a importação ativa, ao executar, veremos um erro indicando que query_sql não está definido.

Agora, vamos definir essa função no módulo utils/sql.py e então importá-la. A função simplesmente executa a query e retorna um DataFrame:

import pandas as pd


def query_sql(conn, query: str) -> pd.DataFrame:
    """Executa uma query SQL e devolve um DataFrame com o resultado."""
    return pd.read_sql_query(query, conn)

Fazemos o seguinte: from utils.sql import query_sql. Passamos a conexão e a query para QuerySql. Ao executar, tudo funciona.

from utils.sql import query_sql

resumo = query_sql(conn, '''
SELECT COUNT(*)                     AS n_reviews,
       ROUND(AVG(rating), 2)        AS nota_media,
       ROUND(100.0 * AVG(verified_purchase), 2) AS pct_verificados,
       MIN(review_date)             AS primeira,
       MAX(DATE(review_date))       AS ultima
FROM reviews
''')

print(resumo.to_string(index=False))

per_mes = query_sql(conn, '''
SELECT strftime('%m', review_date) AS mes, COUNT(*) AS n, ROUND(AVG(rating), 2) AS nota
FROM reviews GROUP BY mes
''')

# conn.close()
per_mes

Apresentamos algumas informações: estamos calculando a contagem do número de reviews (avaliações), a nota média, o percentual de verificados, além da primeira e da última avaliação.

Em seguida, obtemos o resumo como resultado.

O resultado é apresentado como um DataFrame (estrutura de dados tabular). Em seguida, convertemos para String (texto) e realizamos outra consulta.

Corrigindo o erro de conexão fechada

Identificamos um erro: o problema ocorre porque estamos fechando o banco de dados.

Vamos retornar ao início, onde criamos a conexão. Localizamos o trecho em que a conexão foi criada, vamos copiar esse caminho e inseri-lo aqui. Funcionou.

from utils.sql import query_sql

conn = sqlite3.connect(DB_PATH)

resumo = query_sql(conn, '''

Aqui trazemos essas métricas e realizamos outra verificação.

Agrupando por mês

Estamos efetuando um agrupamento por mês.

SELECT strftime('%m', review_date) AS mes, COUNT(*) AS n, ROUND(AVG(rating), 2) AS nota
FROM reviews GROUP BY mes
''')

conn.close()
per_mes

Esse é o resultado e, por ora, está funcionando.

Encerrando a aula

Concluímos nosso primeiro objetivo: extrair os dados do Hugging Face e inseri-los em um SQLite.

Na próxima aula, retornaremos para avaliar esses dados e realizar uma análise exploratória breve.

Pessoal, agradeço muito e te vejo na próxima aula.

Sobre o curso Projeto ciência de dados: plataforma de análise de reviews com chatbot

O curso Projeto ciência de dados: plataforma de análise de reviews com chatbot possui 146 minutos de vídeos, em um total de 28 atividades. Gostou? Conheça nossos outros cursos de Exploração de Dados em Dados, ou leia nossos artigos de Dados.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Exploração de Dados acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas