Pandas: Projeto: Análise Abrangente

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

Projetos do mundo real nunca envolvem apenas uma tabela -- pense em 5 CSVs + 1 arquivo Excel + uma consulta de banco de dados, mesclados 4 vezes, agrupados em 3 dimensões, pivotados em 2 tabelas cruzadas e estilizados em 1 relatório polido. Esta lição é o grande final de todo o curso, reunindo cada habilidade das 24 lições anteriores em um único projeto: integração multi-fonte -> auditoria de qualidade -> junções complexas -> análise multidimensional -> relatório automatizado.

Aviso: O código abaixo deve ser executado em um ambiente Python local.

1. O Que Você Aprenderá


2. Contexto do Projeto: Análise de E-Commerce Transfronteiriço

(1) A Tarefa

Bob precisa analisar os dados do 1º ao 3º trimestre de um negócio de e-commerce transfronteiriço: 4 CSVs (pedidos/produtos/clientes/regiões) + 1 banco de dados SQLite (inventário) -> integrar -> analisar -> relatar.

(2) Fluxo de Trabalho Completo

100%
graph TB
    A["Carregar 5 Fontes de Dados"] --> B["Auditoria de Qualidade dos Dados"]
    B --> C["Merge de 4 Tabelas"]
    C --> D["Pipeline de Limpeza"]
    D --> E["Groupby Multidimensional"]
    E --> F["Análise Cruzada Pivô"]
    F --> G["Relatório Styler"]
    G --> H["Exportação Multi-Sheet"]
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

3. Carregamento de Dados Multi-Fonte

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Carregando 5 fontes de dados (Dificuldade: 3/5 estrelas)

PYTHON
import pandas as pd
import numpy as np
import sqlite3
from io import StringIO, BytesIO

# ============================================
# Passo 1: Carregamento de Dados Multi-Fonte
# ============================================

np.random.seed(42)

# Fonte 1: Clientes (CSV)
customers = pd.DataFrame({
    'customer_id': range(1, 501),
    'name': [f'Customer_{i:04d}' for i in range(1, 501)],
    'segment': np.random.choice(['Consumer', 'Corporate', 'Home Office'], 500),
    'city': np.random.choice(['New York', 'Los Angeles', 'Chicago', 'Houston', 'London', 'Tokyo'], 500),
    'country': np.random.choice(['US', 'US', 'US', 'US', 'UK', 'JP'], 500)
})

# Fonte 2: Produtos (CSV)
products = pd.DataFrame({
    'product_id': range(1, 51),
    'product_name': [f'Product_{i:02d}' for i in range(1, 51)],
    'category': np.random.choice(['Electronics', 'Clothing', 'Home', 'Sports', 'Books'], 50),
    'unit_price': np.round(np.random.uniform(10, 500, 50), 2)
})

# Fonte 3: Pedidos (CSV)
orders = pd.DataFrame({
    'order_id': [f'ORD-{i:05d}' for i in range(1, 2001)],
    'customer_id': np.random.randint(1, 501, 2000),
    'product_id': np.random.randint(1, 51, 2000),
    'order_date': pd.to_datetime(np.random.choice(
        pd.date_range('2024-01-01', '2024-09-30'), 2000)),
    'quantity': np.random.randint(1, 10, 2000),
    'discount': np.random.choice([0, 0.05, 0.1, 0.2, 0.3], 2000)
})

# Fonte 4: Regiões (Excel)
regions = pd.DataFrame({
    'country': ['US', 'UK', 'JP', 'DE', 'FR'],
    'region': ['North America', 'Europe', 'Asia Pacific', 'Europe', 'Europe'],
    'currency': ['USD', 'GBP', 'JPY', 'EUR', 'EUR']
})

# Fonte 5: Inventário (SQLite)
conn = sqlite3.connect(':memory:')
inventory = pd.DataFrame({
    'product_id': range(1, 51),
    'stock': np.random.randint(0, 500, 50),
    'reorder_level': np.random.randint(20, 100, 50)
})
inventory.to_sql('inventory', conn, index=False, if_exists='replace')

# Carregar do banco de dados
inv_df = pd.read_sql('SELECT * FROM inventory', conn)
conn.close()

print(f"✅ Carregado: customers({len(customers)}), products({len(products)}), "
      f"orders({len(orders)}), regions({len(regions)}), inventory({len(inv_df)})")
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

4. Auditoria de Qualidade dos Dados

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Auditoria de qualidade (Dificuldade: 2/5 estrelas)

PYTHON
# ============================================
# Passo 2: Auditoria de Qualidade dos Dados
# ============================================

def audit_quality(df, name):
    """Executa auditoria de qualidade em um DataFrame"""
    issues = []
    # Valores faltantes
    missing = df.isnull().sum()
    if missing.sum() > 0:
        issues.append(f"Faltantes: {dict(missing[missing > 0])}")
    # Duplicatas
    dups = df.duplicated().sum()
    if dups > 0:
        issues.append(f"Duplicatas: {dups}")
    # Tipos
    object_cols = df.select_dtypes(include='object').columns.tolist()
    if object_cols:
        issues.append(f"Colunas objeto: {object_cols}")
    status = "⚠️ PROBLEMAS" if issues else "✅ LIMPO"
    print(f"{name}: {status}")
    for issue in issues:
        print(f"  - {issue}")
    return issues

audit_quality(customers, 'Clientes')
audit_quality(products, 'Produtos')
audit_quality(orders, 'Pedidos')
audit_quality(regions, 'Regiões')
audit_quality(inv_df, 'Inventário')

# Injetar problemas para demo
orders.loc[np.random.choice(2000, 100, replace=False), 'discount'] = np.nan
dups = orders.sample(30)
orders = pd.concat([orders, dups], ignore_index=True)
print(f"\nApós injeção de problemas: formato dos pedidos = {orders.shape}")
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

5. Merge de 4 Tabelas + Limpeza

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Merge complexo + limpeza com pipe (Dificuldade: 3/5 estrelas)

PYTHON
# ============================================
# Passo 3-4: Merge de 4 Tabelas + Limpeza
# ============================================

def clean_orders(df):
    df = df.drop_duplicates(subset='order_id', keep='last')
    df['discount'] = df['discount'].fillna(0)
    return df

# Passo 1: Limpar pedidos
clean_orders_df = orders.pipe(clean_orders)

# Passo 2: Merge pedidos + produtos
op = pd.merge(clean_orders_df, products, on='product_id', how='left')

# Passo 3: Merge + clientes
opc = pd.merge(op, customers, on='customer_id', how='left')

# Passo 4: Merge + regiões
full = pd.merge(opc, regions, on='country', how='left')

# Passo 5: Merge + inventário
full = pd.merge(full, inv_df, on='product_id', how='left')

# Colunas derivadas
full['revenue'] = full['unit_price'] * full['quantity'] * (1 - full['discount'])
full['cost_estimate'] = full['unit_price'] * full['quantity'] * 0.6
full['profit'] = full['revenue'] - full['cost_estimate']
full['month'] = full['order_date'].dt.to_period('M')
full['is_low_stock'] = full['stock'] < full['reorder_level']

print(f"✅ Dataset completo: {full.shape}")
print(f"Colunas: {full.columns.tolist()}")
print(f"Faltantes: {full.isnull().sum().sum()}")
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

6. Groupby Multidimensional + Análise Pivô

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Agregação multidimensional e análise cruzada (Dificuldade: 3/5 estrelas)

PYTHON
# ============================================
# Passo 5-6: Análise Multidimensional
# ============================================

# 1. Receita por região × categoria
region_cat = full.groupby(['region', 'category']).agg(
    revenue=('revenue', 'sum'),
    orders=('order_id', 'count'),
    avg_order_value=('revenue', 'mean'),
    profit_margin=('profit', lambda x: x.sum() / full.loc[x.index, 'revenue'].sum())
).round(2)
print("=== Receita por Região × Categoria ===")
print(region_cat.head(8))

# 2. Tendência mensal por região
monthly_region = full.groupby(['month', 'region'])['revenue'].sum().unstack()
print(f"\n=== Mensal por Região ===\n{monthly_region.tail(3)}")

# 3. Tabela pivô: segmento × categoria
seg_cat = pd.pivot_table(
    full, values='revenue', index='segment', columns='category',
    aggfunc='sum', margins=True, margins_name='Total'
).round(0)
print(f"\n=== Pivô Segmento × Categoria ===\n{seg_cat}")

# 4. Produtos top
top_products = full.groupby('product_name').agg(
    revenue=('revenue', 'sum'),
    quantity=('quantity', 'sum'),
    avg_discount=('discount', 'mean')
).nlargest(5, 'revenue')
print(f"\n=== Top 5 Produtos ===\n{top_products}")

# 5. Alerta de estoque baixo
low_stock = full[full['is_low_stock']].groupby('product_name').agg(
    stock=('stock', 'first'),
    reorder_level=('reorder_level', 'first'),
    total_orders=('order_id', 'count')
).sort_values('total_orders', ascending=False)
print(f"\n=== Alerta de Estoque Baixo ===\n{low_stock.head(5)}")
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

7. Relatório Styler e Exportação Multi-Sheet

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Relatório Styler + exportação para Excel (Dificuldade: 3/5 estrelas)

PYTHON
# ============================================
# Passo 7: Relatório Estilizado + Exportação
# ============================================

# Estilizar a pivô segmento × categoria
styled_pivot = (seg_cat.style
    .format('${:,.0f}')
    .background_gradient(cmap='RdYlGn', axis=None)
    .set_caption('Receita por Segmento × Categoria')
)

# Estilizar top produtos
styled_products = (top_products.style
    .format({'revenue': '${:,.0f}', 'quantity': '{:,}', 'avg_discount': '{:.1%}'})
    .bar(subset=['revenue'], color='lightblue')
    .highlight_max(subset=['revenue'], color='lightgreen')
)

# Estilizar alerta de estoque baixo
styled_stock = (low_stock.head(10).style
    .format({'stock': '{:.0f}', 'reorder_level': '{:.0f}', 'total_orders': '{:,}'})
    .background_gradient(subset=['total_orders'], cmap='YlOrRd')
    .set_caption('Alerta de Estoque Baixo — Produtos de Alta Demanda')
)

# Exportar para Excel com múltiplas folhas
output_path = 'ecommerce_report.xlsx'
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
    # Folha de resumo
    summary = pd.DataFrame({
        'Métrica': ['Receita Total', 'Lucro Total', 'Total de Pedidos',
                    'Clientes Únicos', 'Produtos Únicos', 'Valor Médio do Pedido',
                    'Margem de Lucro'],
        'Valor': [full['revenue'].sum(), full['profit'].sum(), len(full),
                  full['customer_id'].nunique(), full['product_id'].nunique(),
                  full['revenue'].mean(), full['profit'].sum() / full['revenue'].sum()]
    })
    summary.to_excel(writer, sheet_name='Resumo', index=False)

    # Região × Categoria
    region_cat.to_excel(writer, sheet_name='Região-Categoria')

    # Tendência mensal
    monthly_region.to_excel(writer, sheet_name='Tendência-Mensal')

    # Segmento × Categoria (estilizado)
    styled_pivot.to_excel(writer, sheet_name='Segmento-Categoria')

    # Produtos Top
    top_products.to_excel(writer, sheet_name='Top-Produtos')

print(f"✅ Relatório exportado: {output_path}")

# Resumo final
print("\n" + "=" * 50)
print("  ANÁLISE ABRANGENTE DE E-COMMERCE COMPLETA")
print("=" * 50)
print(f"  Receita: ${full['revenue'].sum():,.0f}")
print(f"  Lucro: ${full['profit'].sum():,.0f}")
print(f"  Margem: {full['profit'].sum() / full['revenue'].sum():.1%}")
print(f"  Região Top: {full.groupby('region')['revenue'].sum().idxmax()}")
print(f"  Categoria Top: {full.groupby('category')['revenue'].sum().idxmax()}")
print(f"  Itens com Estoque Baixo: {len(low_stock)}")
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

❓ Perguntas Frequentes

P: Como você unifica formatos em múltiplas fontes de dados? R: Padronize em três passos: (1) Normalize nomes de colunas -- use o mesmo nome para a mesma chave (ex: customer_id em todos os lugares); (2) Unifique tipos -- converta todas as colunas de data com to_datetime e todas as colunas de ID para int; (3) Unifique codificação -- prefira UTF-8, e converta GBK para UTF-8. Antes do mesclagem, verifique o dtype e os valores únicos das colunas-chave para confirmar que podem corresponder.

P: Como você quantifica a qualidade dos dados? R: Avalie quatro dimensões: (1) Completude (taxa de faltantes = contagem faltante / contagem total, meta < 5%); (2) Consistência (as colunas-chave têm correspondências nas tabelas relacionadas?); (3) Precisão (proporção de outliers, ex: valores negativos ou extremos); (4) Atualidade (quando os dados foram atualizados pela última vez -- estão desatualizados?). Dê uma pontuação de 1 a 5 para cada dimensão para uma avaliação geral.

P: E se a cadeia de merges ficar muito longa? R: Mescle passo a passo e valide após cada junção -- verifique a contagem de linhas e valores faltantes a cada vez. Para um mesclagem de 5 tabelas, não escreva tudo de uma vez. Divida em 4 passos: pedidos+produtos -> +clientes -> +regiões -> +inventário. Após cada passo, print(formato, faltantes) para confirmar a correção antes de prosseguir.

P: Como você automatiza relatórios? R: Use ExcelWriter para produzir múltiplas folhas (resumo + análise por dimensão + pivôs estilizados), ou use Styler.to_html() para gerar um relatório baseado na web. Indo além: use Jupyter Notebook + nbconvert para gerar PDFs automaticamente. A abordagem final: parametrize notebooks com papermill e execute-os em agendamento para produzir relatórios automaticamente.

P: Como isso se compara a ferramentas de BI? R: Pandas é excelente para análises flexíveis e personalizadas -- não é limitado pelos recursos integrados de uma ferramenta de BI, e você pode implementar lógica arbitrariamente complexa. Ferramentas de BI (Tableau/Power BI) são mais adequadas para dashboards padronizados e exploração interativa -- a criação de gráficos por arrastar e soltar é rápida, mas cálculos complexos são restritos. Estratégia: use Pandas para análise profunda e preparação de dados, depois use ferramentas de BI para apresentação visual.

P: Como você constrói tabelas pivô multidimensionais? R: Passe múltiplas colunas para o índice: pd.pivot_table(df, index=['região','segmento'], columns='categoria'), o que produz colunas MultiIndex. Defina margins=True para adicionar totais de linha e coluna. Análise cruzada significa uma dimensão como linhas, uma como colunas e uma como valores -- esta é a maneira mais intuitiva de exibir dados tridimensionais.

P: Como você implementa alertas de estoque baixo? R: Compare o estoque com o reorder_level -- df[df['stock'] < df['reorder_level']]. Para priorizar, ordene por volume de pedidos: estoque baixo + alto volume de pedidos = mais urgente. Use o background_gradient do Styler para indicar o nível de urgência, com vermelho significando "reabastecer imediatamente".


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade: 1/5 estrelas): Crie 2 DataFrames (clientes + pedidos), mescle-os, calcule as vendas totais por região e use o parâmetro indicator para verificar a cobertura da correspondência.
  2. Intermediário (Dificuldade: 2/5 estrelas): Simule 3 fontes de dados (clientes/produtos/pedidos), realize 3 merges -> limpeza -> agregação groupby multidimensional -> tabulação cruzada pivot_table -> formatação Styler.
  3. Desafio (Dificuldade: 3/5 estrelas): Complete o projeto completo desta lição: carregue 5 fontes -> auditoria de qualidade -> mesclagem de 4 tabelas -> limpeza com pipe -> groupby multidimensional + pivô -> relatório Styler -> exportação multi-sheet com ExcelWriter.

<- Lição Anterior: Projeto - Séries Temporais | Conclusão do Curso ->

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%