Fundamentos do Machine Learning com Python
Dividindo Dados em Conjuntos de Treino e Teste (Documentação Scikit-learn)
Aprenda sobre dividindo dados em conjuntos de treino e teste (documentação scikit-learn)
🚀 Dividindo Dados em Conjuntos de Treino e Teste
Olá, futuros cientistas de dados! 👋 Nesta aula prática, vamos mergulhar em um dos passos mais fundamentais e críticos do pipeline de Machine Learning: a divisão dos seus dados em conjuntos de treino e teste. Este processo é essencial para garantir que seus modelos sejam robustos e generalizáveis.
🎯 1. Introdução: Por que Dividir os Dados?
Imagine que você está estudando para uma prova. Se você usar as mesmas questões da prova final para praticar, você provavelmente irá muito bem na prova, certo? Mas isso significa que você realmente aprendeu o conteúdo ou apenas memorizou as respostas? 🤔
No Machine Learning, acontece algo similar. Se treinarmos um modelo usando todos os dados disponíveis e depois o avaliarmos com esses mesmos dados, o modelo pode parecer ter um desempenho excelente. No entanto, isso não garante que ele funcionará bem com dados novos e nunca vistos. Este fenômeno é conhecido como overfitting (sobreajuste).
Para evitar o overfitting e garantir que nosso modelo seja capaz de generalizar (ou seja, fazer previsões precisas em dados que ele nunca viu antes), dividimos nossos dados em dois ou mais conjuntos:
- Conjunto de Treino (Training Set): Usado para treinar o modelo. O modelo "aprende" os padrões e relações nos dados a partir deste conjunto.
- Conjunto de Teste (Test Set): Usado para avaliar o desempenho final do modelo. Este conjunto é mantido completamente separado e intocado durante o treinamento. Ele simula dados "novos" do mundo real.
A divisão correta dos dados é a base para uma avaliação de modelo honesta e confiável! 💪
🛠️ 2. Explicação Detalhada com Exemplos: train_test_split
O Scikit-learn, a biblioteca padrão de Machine Learning em Python, oferece uma função super conveniente para realizar essa divisão: train_test_split.
Como Funciona?
A função train_test_split divide arrays ou matrizes em subconjuntos aleatórios de treino e teste. Ela aceita seus dados de entrada (features X) e seus rótulos/alvos (targets y) e retorna quatro conjuntos:
X_train: Features para treino.X_test: Features para teste.y_train: Alvos para treino.y_test: Alvos para teste.
Parâmetros Chave:
test_size: A proporção do conjunto de dados a ser alocada para o conjunto de teste. Pode ser umfloat(ex:0.2para 20%) ou umint(número absoluto de amostras). SeNone, será definido como0.25por padrão.train_size: Similar atest_size, mas para o conjunto de treino. Geralmente, você define um ou outro.random_state: Um número inteiro que garante a reprodutibilidade da sua divisão. Se você usar o mesmorandom_stateem execuções diferentes, a divisão será sempre a mesma. Isso é CRÍTICO para depuração e para que seus resultados sejam consistentes. 🔑shuffle: Umboolean(padrãoTrue) que define se os dados serão embaralhados antes da divisão. Geralmente, queremos que sejaTruepara garantir que a divisão seja aleatória e representativa.stratify: SeNone(padrão), a divisão é feita de forma simples. Se você passar o seuy(alvos) para este parâmetro, a função fará uma divisão estratificada. Isso significa que a proporção de cada classe (no caso de classificação) será mantida nos conjuntos de treino e teste. Isso é extremamente útil para datasets desbalanceados, onde algumas classes têm muito menos amostras que outras.
Exemplo Básico:
Vamos criar um conjunto de dados simples com numpy e dividi-lo.
import numpy as np
from sklearn.model_selection import train_test_split
# 1. Criando dados de exemplo
# X (features): 10 amostras, 2 características cada
X = np.arange(20).reshape((10, 2))
# y (targets): 10 rótulos
y = np.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
print("Dados originais X:\n", X)
print("Dados originais y:\n", y)
print("-" * 30)
# 2. Dividindo os dados: 80% treino, 20% teste
# test_size=0.2 significa que 20% dos dados irão para o conjunto de teste.
# random_state=42 garante que a divisão seja a mesma toda vez que você rodar o código.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print("X_train (treino - features):\n", X_train)
print("Shape de X_train:", X_train.shape)
print("-" * 30)
print("X_test (teste - features):\n", X_test)
print("Shape de X_test:", X_test.shape)
print("-" * 30)
print("y_train (treino - targets):\n", y_train)
print("Shape de y_train:", y_train.shape)
print("-" * 30)
print("y_test (teste - targets):\n", y_test)
print("Shape de y_test:", y_test.shape)
print("-" * 30)
# Verificando se os dados são únicos nos conjuntos
# Por exemplo, uma amostra de X_train não deve estar em X_test
print("Amostras em X_train:", X_train.flatten())
print("Amostras em X_test:", X_test.flatten())Exemplo com Estratificação (para datasets desbalanceados):
Quando temos um dataset com classes desbalanceadas (por exemplo, 90% da classe A e 10% da classe B), uma divisão aleatória simples pode resultar em conjuntos de treino e teste onde a proporção das classes é muito diferente da original, ou pior, uma das classes pode estar ausente no conjunto de teste! 😱
Para resolver isso, usamos o parâmetro stratify.
import numpy as np
from sklearn.model_selection import train_test_split
from collections import Counter # Para contar a distribuição das classes
# 1. Criando dados de exemplo desbalanceados
# X (features): 100 amostras, 2 características
X = np.random.rand(100, 2)
# y (targets): 90 amostras da classe 0, 10 amostras da classe 1
y = np.concatenate([np.zeros(90), np.ones(10)])
np.random.shuffle(y) # Embaralha os rótulos para não estarem em ordem
print("Distribuição original de classes em y:", Counter(y))
print("-" * 30)
# 2. Divisão SEM estratificação
X_train_no_strat, X_test_no_strat, y_train_no_strat, y_test_no_strat = train_test_split(
X, y, test_size=0.2, random_state=42
)
print("--- Divisão SEM estratificação ---")
print("Distribuição de classes em y_train (sem stratify):", Counter(y_train_no_strat))
print("Distribuição de classes em y_test (sem stratify):", Counter(y_test_no_strat))
print("-" * 30)
# 3. Divisão COM estratificação
X_train_strat, X_test_strat, y_train_strat, y_test_strat = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y # <- AQUI está a mágica!
)
print("--- Divisão COM estratificação ---")
print("Distribuição de classes em y_train (com stratify):", Counter(y_train_strat))
print("Distribuição de classes em y_test (com stratify):", Counter(y_test_strat))
print("-" * 30)
# Observe como a proporção (90/10) é mantida nos conjuntos estratificados.
# No conjunto de teste (20 amostras), esperamos 18 da classe 0 e 2 da classe 1.
# No conjunto de treino (80 amostras), esperamos 72 da classe 0 e 8 da classe 1.No exemplo acima, você pode ver claramente como a estratificação ajuda a manter a proporção das classes, o que é crucial para treinar e avaliar modelos em dados desbalanceados de forma justa.
📚 3. Código de Exemplo Oficial (Scikit-learn)
O código que usamos acima é diretamente inspirado e alinhado com a documentação oficial do Scikit-learn para train_test_split. Você pode encontrar mais detalhes e exemplos na documentação:
- scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html
- scikit-learn.org/stable/modules/cross_validation.html#train-test-split
🤝 4. Integração com Múltiplas Tecnologias
Para o tópico específico de "dividir dados em conjuntos de treino e teste", a função train_test_split do Scikit-learn é a ferramenta padrão e mais utilizada no ecossistema Python para Machine Learning. Portanto, não há uma "integração" com outras tecnologias no sentido de usar diferentes bibliotecas para esta mesma tarefa.
No entanto, é importante notar que os dados que você divide com train_test_split podem vir de diversas fontes (arquivos CSV, bancos de dados, APIs) e serem processados por outras bibliotecas (como pandas para manipulação de DataFrames, numpy para operações numéricas). O train_test_split aceita arrays numpy ou DataFrames pandas como entrada, tornando-o flexível para seu pipeline de dados.
🏋️♀️ 5. Exercícios Práticos / Desafios
Agora é a sua vez de colocar a mão na massa! 🚀
Tarefas:
-
Tarefa 1: Divisão Básica com Proporções Diferentes
- Crie um conjunto de dados
Xcom 50 amostras e 3 características (usenp.random.rand). - Crie um conjunto de alvos
ycom 50 amostras (usenp.random.randint(0, 2, 50)para classes 0 e 1). - Divida os dados em 70% treino e 30% teste.
- Use
random_state=10. - Imprima as formas (shapes) de
X_train,X_test,y_trainey_test.
- Crie um conjunto de dados
-
Tarefa 2: Divisão Estratificada com Dataset Real (Iris)
- Carregue o dataset Iris do Scikit-learn:
from sklearn.datasets import load_iris; iris = load_iris(); X_iris, y_iris = iris.data, iris.target. - Imprima a distribuição original das classes em
y_irisusandocollections.Counter. - Divida o dataset Iris em 80% treino e 20% teste, utilizando estratificação baseada em
y_iris. - Use
random_state=7. - Imprima a distribuição das classes em
y_trainey_testapós a divisão estratificada. Verifique se as proporções foram mantidas.
- Carregue o dataset Iris do Scikit-learn:
-
Tarefa 3: Explorando o
shuffle- Crie um
Xeysimples, como no primeiro exemplo (np.arange(10).reshape((5, 2))erange(5)). - Realize uma divisão com
test_size=0.4,random_state=42eshuffle=False. - Imprima
X_testey_test. O que você observa sobre as amostras que foram para o teste? Elas são aleatórias ou sequenciais? - Compare com uma divisão onde
shuffle=True(o padrão).
- Crie um
💡 Dica para a Tarefa 3
Quando shuffle=False, a função train_test_split simplesmente pega as últimas test_size amostras para o conjunto de teste e as primeiras train_size amostras para o conjunto de treino. Isso pode ser um problema se seus dados estiverem ordenados!
📝 6. Resumo e Próximos Passos
Nesta aula, aprendemos a importância crucial de dividir nossos dados em conjuntos de treino e teste para:
- Evitar o overfitting.
- Garantir que o modelo seja capaz de generalizar para dados novos.
- Realizar uma avaliação honesta do desempenho do modelo.
Vimos como usar a função train_test_split do Scikit-learn, explorando seus parâmetros como test_size, random_state e, especialmente, stratify para lidar com datasets desbalanceados.
Próximos Passos:
Com os dados divididos, estamos prontos para as próximas etapas do pipeline de Machine Learning:
- Treinamento do Modelo: Usaremos o
X_trainey_trainpara "ensinar" o nosso modelo. - Avaliação do Modelo: Usaremos o
X_testey_testpara verificar o quão bem o modelo aprendeu e quão bem ele se comporta com dados nunca vistos.
Continue praticando e experimentando! A divisão de dados é um conceito que você usará em todos os seus projetos de Machine Learning. 🚀