CLR

Classificação e previsão usando estímulo adaptativo

James McCaffrey

Baixar o código de exemplo

Classificação é uma técnica de aprendizado de máquina que usa dados de treinamento para gerar um modelo (normalmente, uma regra complexa única ou equação matemática) que atribui itens de dados a uma de várias categorias distintas. O modelo pode então ser usado para fazer previsões sobre novos itens de dados cuja categoria é desconhecida. Os exemplos incluem prever se um paciente tem câncer (sim, não) com base em vários dados de teste médicos e prever a categoria de risco (baixa, média, alta) de um aplicativo de empréstimo com base no histórico financeiro de um candidato.

Há muitos algoritmos de classificação e técnicas diferentes, incluindo Naive Bayes, rede neural e regressão logística. Neste artigo, explico uma técnica fascinante chamada classificação de estímulo adaptativo na qual, em vez de tentar determinar uma regra de previsão complexa única , dados de treinamento são usados para gerar uma grande coleção de regras básicas rudimentares e simples. Um peso para cada regra básica é então computado. Uma previsão sobre novas entradas é feita combinando as regras básicas, considerando o peso de cada regra simples e chegando a um resultado de consenso. O termo “estímulo” vem do fato que a qualidade de previsão das regras simples é estimulada (melhorada) pela combinação delas.

O estímulo adaptativo é meta-heurístico. Com isso, eu quero dizer que a estímulo adaptativo é um conjunto de diretrizes que podem ser usadas para criar um algoritmo de classificação específico. Há muitas variações de algoritmos de estímulo adaptativo e há muitas ferramentas autônomas existentes que implementam alguma forma de estímulo adaptativo. Então, por que se preocupar em codificar classificação de estímulo adaptativo do zero? As ferramentas de classificação de estímulo adaptativo existentes podem ser difíceis ou impossíveis de personalizar, elas podem ser difíceis de integrar a um sistema de software, e podem ter problemas de direitos autorais ou de propriedade intelectual. 

Um exemplo concreto é a melhor maneira de entender o que o estímulo adaptativo é. Observe a Figura 1. O problema principal do programa de demonstração é prever se uma equipe de esporte de Seattle vencerá ou perderá uma competição futura contra uma equipe de Detroit, quando Seattle jogará em seu campo e o consenso das apostas (a extensão) é que Seattle tem uma leve vantagem (pequena). A parte superior da Figura 1 mostra 10 itens de dados de treinamento hipotéticos com resultados conhecidos. A primeira tupla de treinamento (Detroit, Home, Large, Win) significa que em um jogo anterior contra Detroit, quando Seattle jogou em casa e a extensão de ponto foi grande, Seattle venceu o jogo.

Adaptive Boosting Classification and Prediction
Figura 1 Classificação e previsão do estímulo adaptativo

A próxima parte do programa de demonstração mostra que os 10 itens de dados de treinamento foram convertidos de dados de cadeia de caracteres para formato de inteiros de base zero para processamento mais eficiente e, em seguida, armazenados na memória da máquina como uma matriz. Por exemplo, (Detroit, Home, Large, Win) é armazenado como (3, 0, 2, 1). Observe que nesse exemplo, o resultado a ser previsto tem somente dois valores, vitória ou derrota. Esse é chamado um problema de classificação binária. O estímulo adaptativo também pode ser usado em situações em que a variável dependente tem três ou mais valores (classificação multinomial). A maioria das técnicas de classificação binária codificam a variável dependente a ser prevista usando um esquema (0, 1), mas o estímulo adaptativo quase sempre usa um esquema (-1, +1) porque essa codificação simplifica um pouco parte da implementação do algoritmo. Observe que todos os valores de previsão da variável independente são categóricos (“Home,” “Medium” e assim por diante) O estímulo adaptativo também pode ser usado quando os dados de treinamento têm valores numéricos, como explicarei mais posteriormente.

A terceira parte da Figura 1 mostra que oito regras básicas foram geradas dos dados de treinamento. Com frequência, as regras básicas são chamadas de aprendizes fracos ou classificadores fracos na terminologia de estímulo adaptativo. O primeiro aprendiz fraco, expresso de forma amigável, é “IF Opponent IS Buffalo THEN Result IS Win” com uma taxa de erro bruto de 0,00. O segundo aprendiz fraco, que é mais ilustrativo, é “IF Opponent IS Chicago THEN Result IS Lose” com uma taxa de erro de 0,33. De onde veio esse aprendiz fraco? Se você examinar os dados de treinamento, verá que há três instâncias em que o adversário é Chicago. Em duas dessas instâncias de treinamento o resultado foi Lose, assim o aprendiz fraco está correto em duas de três vezes (0,67) e errado uma de três vezes (0,33).

Observe que nem todos os valores de previsão de item de treinamento geraram um aprendiz fraco; não há regra para quando o adversário é Atlanta. Como há duas tuplas de treinamento em que o adversário é Atlanta, e um resultado é Win e o outro resultado é Lose, a taxa de erro do aprendiz seria 0,50, o que não fornece nenhuma informação útil. A versão da classificação de estímulo adaptativo apresentada neste artigo supõe que todo os aprendizes fracos têm uma taxa de erro bruto menor que 0,50.

A próxima seção da Figura 1 indica que em segundo plano o algoritmo do estímulo adaptativo processa os aprendizes fracos para encontrar um peso para cada aprendiz. Esses pesos são medidas da importância de cada classificador fraco e são chamados valores alfa na terminologia de estímulo adaptativo. Determinar os valores alfa é a parte principal do estímulo adaptativo. O conjunto de aprendizes fracos e seus pesos alfa forma o modelo de classificação.

A última parte do programa de demonstração mostra o modelo de classificação sendo usado para fazer uma previsão para a equipe de Seattle quando a equipe adversária é Detroit, o campo é Home e a extensão de ponto é Small. Se você consultar o conjunto de aprendizes fracos gerados, verá que três aprendizes são aplicáveis: [2] IF Opponent IS Detroit THEN Result IS Win (+1), [3] IF Field IS Home THEN Result IS Win (+1) e [5] IF Spread IS Small THEN Result IS Lose (-1). Os valores alfa computados para os aprendizes fracos 2, 3 e 5 são 0,63, 3,15 e 4,49, respectivamente. Portanto, a previsão de consenso = (0,63)(+1) + (3,15)(+1) + (4,49)(-1) = -0,72 (arredondado), que, como o valor é negativo, significa Lose. Observe que mesmo que dois de três aprendizes fracos façam uma previsão de Win, o alfa grande do aprendiz fraco 5 tem peso maior que as previsões de Win para resultar em uma previsão geral de Lose.

Nas seções seguintes explicarei com cuidado como o programa de demonstração funciona para que você possa adicionar características de previsão a um sistema ou aplicativo .NET. Este artigo pressupõe que você tenha habilidades avançadas em programação com uma linguagem da família C, mas não pressupõe que conheça qualquer coisa sobre a classificação com estímulo adaptativo. Codifiquei a demonstração usando C#, mas a explicação deve lhe dar informações suficientes para refatorar o código em outras linguagens como Visual Basic .NET ou Python. O código do programa de demonstração é um pouco longo para ser apresentado por completo neste artigo, mas o código-fonte completo está disponível em archive.msdn.microsoft.com/mag201304AdaptiveBoost.

O algoritmo do estímulo adaptativo

O centro da classificação de estímulo adaptativo é uma rotina que examina cada aprendiz fraco e atribui um peso alfa a cada um. O algoritmo é bastante complicado e é melhor explicado por um exemplo concreto. Suponha que haja 10 tuplas de treinamento e oito aprendizes fracos, como mostrado na Figura 1. A cada tupla de treinamento é atribuído um peso, normalmente chamado D na literatura de estímulo adaptativo. A soma dos pesos D é 1,0, tornando os valores D uma distribuição. Inicialmente, a todos os itens de dados de treinamento são atribuídos pesos D iguais, nesse caso 0,10 porque há 10 itens.

 

[0] (D = 0.10) Detroit   Home   Large    Win
[1] (D = 0.10) Detroit   Away   Medium   Win
[2] (D = 0.10) Buffalo   Home   Small    Win
[3] (D = 0.10) Buffalo   Home   Medium   Win
[4] (D = 0.10) Atlanta   Away   Large    Win
[5] (D = 0.10) Chicago   Home   Medium   Win
[6] (D = 0.10) Chicago   Away   Small    Lose
[7] (D = 0.10) Chicago   Home   Small    Lose
[8] (D = 0.10) Atlanta   Away   Medium   Lose
[9] (D = 0.10) Detroit   Away   Large    Lose

Cada aprendiz tem um valor épsilon e uma valor alfa. Valores épsilon são taxas de erro ponderadas usadas para computar valores alfa. Inicialmente todos os aprendizes têm valores alfa desconhecidos (digamos a = 0,00) e valores épsilon desconhecidos (digamos e = 1,0):

[0] (a = 0.00) (e = -1.0) IF Opponent IS Buffalo THEN Result IS Win
[1] (a = 0.00) (e = -1.0) IF Opponent IS Chicago THEN Result IS Lose
[2] (a = 0.00) (e = -1.0) IF Opponent IS Detroit THEN Result IS Win
[3] (a = 0.00) (e = -1.0) IF Field IS Home THEN Result IS Win
[4] (a = 0.00) (e = -1.0) IF Field IS Away THEN Result IS Lose
[5] (a = 0.00) (e = -1.0) IF Spread IS Small THEN Result IS Lose
[6] (a = 0.00) (e = -1.0) IF Spread IS Medium THEN Result IS Win
[7] (a = 0.00) (e = -1.0) IF Spread IS Large THEN Result IS Win

Em pseudocódigo, o algoritmo para descobrir os pesos alfa de cada aprendiz é:

set t=0
while not done loop
  update all learners' epsilons (weighted errors)
  find best (smallest epsilon) unused learner
  compute and save the alpha of best learner using its epsilon
  update the D weights for each training item using the best learner
  normalize the D weights so they sum to 1.0
  ++t
end loop

O principal loop de processamento termina quando todos os aprendizes fracos foram processados e a eles atribuídos um peso alfa; ou quando a variável do contador de loop t exceder algum valor máximo; ou quando a taxa de erro ponderada, épsilon, do melhor aprendiz fraco não utilizado for alguma valor, como 0,45 ou 0,49, indicando que não há nenhum aprendiz relativamente bom não utilizado a ser processado.

A primeira etapa dentro do loop é atualizar todos os épsilons. Um valor épsilon é a soma dos pesos D das tuplas de treinamento classificadas incorretamente. Para o aprendiz [0] (IF Opponent IS Buffalo THEN Result IS Win) há duas tuplas de treinamento aplicáveis, [2] e [3], e a regra está correta nas duas instâncias, portanto, épsilon é 0,00. Para o aprendiz [1] (IF Opponent IS Chicago THEN Result IS Lose) há três tuplas de treinamento aplicáveis, [5], [6] e [7]. Entre elas, a tupla [5] é incorreta, portanto, épsilon é simplesmente o peso D da tupla [5] = 0,10.

Embora não esteja imediatamente óbvio, se você examinar cuidadosamente como os épsilons são computados, observará que os valores épsilon estarão sempre entre 0,0 e 0,5. Depois de todas as atualizações, os épsilons de aprendiz são:

[0] (a = 0.00) (e = 0.00) IF Opponent IS Buffalo THEN Result IS Win
[1] (a = 0.00) (e = 0.10) IF Opponent IS Chicago THEN Result IS Lose
[2] (a = 0.00) (e = 0.10) IF Opponent IS Detroit THEN Result IS Win
[3] (a = 0.00) (e = 0.10) IF Field IS Home THEN Result IS Win
[4] (a = 0.00) (e = 0.20) IF Field IS Away THEN Result IS Lose
[5] (a = 0.00) (e = 0.10) IF Spread IS Small THEN Result IS Lose
[6] (a = 0.00) (e = 0.10) IF Spread IS Medium THEN Result IS Win
[7] (a = 0.00) (e = 0.10) IF Spread IS Large THEN Result IS Win

Nesse ponto o melhor aprendiz é selecionado. É o aprendiz [0] porque seu épsilon é o menor em 0,00. O alfa associado é computado como:

alpha = 0.5 * log((1.0 - epsilon) / epsilon)

Essa é essencialmente uma equação mágica da teoria do estímulo adaptativo. Aqui, log é o logaritmo natural (base e). Lembre-se de que o valor alfa é um peso que atribui uma importância a um aprendiz. A equação anterior foi projetada de modo que valores menores de épsilon (erro de aprendiz) resultem em valores maiores de alfa ( importância de aprendiz)

Nessa situação em particular há um problema porque o épsilon é 0; assim, haveria um erro de divisão por 0. Para evitar isso, o programa de demonstração arbitrariamente converte qualquer épsilon com um valor de 0 a 0,000001. Assim, o alfa do aprendiz [0] é computado como 0,5 * log(0,999999 / 0,000001) = 6,91 e esse valor é atribuído ao aprendiz [0], e o aprendiz [0] é sinalizado como concluído.

A próxima etapa dentro do loop do algoritmo é atualizar os pesos da tupla de treinamento D com base no melhor aprendiz que acabou de ser computado. A ideia é aumentar os pesos D dessas tuplas de treinamento que estão incorretamente classificadas pelo melhor aprendiz e reduzir os pesos D das tuplas de treinamento que estão corretamente classificadas pelo melhor aprendiz. A equação de atualização de D é um pouco complicada à primeira vista:

D(new) = D(old) * exp(-alpha * actualY * predictedY)

O melhor aprendiz foi o aprendiz [0] (IF Opponent IS Buffalo THEN Result IS Win) com um alfa de 6,91. Das 10 tuplas de treinamento, o aprendiz [0] aplica-se às tuplas [2] e [3], portanto, esses valores D são atualizados. Para a tupla de treinamento [2]:

D(new) = 0.10 * exp(-6.91 * (+1) * (+1))
       = 0.10 * exp(-6.91)
       = 0.0000997758

O novo valor D da tupla de treinamento [3] tem o mesmo cálculo e o mesmo valor da tupla [2].

Nesse caso, obtemos um novo valor D que é muito pequeno porque a tupla de treinamento foi corretamente classificada pelo melhor aprendiz. Observe que quando o valor Y real e o valor Y previsto são os mesmos (ambos são -1 ou ambos são +1), quando multiplicados juntos o resultado é +1 e o argumento de exp será um número negativo (porque -alfa será sempre negativo), o que dará um resultado menor que 1,0. No entanto, se o Y real e o Y previsto forem diferentes, seu produto será -1, e o argumento de exp será positivo, o que resultará em um número maior que 1,0 (possivelmente grande). Essa técnica de atualização de D é por que a classificação de estímulo adaptativo normalmente usa -1 e +1 para os valores de variável dependente em vez de 0 e +1.

Nesse ponto, os valores D aproximados preliminares (arredondados) são:

[0] (D = 0.1000) Detroit   Home   Large    Win
[1] (D = 0.1000) Detroit   Away   Medium   Win
[2] (D = 0.0001) Buffalo   Home   Small    Win
[3] (D = 0.0001) Buffalo   Home   Medium   Win
[4] (D = 0.1000) Atlanta   Away   Large    Win
[5] (D = 0.1000) Chicago   Home   Medium   Win
[6] (D = 0.1000) Chicago   Away   Small    Lose
[7] (D = 0.1000) Chicago   Home   Small    Lose
[8] (D = 0.1000) Atlanta   Away   Medium   Lose
[9] (D = 0.1000) Detroit   Away   Large    Lose

A próxima etapa no loop do algoritmo principal é normalizar os valores D de modo que a soma seja 1,0 dividindo cada valor D preliminar pela soma dos valores D. A soma dos 10 valores D é aproximadamente 0,8002. Portanto, o D normalizado da tupla de treinamento [0] é aproximadamente 0,1000 / 0,8002 = 0,1249. Os pesos D atualizados finais são:

[0] (D = 0.1249) Detroit   Home   Large    Win
[1] (D = 0.1249) Detroit   Away   Medium   Win
[2] (D = 0.0001) Buffalo   Home   Small    Win
[3] (D = 0.0001) Buffalo   Home   Medium   Win
[4] (D = 0.1249) Atlanta   Away   Large    Win
[5] (D = 0.1249) Chicago   Home   Medium   Win
[6] (D = 0.1249) Chicago   Away   Small    Lose
[7] (D = 0.1249) Chicago   Home   Small    Lose
[8] (D = 0.1249) Atlanta   Away   Medium   Lose
[9] (D = 0.1249) Detroit   Away   Large    Lose

A ideia aqui é que queremos que o algoritmo agora focalize as tuplas de treinamento além das [2] e [3] porque essas tuplas foram consideradas pelo aprendiz [0]. Nesse ponto, o algoritmo pula de volta para a parte superior do loop e atualiza todos os valores épsilon dos aprendizes com base nos pesos D recém-computados, determina o melhor aprendiz não utilizado (aprendiz [5]), computa o alfa do melhor aprendiz (4,49), atualiza os valores D das tuplas de treinamento aplicáveis ([2], [6] e [7]) e computa valores D normalizados de todas as tuplas de treinamento.

Nesse exemplo, o processo continua até que os valores alfa de todos os oito aprendizes fracos tenham sido computados, mas em geral, nem todos os aprendizes fracos serão necessariamente considerados bons aprendizes e a eles serão atribuídos um valor alfa.

Estrutura geral do programa

O programa de demonstração mostrado na Figura 1 é um único aplicativo de console do C#. Usei Visual Studio 2010, mas qualquer versão que dê suporte ao Microsoft .NET Framework 2.0 ou superior funcionará. Criei um novo projeto chamado AdaptiveBoosting e na janela Gerenciador de Soluções renomeei Program.cs com um nome mais descritivo AdaptiveBoostingProgram.cs, que também automaticamente renomeou a classe Program. Exclui todas as instruções using geradas por modelo na parte superior do código-fonte, exceto as referências aos namespaces System e Collections.Generic. O método Main, com algumas instruções WriteLine removidas, algumas outras pequenas edições e uma classe-chave definida por programa para definir objetos de aprendizes fracos, está listado na Figura 2.

Figura 2 Estrutura geral do programa

using System;
using System.Collections.Generic;
namespace AdaptiveBoosting
{
  class Program
  {
    static void Main(string[] args)
    {
      try
      {
        Console.WriteLine("\nBegin adaptive boosting classification demo\n");
        string[] features = new string[] { "Opponent", "Field", "Spread",
          "Result" };
        string[][] values = new string[4][];
        values[0] = new string[] { "Atlanta", "Buffalo", "Chicago",
          "Detroit" }; // opponent
        values[1] = new string[] { "Home", "Away" };  // Field
        values[2] = new string[] { "Small ", "Medium", "Large " }; 
        // Note: Spaces added
        values[3] = new string[] { "Lose", "Win" }; 
        // The dependent/predicted variable
        string[][] rawTrain = new string[10][];
        rawTrain[0] = new string[] { "Detroit", "Home", "Large ", "Win" };
        rawTrain[1] = new string[] { "Detroit", "Away", "Medium", "Win" };
        rawTrain[2] = new string[] { "Buffalo", "Home", "Small ", "Win" };
        rawTrain[3] = new string[] { "Buffalo", "Home", "Medium", "Win" };
        rawTrain[4] = new string[] { "Atlanta", "Away", "Large ", "Win" };
        rawTrain[5] = new string[] { "Chicago", "Home", "Medium", "Win" };
        rawTrain[6] = new string[] { "Chicago", "Away", "Small ", "Lose" };
        rawTrain[7] = new string[] { "Chicago", "Home", "Small ", "Lose" };
        rawTrain[8] = new string[] { "Atlanta", "Away", "Medium", "Lose" };
        rawTrain[9] = new string[] { "Detroit", "Away", "Large ", "Lose" };
        Console.WriteLine("Raw (string) training data for team seattle:\n");
        Console.WriteLine("Opponent Field  Spread   Result");
        Console.WriteLine("===============================");
        ShowMatrix(rawTrain);
        Console.WriteLine("\nConverting and storing training data");
        int[][] train = RawTrainToInt(rawTrain, values);
        Console.WriteLine("Training data in int form:\n");
        ShowMatrix(train, true);
        Console.WriteLine(
          "\nCreating weak categorical stump learners from training data");
        List<Learner> learners = MakeLearners(values, train);
        Console.WriteLine("Completed. Weak learners are:\n");
        for (int i = 0; i < learners.Count; ++i)
          Console.WriteLine("[" + i + "] " + Description(learners[i],
            features, values));
        Console.WriteLine("\nInitializing list of best learner indexes");
        List<int> bestLearners = new List<int>();  // Indexes of good weak learners
        Console.WriteLine(
          "\nUsing adaptive boosting to find best  learners and alphas");
        MakeModel(train, values, learners, bestLearners);
        Console.WriteLine("\nModel completed");
        int numGood = bestLearners.Count;
        Console.Write("Algorithm found " + numGood + " good learners ");
        Console.WriteLine("and associated alpha values");
        Console.WriteLine("\nThe good learners and their alpha value are:");
        for (int i = 0; i < bestLearners.Count; ++i)
        {
          int lrn = bestLearners[i];
          Console.Write("[" + lrn + "] " +
            learners[lrn].alpha.ToString("F2") + "  ");
        }
        Console.Write("\nPredicting outcome when Opponent = Detroit, ");
        Console.WriteLine("Field = Home, Spread = Small\n");
        int[] unknownTuple = new int[] { 3, 0, 0 }; // Detroit, Home, Small
        int Y = Classify(unknownTuple, learners, bestLearners);
        Console.Write("Predicted Y = " + Y + " => ");
        Console.WriteLine("seattle will " + YValueToString(Y, values));
        Console.WriteLine("\nEnd\n");
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    } // Main
    // (Many) static methods here
  } // Class Program
  public class Learner  // Weak learner
  {
    // Definition code here
  }
} // ns

O método Main começa configurando cadeias de caracteres codificadas para as características “Opponent,” “Field,” “Spread” e “Result”. Em seguida, o código em Main configura valores codificados para cada característica: “Atlanta,” “Buffalo,” “Chicago,” “Detroit,” “Home,” “Away,” “Small,” “Medium,” “Large,” “Lose” e “Win.” Para manter minha saída organizada, usei um truque e inseri um espaço em branco ao final de “Small” e “Large.”

Para simplificar, os dados de treinamento também são codificados no programa de demonstração. Em muitos casos seus dados de treinamento serão armazenados em um arquivo de texto ou em uma tabela SQL. Nessas situações convém considerar a verificação de forma programática dos dados de treinamento para determinar os nomes da característica (supostamente de uma linha de cabeçalho do arquivo de texto ou nomes de coluna da tabela SQL) e os valores da característica.

O método RawTrainToInt converte os dados de treinamento em forma de cadeia de caracteres para inteiros de base zero e armazena esses inteiros em uma matriz int[][] chamada train. RawTrainToInt chama um auxiliar chamado ValueToInt. A matriz train tem os valores da variável dependente (Result) armazenados na última coluna. Convém armazenar valores dependentes em uma matriz de colunas separada. Nos casos com conjuntos de dados de treinamento muito grandes, talvez você não possa armazenar o conjunto de dados de treinamento inteiro na memória da máquina. Nesse casos você terá de percorrer o armazenamento de dados externos em vez de uma matriz interna.

O programa de demonstração determina os aprendizes fracos usando o método MakeLearners e uma classe Learner definida por programa. Descreverei esse método e a classe em detalhes na próxima seção deste artigo. Após os aprendizes fracos terem sido criados, o programa de demonstração chama o método MakeModel. MakeModel é o coração do algoritmo do estímulo adaptativo como descrito na seção anterior. O resultado é uma lista classificada, chamada bestLearners, dos índices dos aprendizes a que foram atribuídos valores alfa.

O método Main termina com a previsão do resultado de Seattle para um conjunto de entradas com Opponent como “Detroit”, Field como “Home” e Spread como “Small”, usando o método Classify. Nesse caso, o valor de retorno de Classify é -0,72, que é interpretado como “Lose”.

Fazendo os aprendizes fracos

A implementação de um algoritmo de estímulo adaptativo específico depende até certo ponto da definição específica de um aprendiz fraco. A classe Learner definida por programa tem seis campos:

public int feature;
public int value;
public int predicted;
public double error;
public double epsilon;
public double alpha;

Declarei todos os cinco campos com escopo público para simplificar. O campo característica contém um inteiro que indica qual variável independente é a chave para o aprendiz. Por exemplo, se a característica é 0, o aprendiz fraco é baseado no valor de um adversário. O campo valor contém um inteiro que indica o valor da característica. Por exemplo, se o valor é 3, o aprendiz fraco é baseado na condição. O adversário é Detroit. O campo previsto é -1 ou +1, dependendo de se a categoria real do valor da característica é Lose ou Win.

O campo de erro é tipo double e é a taxa de erro bruto associada ao aprendiz fraco nos dados de treinamento. Por exemplo, se um aprendiz fraco tem característica = 0, valor = 3 e previsto = +1 (significando if Opponent is Detroit then result is Win), então, a taxa de erro bruto dos dados de treinamento na Figura 1 é 0,33 porque um de três itens de dados de treinamento seria previsto incorretamente. Observe que o erro bruto trata cada item de treinamento de forma igual. Acontece que o algoritmo de estímulo adaptativo apresentado neste artigo não precisa realmente do campo erro bruto, portanto esse campo poderia ter sido omitido, mas acredito que a informação seja útil.

O campo épsilon é um termo de erro ponderado. O épsilon de um aprendiz fraco é um termo de erro que considera os pesos D internos atribuídos a cada item de treinamento. Os valores épsilon são usados pelo algoritmo de estímulo adaptativo para computar os pesos alfa. Resumindo, há dois conjuntos de pesos usados na classificação de estímulo adaptativo. Os pesos alfa atribuem uma importância a cada aprendiz fraco e são usados para determinar uma previsão geral. Um erro épsilon é um erro interno associado a um aprendiz fraco que é usado para computar os pesos alfa. Cada tupla de treinamento tem um peso interno (denominado D na literatura de estímulo adaptativo) que é usado para computar os erros épsilon.

Em pseudocódigo, o método MakeLearners funciona da seguinte maneira:

initialize an empty result list of learners
for each feature loop
  for each value of curr feature loop
    scan training data to determine most likely -1, +1 result
    if no most likely result, skip curr value
    create a new learner object with feature, value, predicted
    add learner object to result list
  end each value
end each feature
for each learner in result list
  for each training data item
    if learner isn't applicable to data, skip curr data item
    compute raw error rate
    store raw error into learner
  end each training data item
end each learner

A ideia é que cada valor de característica como “Atlanta” (adversário) ou “Medium” (extensão de ponto) gerará uma regra de aprendiz fraco com base nos dados de treinamento a menos que o valor não apareça nos dados de treinamento (por exemplo, um adversário como “New York”) ou o valor não produza um resultado mais provável porque há o mesmo número de vitórias e derrotas associado ao valor (por exemplo, quando o adversário é “Atlanta” nos dados de demonstração, com uma vitória e uma derrota).

Conclusão

Uma variação importante no algoritmo apresentado neste artigo é lidar com dados que têm valores numéricos. Por exemplo, suponha que os valores da característica extensão de ponto, em vez de serem categóricos “Small”, “Medium” e “Large”, fossem numéricos, como 1,5, 3,0 e 9,5. Uma das principais vantagens da classificação de estímulo adaptativo comparada com algumas outras técnicas de classificação é que o estímulo adaptativo pode lidar facilmente com dados categóricos e numéricos diretamente. Você poderia criar uma classe de aprendiz dedicada que tem uma descrição amigável semelhante a “if Spread is less than or equal to 5.5 then Result is Lose,” ou um aprendiz mais complexo junto com as linhas de “if Spread is between 4.0 and 6.0 then Result is Win.”

Em minha opinião, a classificação de estímulo adaptativo é melhor usada quando a variável dependente a ser prevista tem apenas dois valores possíveis. No entanto, formas avançadas de estímulo adaptativo podem lidar com classificação multinomial. Se desejar investigar isso ou a teoria por trás do estímulo adaptativo em geral, recomendo pesquisar artigos dos pesquisadores R. Schapire e Y. Freund.

A pesquisa de aprendizado automatizado sugere que não há uma única melhor técnica de classificação/previsão de dados. Mas o estímulo adaptativo é uma abordagem muito poderosa que pode formar a base da adição de recursos de previsão a um sistema de software .NET.

Dr. James McCaffrey  trabalha para a Volt Information Sciences Inc., onde gerencia o treinamento técnico de engenheiros de software que trabalham no campus da Microsoft, em Redmond, Washington. Ele trabalhou em vários produtos da Microsoft, como o Internet Explorer e o MSN Busca. Ele é autor de “.NET Test Automation Recipes” (Apress, 2006) e pode ser contatado pelo email jammc@microsoft.com.

Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Darren Gehring (Microsoft)