import pandas as pd
import numpy as np
from sklearn.model_selection import StratifiedKFold
11 Validação Cruzada
Imports
Segue abaixo o código da importação dos módulos que usaremos nesse caderno:
Validação Cruzada
Como exposto no caderno de criação e avaliação de preditores, existem diversos métodos de aprendizado de máquina que podemos usar para construir um preditor. Então como saber qual método é melhor? Um jeito de fazer isso é usando a validação cruzada.
A Validação Cruzada nos permite comparar diferentes métodos de aprendizado de máquina ou parâmetros para o método escolhido e avaliar qual funcionará melhor na prática.
Então o que vamos fazer é, para cada método,
- Separar os dados em conjunto de treino e conjunto de teste.
- Treinar um modelo no conjunto de treino.
- Avaliar no conjunto de teste.
- Repetir os passos 1-3 e estimar o erro.
Já sabemos que não é uma boa ideia usar toda a base de dados para treinar o nosso preditor e então podemos dividir por exemplo os primeiros 75% dos dados para treino e 25% finais para teste. Mas, e se esse não for o melhor jeito de dividir nossos dados? E se o melhor jeito de fazer essa divisão for usando os primeiros 25% para teste e o restante para treino? A Validação cruzada leva em consideração todas essas divisões usando uma de cada vez e tirando a média dos resultados no final. Para isso veremos como realizar alguns métodos de reamostragem, para utilizarmos várias amostras possíveis e não ficarmos dependentes de uma única amostra.
Utilizaremos a base Spam ao longo do caderno.
# trocar essa url pelo caminho da base spam de vocês.
= pd.read_csv("Cadernos Grupo Python\\Validação Cruzada\\spam.csv")
Spam # Separando o rótulo das demais variáveis
= Spam.loc[:, Spam.columns != "type"]
XSpam = Spam["type"] YSpam
Alguns Métodos de Reamostragem
Falaremos de 3 métodos de reamostragem: K-fold, Repeated K-fold e Bootstrap. Daremos uma definição e exemplo de código de cada um para depois entrar em como utilizar na validação cruzada.
K-fold
Definição
Este método consiste em fatiar os dados em k pedaços iguais. Utilizamos um pedaço para o teste e os demais para o treino. Então realizamos esse procedimento k vezes, de modo que em cada repetição um novo pedaço seja utilizado para o teste. Para avaliar o erro nós tiramos a média de todos os erros de todas as replicações.
Exemplo: K-fold com 10 partes:
Quanto maior o k escolhido obtemos menos viés, porém mais variância. Em outras palavras, você terá uma estimativa muito precisa do viés entre os valores previstos e os valores verdadeiros, porém altamente variável. Agora quanto menor o k escolhido, mais viés e menos variância. Ou seja, não iremos necessariamente obter uma boa estimativa do viés, mas ela será menos variável.
OBS: Quando o k é igual ao tamanho da amostra, o método é também conhecido como leave-one-out.
Código de exemplo
Vamos utilizar reamostragem por k-fold
no conjunto de dados spam usando a implementação do scikit-learn. O scikit-learn possui algumas diferentes implementações para a reamostragem por k-folds. Usaremos a função StratifiedKFold
porque ela faz a separação de k-folds preservando a proporção original da coluna com os rótulos.
# Criação dos k-folds
= StratifiedKFold(n_splits=10, shuffle=True, random_state=11).split(XSpam, YSpam) kfSpam
Parâmetros da função StratifiedKFold()
:
n_splits
: Recebe o número de partições, o padrão é 5.shuffle
: SeFalse
os dados seguirão a ordem em que aparecem no conjunto de dados, seTrue
os dados serão embaralhados. Padrão éFalse
.random_state
: Semente de aleatoriedade para o embaralhamento. Padrão éNone
.
Logo após chamar a função StratifiedKFold()
chamamos um método, .split()
. Esse método é aplicado em cima do resultado do StratifiedKFold(). Ele recebe os dados da base utilizada e o rótulo para realizar a separação em k-folds. Fizemos a chamada do método desse jeito para encurtar o processo de separação em k-folds, não usaremos o resultado da função StratifiedKFold() para nada sem antes inserir os dados, assim também evitamos ter uma variável interemediária desnecessária.
O resultado da função StratifeidKFold(), assim como qualquer outra implementação de k-folds no scikit-learn é um generator
:
# Tipo da variável resultado do StratifiedKFold().split()
print(type(kfSpam))
<class 'generator'>
Eles são um tipo especial de vetor, possuindo um comportamento diferente de uma lista, notavelmente ele só pode ser iterado uma vez que para o scikit-learn é o ideal em termos de eficiência computacional. Vamos criar uma lista a partir desse generator apenas para poder entender como o scikit-learn fez a divisão, mas usaremos sempre a variável gerada a partir da chamada do método .split() em cima do resultado da função StratifiedKFold().
# criação de uma lista para reutilização do generator
= list(kfSpam)
kfSpamLista
# Exibindo cada k-fold
for K, (train, test) in enumerate(kfSpamLista, 1):
print("K:", K)
print("Treino:", train)
print("Teste:", test)
print(f"len(train): {len(train)}\nlen(test): {len(test)}\n\n")
if K == 3:
break
K, train e test são gerada a partir de kfSpamLista através da função enumerate, um jeito de lidar com a lista gerada a partir do gerador, e são prontamente iterados. O foco dessa explicação é entender como os k-folds funcionam, entender o enumerate e o generator é secundário, não iremos abordar isso futaramente porque são detalhes muito específicos do python que não é importante para entender validação cruzada.
Restringi para exibir apenas 3 k-folds para ficar melhor formatado aqui no caderno. Caso seja do interesse de vocês visualizar o exemplo com todos os k-folds, apenas retire a condição if K == 3:
e o break
do loop.
No computador de vocês poderá aparecer mais elementos nas listas, formatei para mostrar os 3 primeiros e os 3 últimos apenas para fim explicativo.
Analisando o resultado inteiro com todos os k-folds chegamos a algumas observações importantes:
- a lista treino e teste de cada fold K são complementares
- a união entre lista treino e teste de cada fold K é tem como resultado os índices da base original.
- índices na lista de teste não se repetem em outras listas de teste
- todos os índices passam uma vez pelo conjunto teste de algum k-fold
- os índices se repetem K-1 vezes em diferentes k-folds