Lidando com desbalanceamento de classes
Considere que queremos aplicar técnicas de aprendizado de máquina para predizer a partir de dados de um dia se um grande terremoto acontecerá no dia seguinte. A maneira clássica envolve coletarmos dados, digamos o sinal de um sismógrafo, para as duas situações de interesse: terremoto e não-terremoto. Isso é relativamente simples: durante, digamos, um ano, pegamos os dados do sismógrafo e para cada dia de sinal anotamos se um terremoto ocorreu ou não no dia seguinte. Mais ainda, fazemos isso em um país com falhas mais ativas que o Brasil.
Ao fazermos isso, nos depararemos com uma característica destes dados: apenas cerca de 15 terremotos “grandes” (escala 7 ou acima) ocorrem em um ano (dado típico para os EUA). Logo, nossa base de dados conterá 350 dias sem terremotos e apenas 15 com terremotos. Nossos dados serão desbalanceados, com uma classe ocorrendo com mais frequência que a outra. Em problemas binários, chamamos a classe que contém o maior número de exemplos de classe majoritária, enquanto a outra é denominada classe minoritária.
Em dados desbalanceados, é necessário utilizar métricas adequadas para a avaliação do desempenho do modelo treinado. Um modelo com acurácia de 95,9% para o problema dos terremotos é possível, simplesmente retornando “não-terremoto” para qualquer exemplo, pois 95,9% dos exemplos são desta classe. O uso de métricas adicionais e complementares (e.g. precisão, recall), bem como métricas menos sensíveis (e.g. AUC-ROC) é essencial nestas situações.
De forma semelhante, deve-se tomar cuidado com a metodologia de avaliação do modelo. Em dados muito desbalanceados, uma simples divisão aleatória treino/teste poderia levar a nenhum exemplo da classe minoritária estar presente em alguma das classes. Utilizar uma divisão estratificada é desejável, onde faz-se a separação garantindo que os conjuntos possuam uma razão semelhante entre as classes. O mesmo pode ser feito com outras técnicas de validação cruzada, como K-Folds.
Mesmo com estes cuidados, o desbalanceamento de classes causa problemas para a maioria dos algoritmos de treinamento de modelos. Por exemplo, um perceptron treinado com descida de gradiente irá calcular o gradiente a partir de todos os exemplos. Inevitavelmente, o gradiente será quase totalmente determinado pela classe majoritária se o desbalanceamento for muito grande. O efeito tipicamente é que o hiperplano resultante dará excessiva ênfase à classe majoritária.
Diversas técnicas existem para tentar lidar com desbalanceamentos no processo de treinamento dos modelos. Todas procuram de alguma forma equalizar a influência das classes no treinamento do modelo. Nem sempre o objetivo é balancear perfeitamente os dados, sendo mais importante permitir o aprendizado apesar do desbalanceamento. Remover completamente o desbalanceamento pode ser inclusive contra-producente, pois a frequência relativa das classes estabelece a probabilidade a priori da ocorrência natural dos exemplos, uma informação potencialmente importante para o modelo.
Discutimos abaixo algumas técnicas utilizadas para lidar com desbalanceamentos.
Subamostragem da classe majoritária
A maneira mais simples envolve balancear os dados removendo exemplos da classe majoritária. Novamente, não é necessário remover exemplos a ponto de obter o mesmo número da classe minoritária — no caso do problema dos terremotos, acabaríamos com apenas 30 exemplos totais.
A decisão de quais exemplos serão removidos dá origem a diferentes mecanismos de subamostragem. A remoção aleatória é bastante simples e comum e tem a característica desejável de não criar suposições adicionais sobre os dados. Porém, pode-se também utilizar informação sobre os exemplos para ajudar na decisão, removendo exemplos com certas características. Tipicamente isso é feito para ampliar a separação entre as classes ou remover possíveis ruídos e, assim, pode ser aplicado mesmo sem a intenção de balancear classes.
Em um método, podemos rodar um KNN e descartar exemplos que “discordam” de seus vizinhos. Em outro, treinamos um classificador e descartamos exemplos “difíceis” — que são preditos com baixa probabilidade pelo modelo.
A subamostragem é tipicamente aplicada quando há uma quantidade muito grande de exemplos em ambas as classes. Do contrário, o descarte de exemplos pode representar perda de informações importantes para o processo de aprendizagem.
Sobreamostragem da classe minoritária
Uma alternativa a subamostragem é sobreamostrar a classe minoritária — isto é, ampliar a classe minoritária. Assume-se, claro, que não é mais possível coletar novos exemplos, o que seria ideal. Assim, novos exemplos precisam ser gerados a partir dos existentes. A grande vantagem é não precisar descartar exemplos como na subamostragem.
A forma mais direta é replicar exemplos aleatórios da classe minoritária. Escolhe-se aleatoriamente (com ou sem substituição) um exemplo, cria-se uma réplica deste e repete-se até atingir a razão desejada. Como na subamostragem, pode ser interessante replicar exemplos específicos, como exemplos mais difíceis.
Outra abordagem é sintetizar exemplos. Isso é feito gerando novos exemplos a partir dos existentes. Uma técnica popular é denominada SMOTE (Synthetic Minority Over-sampling Technique), que gera novos exemplos entre vizinhos da mesma classe, interpolando os atributos.
A sobreamostragem é adequada quando há poucos exemplos e descartar exemplos seria indesejável. A escolha de quais exemplos serão sobreamostrados, ou que servirão de base para a síntese de novos exemplos, tem um papel importante no desempenho final esperado do modelo.
Cuidado: a sub ou sobreamostragem devem ser feitas apenas no conjunto de treino. É um erro comum aplicar estas técnicas sobre todo o conjunto de dados e depois dividir os conjuntos para avaliação do modelo, o que pode causar vazamentos de informações entre conjuntos. O caso mais simples para compreender isto é na sobreamostragem, onde um exemplo pode estar no conjunto de treino e sua réplica exata no conjunto de teste.
Pesos para classes
Para alguns algoritmos de treinamento, é possível dar pesos para classes de forma a forçar o algoritmo a enfatizar classes específicas. Em algoritmos baseados em descida de gradiente isto é simples de ser feito. Considere o treinamento de um perceptron por SGD (descida de gradiente estocástica): cada exemplo irá atualizar os pesos em proporção ao erro e a taxa de aprendizado; podemos aumentar (ou diminuir) a taxa de aprendizado apenas para certas classes, forçando o algoritmo a dar mais pesos a estas.