Como fazer validação cruzada em Machine Learning
A validação cruzada é uma das formas mais fiáveis de avaliar um modelo de Machine Learning. Em vez de confiar numa única divisão entre treino e teste, o modelo é avaliado várias vezes em partes diferentes dos dados, o que produz uma estimativa muito mais estável do desempenho real. Esta técnica é especialmente valiosa quando tens poucos dados, porque aproveita todos os exemplos tanto para treinar como para testar. A seguir vês como fazer validação cruzada em Machine Learning com scikit-learn, com exemplos simples e prontos a correr.
Pré-requisitos
- Python 3 instalado no teu computador.
- As bibliotecas scikit-learn e NumPy instaladas (
pip install scikit-learn). - Saber o que é um modelo e a diferença entre dados de treino e de teste.
- Um editor de código ou o Jupyter Notebook para correr os exemplos.
Passo 1: Preparar os dados
Para este exemplo usamos o conjunto de dados iris, que já vem incluído no scikit-learn e não precisa de qualquer descarga. Separamos as características (X) da classe que queremos prever (y). As características são as colunas que descrevem cada flor — comprimento e largura das pétalas e das sépalas — e a classe é a espécie que queremos identificar.
from sklearn.datasets import load_iris
data = load_iris()
X = data.data
y = data.target
print(X.shape)
O resultado (150, 4) indica 150 exemplos e 4 características. É um conjunto pequeno e equilibrado, perfeito para aprender.
Passo 2: Escolher o modelo
A validação cruzada funciona com qualquer modelo do scikit-learn. Vamos usar uma regressão logística como exemplo. O parâmetro max_iter garante que o treino tem iterações suficientes para convergir.
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(max_iter=200)
Repara que ainda não treinámos nada: a função de validação cruzada vai tratar disso por nós. Se preferires outro algoritmo, basta substituir esta linha — o resto do código mantém-se igual.
Passo 3: Aplicar a validação cruzada
A função cross_val_score faz todo o trabalho. Com cv=5 divide os dados em 5 partes (chamadas folds), treina o modelo 5 vezes e, em cada uma, usa uma parte diferente para teste e as restantes para treino. É daqui que vem o nome k-fold. Ao repetir a avaliação em várias divisões, reduz-se o risco de um resultado enganador causado por uma divisão particularmente fácil ou difícil.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5)
print(scores)
O resultado é uma lista com 5 valores de exatidão, um por cada fold. Cada valor está entre 0 e 1. Usar 5 ou 10 folds é a escolha mais comum.
Passo 4: Interpretar os resultados
Um único número não chega: interessa saber a média e a variação entre os folds. A média é a melhor estimativa do desempenho do modelo; o desvio padrão mostra se esse desempenho é consistente.
print("Mean accuracy:", scores.mean().round(3))
print("Std deviation:", scores.std().round(3))
Um desvio padrão baixo significa que o modelo se comporta de forma parecida em todas as partes dos dados — sinal de um resultado fiável. Um desvio alto sugere que o modelo é instável ou que há poucos dados. Por exemplo, uma média de 0.97 com um desvio de 0.02 indica que o modelo acerta cerca de 97% das vezes de forma consistente.
Passo 5: Ter mais controlo com StratifiedKFold
Em problemas de classificação convém que cada fold mantenha a mesma proporção de classes que o conjunto completo. O StratifiedKFold faz exatamente isso, e com shuffle=True e random_state os resultados ficam reproduzíveis. Sem estratificação, um fold poderia ficar com demasiados exemplos de uma só espécie, distorcendo a avaliação.
from sklearn.model_selection import StratifiedKFold
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=kfold)
print(scores.mean().round(3))
Dica: usa sempre o mesmo random_state para conseguires comparar experiências de forma justa.
Verificar o resultado
Se tudo correu bem, o print(scores) mostra um array com 5 números entre 0 e 1, e a média aparece como um único valor (por exemplo, à volta de 0.97 no conjunto iris). Confirma que a média está próxima dos valores individuais dos folds. Se surgir um aviso de convergência, aumenta o max_iter; se os valores variarem muito, pode faltar dados ou o modelo não ser o mais adequado.
Conclusão
Já consegues avaliar um modelo de forma robusta, sem depender da sorte de uma única divisão dos dados. O passo seguinte natural é combinar a validação cruzada com o GridSearchCV para escolher os melhores hiperparâmetros, ou usar cross_val_predict para inspecionar as previsões fold a fold. Experimenta trocar a LogisticRegression por um RandomForestClassifier: será que a exatidão média sobe?