📘 Lição 3: Sua Primeira Interação com Dados — Carregamento, Exploração e Preparação Básica

"Dados não são números frios. São histórias, padrões, erros e oportunidades. Aprenda a ouvi-los."


⏱️ Duração estimada desta lição: 75-90 minutos


🧭 Por que esta lição é tão importante?

Porque aqui é onde a teoria se torna prática.

Na Lição 2 você aprendeu o mapa. Agora, você vai percorrer o caminho.

Você irá:

  • Carregar um conjunto de dados real.
  • Explorá-lo como um detetive.
  • Limpar como um cirurgião.
  • Preparar como um chef.
  • E deixá-lo pronto para que um modelo o entenda.

⚠️ Aviso amigável: Esta lição tem mais código que as anteriores. Mas não tenha medo. Faremos passo a passo, com explicações detalhadas, erros comuns e dicas de especialistas. Você não estará sozinho.


🎯 Objetivos desta lição

Ao final, você será capaz de:

✅ Carregar um conjunto de dados de uma URL ou arquivo local usando Pandas.
✅ Explorar sua estrutura, conteúdo e possíveis problemas (nulos, duplicados, valores estranhos).
✅ Criar visualizações simples para entender padrões.
✅ Preparar os dados para o modelo: codificar rótulos, dividir em treino/teste, vetorizar texto.
✅ Entender por que cada etapa de preparação é necessária.
✅ Sentir-se confortável manipulando dados… sua nova matéria-prima!


🛠️ Ferramentas que você usará

  • Pandas → A canivete suíço para manipulação de dados.
  • Matplotlib / Seaborn → Para visualizações básicas.
  • Scikit-learn → Para dividir dados e vetorizar texto.
  • Jupyter Notebook ou Google Colab → Seu laboratório de experimentação.

💡 Se você ainda não fez isso, abra o Google Colab agora: https://colab.research.google.com
Crie um novo notebook e vamos começar!


📥 Parte 1: Carregando os Dados — Sua Primeira Importação

Usaremos o conjunto de dados SMS Spam Collection. É pequeno, limpo e perfeito para começar.

🔹 Passo 1: Importar as bibliotecas necessárias

# Sempre comece importando o que você precisa
import pandas as pd

📌 O que é Pandas?
É uma biblioteca Python para manipular e analisar dados. Pense nela como o Excel, mas mais poderosa e programável.


🔹 Passo 2: Carregar o conjunto de dados de uma URL

# URL do conjunto de dados (hospedado no GitHub)
url = "https://raw.githubusercontent.com/justmarkham/DAT8/master/data/sms.tsv"

# Carregar com pandas
# O arquivo é separado por tabulações (\t), e não tem cabeçalho
data = pd.read_csv(url, sep='\t', names=['label', 'message'])

# Mostrar as primeiras 5 linhas
print(data.head())

📌 Saída esperada:

  label                                            message
0   ham  Go until jurong point, crazy.. Available only ...
1   ham                      Ok lar... Joking wif u oni...
2  spam  Free entry in 2 a wkly comp to win FA Cup fina...
3   ham  U dun say so early hor... U c already then say...
4   ham  Nah I don't think he goes to usf, he lives aro...

✅ Dados carregados! Agora você tem um DataFrame do Pandas.


🔹 Passo 3: Entender a estrutura do conjunto de dados

# Quantas linhas e colunas?
print(f"Formato do conjunto de dados: {data.shape}")  # (5572, 2)

# Nomes das colunas
print(f"Colunas: {data.columns.tolist()}")  # ['label', 'message']

# Tipos de dados
print(data.dtypes)

📌 Saída:

label      object
message    object
dtype: object

→ Ambas as colunas são do tipo object (texto no Pandas).


🔹 Passo 4: Ver estatísticas básicas

# Resumo estatístico (apenas para colunas numéricas, mas útil para ver se há nulos)
print(data.describe(include='all'))

📌 Saída chave:

       label           message
count   5572              5572
unique     2              5169
top      ham  Sorry, I'll call later
freq    4825                30

unique=2 no rótulo: há apenas dois valores: 'ham' e 'spam'.
top=ham: o valor mais frequente é 'ham'.
freq=4825: 'ham' aparece 4825 vezes.


🔍 Parte 2: Explorando os Dados — Seja um Detetive de Dados

Agora, vamos aprofundar. Não assuma nada. Explore tudo.


🔸 Pergunta 1: Quantos spam e quantos ham há?

print(data['label'].value_counts())

📌 Saída:

ham     4825
spam     747
Name: label, dtype: int64

→ Temos um conjunto de dados desbalanceado! Há 6,5 vezes mais ham que spam.
→ Isso é normal na detecção de spam… mas afetará como avaliamos o modelo. Veremos isso na Lição 6!


🔸 Pergunta 2: Há valores nulos?

print(data.isnull().sum())

📌 Saída:

label      0
message    0
dtype: int64

→ Perfeito! Não há valores nulos. Na vida real, isso é raro. Sempre verifique isso.


🔸 Pergunta 3: Como é a distribuição do comprimento das mensagens?

# Criar uma nova coluna: comprimento da mensagem
data['length'] = data['message'].apply(len)

# Estatísticas descritivas
print(data['length'].describe())

📌 Saída:

count    5572.000000
mean       80.489052
std        59.942492
min         2.000000
25%        36.000000
50%        61.000000
75%       111.000000
max       910.000000
Name: length, dtype: float64

→ Há mensagens de até 910 caracteres! Serão spam? Serão normais?


🔸 Pergunta 4: Visualizar a distribuição dos comprimentos

import matplotlib.pyplot as plt
import seaborn as sns

# Definir estilo
sns.set_style("whitegrid")

# Histograma dos comprimentos, colorido por rótulo
plt.figure(figsize=(12, 6))
sns.histplot(data=data, x='length', hue='label', bins=50, kde=False)
plt.title("Distribuição do comprimento das mensagens por tipo (Spam vs Ham)", fontsize=16)
plt.xlabel("Comprimento da mensagem (caracteres)", fontsize=12)
plt.ylabel("Frequência", fontsize=12)
plt.legend(title='Tipo', labels=['Spam', 'Ham'])
plt.show()

📌 O que você vê?

  • Mensagens spam tendem a ser mais longas (muitas em torno de 150-200 caracteres).
  • Mensagens ham são mais curtas (concentradas entre 20 e 100 caracteres).
  • Esta é uma pista valiosa! O comprimento pode ser uma característica útil para o modelo.

🔸 Pergunta 5: Que palavras aparecem em spam?

Vamos fazer uma análise de texto muito básica.

# Filtrar apenas spam
spam_messages = data[data['label'] == 'spam']['message']

# Converter para minúsculas e dividir em palavras
words = ' '.join(spam_messages).lower().split()

# Contar frequência das palavras
from collections import Counter
word_freq = Counter(words)

# Mostrar as 20 palavras mais comuns em spam
print("Palavras mais frequentes em SPAM:")
for word, freq in word_freq.most_common(20):
    print(f"{word}: {freq}")

📌 Saída típica:

free: 167
to: 137
you: 117
call: 90
txt: 89
now: 87
...

→ Claro! Palavras como "free", "call", "now" são muito comuns em spam.
→ Isso confirma que o modelo conseguirá aprender com essas pistas.


🧹 Parte 3: Preparando os Dados — Limpeza e Transformação

Agora, prepararemos os dados para o modelo. Lembre-se: modelos entendem números, não texto.


🔹 Passo 1: Codificar os rótulos (codificação de rótulos)

Converteremos 'ham' e 'spam' em 0 e 1.

# Criar um mapeamento
label_map = {'ham': 0, 'spam': 1}

# Aplicar o mapeamento
data['label_encoded'] = data['label'].map(label_map)

# Verificar
print(data[['label', 'label_encoded']].head())

📌 Saída:

  label  label_encoded
0   ham              0
1   ham              0
2  spam              1
3   ham              0
4   ham              0

→ Pronto! Agora o rótulo é numérico.


🔹 Passo 2: Dividir em Treino e Teste

Nunca treine e avalie com os mesmos dados!

from sklearn.model_selection import train_test_split

# Características (X) = mensagens
# Rótulo (y) = label_encoded
X = data['message']
y = data['label_encoded']

# Dividir: 80% treino, 20% teste
X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,
    random_state=42,  # Para reprodutibilidade
    stratify=y        # Mantém a proporção de spam/ham no treino e teste!
)

print(f"Tamanho do treino: {len(X_train)} mensagens")
print(f"Tamanho do teste: {len(X_test)} mensagens")
print(f"Proporção de spam no treino: {y_train.mean():.2%}")
print(f"Proporção de spam no teste: {y_test.mean():.2%}")

📌 Saída:

Tamanho do treino: 4457 mensagens
Tamanho do teste: 1115 mensagens
Proporção de spam no treino: 13.42%
Proporção de spam no teste: 13.41%

→ Perfeito! A proporção é mantida graças a stratify=y.


🔹 Passo 3: Vetorizar o texto — Converter palavras em números

Usaremos o CountVectorizer do Scikit-learn.

from sklearn.feature_extraction.text import CountVectorizer

# Criar o vetorizador
vectorizer = CountVectorizer()

# Aprender o vocabulário e transformar X_train
X_train_vec = vectorizer.fit_transform(X_train)

# Apenas transformar X_test (não aprender com ele!)
X_test_vec = vectorizer.transform(X_test)

# Ver o tamanho
print(f"Vocabulário: {len(vectorizer.vocabulary_)} palavras únicas")
print(f"Formato de X_train_vec: {X_train_vec.shape}")  # (4457, 7358)
print(f"Formato de X_test_vec: {X_test_vec.shape}")    # (1115, 7358)

📌 O que significa (4457, 7358)?

  • 4457 → número de mensagens no treino.
  • 7358 → número de palavras únicas no vocabulário (aprendido do treino).

→ Cada mensagem é agora um vetor de 7358 números (a maioria é 0, porque nem todas as palavras aparecem em todas as mensagens).


🔹 Passo 4 (Opcional): Salvar o vocabulário

Quer ver que palavras o vetorizador aprendeu?

# Obter as primeiras 20 palavras do vocabulário
vocab = vectorizer.get_feature_names_out()
print("Primeiras 20 palavras no vocabulário:")
print(vocab[:20])

📌 Saída:

['00', '000', '0000', '00000', '000000', '00001', '0001', '00011', '00012', '00015', '0002', '0003', '0004', '0005', '0006', '0007', '00080', '0009', '001', '0010']

→ Ops! Há muitos números. Por quê? Porque o CountVectorizer por padrão pega tudo como palavra, incluindo números e pontuação.

💡 Dica profissional: Mais tarde, você pode melhorar isso com:

  • stop_words='english' → remover palavras comuns ("the", "and", "is").
  • lowercase=True → converter para minúsculas (já faz isso por padrão).
  • token_pattern=r'\b[a-zA-Z]{2,}\b' → apenas palavras de 2+ letras, sem números ou sinais.

Mas por agora, está bom! Estamos aprendendo.


🧪 Parte 4: Mini-Projeto Exploratório — Torne-o Seu!

Agora, é sua vez de explorar.

🔸 Exercício 1: Qual é a mensagem mais longa? É spam ou ham?

# Encontrar o índice da mensagem mais longa
idx_max = data['length'].idxmax()
longest_message = data.loc[idx_max]

print(f"Comprimento: {longest_message['length']} caracteres")
print(f"Tipo: {longest_message['label']}")
print(f"Mensagem: {longest_message['message']}")

📌 Saída típica:

Comprimento: 910 caracteres
Tipo: spam
Mensagem: "I HAVE A DATE ON SUNDAY WITH WILL!!..." (Um spam MUITO longo!)

🔸 Exercício 2: Quantas mensagens têm mais de 200 caracteres? Que porcentagem são spam?

# Filtrar mensagens longas
long_messages = data[data['length'] > 200]
total_long = len(long_messages)
spam_long = long_messages[long_messages['label'] == 'spam'].shape[0]

print(f"Mensagens > 200 caracteres: {total_long}")
print(f"Dessas, spam: {spam_long} ({spam_long/total_long:.1%})")

📌 Saída típica:

Mensagens > 200 caracteres: 45
Dessas, spam: 43 (95.6%)

→ Quase todas as mensagens longas são spam! Isso confirma nossa hipótese visual.


🔸 Exercício 3: Quão limpo está o texto?

Veja algumas mensagens aleatórias. Você vê sinais de pontuação, letras maiúsculas, números, erros de ortografia?

# Mostrar 5 mensagens aleatórias
sample = data.sample(5, random_state=1)
for i, row in sample.iterrows():
    print(f"[{row['label']}] {row['message'][:100]}...")  # Apenas os primeiros 100 caracteres

→ Você verá coisas como:

  • "U dun say so early hor..." → linguagem informal, abreviações.
  • "FreeMsg Hey there darling..." → mistura de letras maiúsculas, sinais, números.

💡 Reflexão: Você acha que isso afetará o modelo? Como você poderia melhorá-lo? (Dica: limpeza de texto, lematização, etc. — veremos isso em cursos avançados).


❌ Erros Comuns nesta Lição (Evite-os!)

  1. Não usar stratify em train_test_split → Desbalanceia treino/teste.
  2. Aplicar fit_transform no teste → Vazamento de dados. Apenas transform!
  3. Não explorar os dados antes de vetorizar → Você perde padrões e erros.
  4. Ter medo da alta dimensionalidade (7358 colunas) → É normal em texto! Chama-se "espaço de alta dimensão".
  5. Não salvar y_train e y_test como variáveis separadas → Depois você não consegue treinar ou avaliar.

✅ Checklist desta lição — O que você deve saber fazer agora?

☐ Carregar um conjunto de dados de uma URL com Pandas.
☐ Explorar sua estrutura, valores únicos, nulos e estatísticas.
☐ Criar visualizações para entender padrões (comprimento, palavras frequentes).
☐ Codificar rótulos de texto em números.
☐ Dividir dados em treino/teste mantendo proporções (stratify).
☐ Vetorizar texto com CountVectorizer.
☐ Entender a forma das matrizes resultantes.
☐ Fazer perguntas exploratórias e respondê-las com código.
☐ Sentir-se confortável com a manipulação básica de dados.


🎯 Frase para lembrar:

"Antes de treinar um modelo, treine seus olhos. Aprenda a ver o que os dados estão dizendo."


← Anterior: Lição 2: O Mapa do Tesouro | Próximo: Lição 4: Treine Seu Primeiro Modelo →

Course Info

Course: AI-course0

Language: PT

Lesson: 3 data exploration