Uma das etapas mais importantes
em um projeto de machine learning é a etapa de validação dos
resultados. Muitas das técnicas mais poderosas de aprendizado apresentam uma
grande quantidade de parâmetros e quanto menos restrições colocarmos no nosso
modelo maior a probabilidade de encontrarmos um super ajustamento, ou como é
mais conhecido, o overfitting.
Mas
o que é overfitting? Overfitting ocorre quando o método que
estimamos consegue bons resultados apenas nos dados que eles foram treinados.
Já na presença de novas observações, percebemos uma grande piora na qualidade da
predição. Ou seja, o overfitting
ocorre quando o método de aprendizado não consegue generalizar os resultados
para dados que não foram utilizados no processo de treino.
Para
evitar este problema existe o processo de validação. Há diversos tipos de validação,
um dos mais utilizados na prática corresponde a dividir os seus dados em três
bases, base de treino, validação e teste. A base de treino, como o próprio nome
diz, é utilizada para treinar o seu modelo, enquanto que a base de teste serve
para verificarmos a eficiência do método em “novos” dados. Já a base de
validação, que pode não existir, é utilizada para a escolha de algum parâmetro
da técnica de aprendizado, o que chamamos de model tuning. Um exemplo do model
tuning pode ser desde a escolha do
número de neurônios de uma rede neural ou até mesmo no uso do random forest para seleção de variáveis, comentada no post anterior, em
que podemos ajustar modelos adicionando a cada nova etapa uma variável
respeitando a ordem do random forest e escolher o conjunto que
apresente melhor resultado nesta base de validação. Um outro tipo de validação
é a validação out-of-time, muito
utilizada para projetos de aprendizado com dados obtidos ao longo do tempo, em
que os últimos dados ou últimos meses são deixados para verificar se o modelo
se comporta de maneira estável e se continuará com boa performance à medida que
novos dados forem sendo observados.
Neste
post iremos discutir um tipo de validação que vem sendo a cada dia mais
utilizado, trata-se da validação cruzada.
A
validação cruzada estima o erro do método de aprendizado em observações não
utilizadas no treino, ou seja, estima como o modelo construído irá se
comportará em novos dados, claro que isto é válido apenas se mantivermos a
mesma probabilidade conjunta das variáveis explicativas e da variável resposta
utilizada durante o treino.
O
k-fold cross validation consiste em
dividir a base em k pedaços. Para cada pedaço, estimamos o método sem a
presença desta parte e verificamos o erro médio no pedaço não utilizado durante
o treino. Abaixo, um exemplo de 8-fold cross
validation.
1
Treino
|
2
Validação
|
3
Treino
|
4
Treino
|
5
Treino
|
6
Treino
|
7
Treino
|
8
Treino
|
A
estimativa do erro de predição de cross
validation é dada pela média dos erros médios nos k pedaços. O model tuning, discutido anteriormente,
pode também ser realizado com o método de validação cruzada ao invés de apenas
uma base de validação. Uma importante escolha ao utilizarmos este método é
justamente a escolha do k, que pode variar de 2 a N, em que N é o número total
de observações disponíveis. Mas por que o método é sensível à escolha do k?
Imagine
que você escolha k igual a N, um caso particular é denotado como leave-one-out, pois somente uma
observação é deixada de fora em cada etapa. Com esta escolha, primeiramente
teremos um custo computacional alto, pois teríamos que ajustar o modelo N
vezes. Além disso, como os vários ajustes são muito parecidos, apenas uma
observação será diferente em cada etapa, teremos um estimador não viesado, no
entanto com alta variância. Já diminuindo o valor de k, diminuiremos a
variância, mas podemos aumentar o viés do estimador. Na prática, costuma-se
utilizar k variando de 5 a 10.
Um
detalhe importante que muitas vezes é esquecido ou deixado de lado em muitos
projetos de machine learning ocorre
quando há, por exemplo, um processo de seleção de variáveis. Muitas pessoas
costumam aplicar o método de validação cruzada apenas na estimação do modelo
final, no entanto, isto pode produzir viés na estimativa do erro de previsão
com o método. Nestes casos, devemos fazer a seleção de variáveis em conjunto
com a estimação, ou seja, deixando cada pedaço fora, realizamos a seleção e
ajustamos o modelo sem este pedaço e calculamos o erro em cada um dos pedaços.
Com
o intuito de exemplificar o que foi discutido neste post, construí um exemplo
com ajuda do software R e do pacote caret. Esta library do R é tão completa e possibilita tantas coisas que com
certeza será tema de um post específico no futuro. A base de exemplo utilizada
foi novamente a base de spam já utilizada em outros posts. O código em R e a
base estão disponíveis em (https://github.com/carlosrelvas/Cross_validation).
Primeiramente,
deixei 3.000 observações para o treino. As restantes, deixei separadas para
avaliar a performance e comparar com os resultados da validação cruzada. Optei
por utilizar a 10-fold cross validation,
assim cada um dos 10 ajustes utilizou 2.700 observações e avaliou as 300
restantes. A medida de performance que optei por utilizar foi a AUC (area under the curve) que é a área sob a
curva ROC. Como o intuito era só exemplificar, utilizei todas as variáveis
explicativas disponíveis (57) em um modelo de árvore de decisão, mais
precisamente optei por utilizar o algoritmo do pacote “ctree” que estima conditional inference trees. Um dos
parâmetros deste algoritmo é a profundidade da árvore que representa a
quantidade de nós finais na árvore. A validação cruzada foi utilizada para
escolher este parâmetro, ou seja, para construir o model tuning. Optei por testar apenas os valores de 10, 15 e 20
como profundidade e obtive a seguinte tabela:
Profundidade
|
ROC
|
10
|
0.946
|
15
|
0.951
|
20
|
0.95
|
Podemos
perceber que a validação cruzada não escolhe o modelo mais complexo
(profundidade 20) e sim aquele que generaliza melhor os resultados
(profundidade 15).
A estimativa
de validação cruzada com profundidade 15 foi 0.951 enquanto que a mesma medida
na base de teste, deixada totalmente de fora da validação cruzada, foi 0.929.