English Русский Deutsch 日本語
preview
Ciência de Dados e Aprendizado de Máquina (Parte 19): Supercharge Seus Modelos de IA com AdaBoost

Ciência de Dados e Aprendizado de Máquina (Parte 19): Supercharge Seus Modelos de IA com AdaBoost

MetaTrader 5Negociação | 24 julho 2024, 10:15
9 0
Omega J Msigwa
Omega J Msigwa

O que é Adaboost?

Adaboost, abreviação de adaptive boosting, é um modelo de aprendizado de máquina em conjunto que tenta construir um classificador forte a partir de classificadores fracos.

Como funciona?

  • O algoritmo atribui pesos às instâncias com base em sua classificação correta ou incorreta.
  • Ele combina aprendizes fracos usando uma soma ponderada.
  • O aprendiz forte final é uma combinação linear de aprendizes fracos com pesos determinados durante o processo de treinamento.

adaboost no mql5


Por que alguém deveria se importar em usar Adaboost?

Adaboost oferece vários benefícios, incluindo:

  • Melhoria na Precisão – O Boosting pode melhorar a precisão geral do modelo combinando várias previsões de modelos fracos. Média das previsões feitas por todos os modelos para regressão ou votação sobre elas para classificação para aumentar a precisão do modelo finalidade 
  • Robustez contra Overfitting – O Boosting pode reduzir o risco de overfitting atribuindo pesos às entradas classificadas incorretamente.
  • Melhor manejo de dados desbalanceados – O Boosting pode lidar com dados desbalanceados focando mais nos pontos de dados que são classificados incorretamente.
  • Melhor interpretabilidade – O Boosting pode aumentar a interpretabilidade do modelo dividindo o processo de decisão do modelo em vários processos. 


O que é um Stump de Decisão?

Um Stump de Decisão é um modelo simples de aprendizado de máquina usado como um aprendiz fraco em métodos de conjunto como Adaboost. Ele é essencialmente um modelo de aprendizado de máquina simplificado para tomar decisões com base em uma única característica e um limiar. O objetivo de usar um stump de decisão como um aprendiz fraco é capturar um padrão básico nos dados que pode contribuir para melhorar o modelo de conjunto geral.

Abaixo está uma breve explicação da teoria por trás de um stump de decisão, usando o classificador Árvore de Decisão como exemplo:

1. Estrutura:

Um stump de decisão toma uma decisão binária com base em uma única característica e um limiar.

Ele divide os dados em dois grupos: aqueles com valores de característica abaixo do limiar e aqueles com valores acima.

Isso é comumente implementado no construtor da maioria dos nossos classificadores nesta Biblioteca:

 CDecisionTreeClassifier(uint min_samples_split=2, uint max_depth=2, mode mode_=MODE_GINI);
~CDecisionTreeClassifier(void);

2. Treinamento:.

Durante o treinamento, o stump de decisão identifica a característica e o limiar que minimizam um determinado critério, muitas vezes o erro de classificação ponderado.

O erro de classificação é calculado para cada possível divisão, e a que possui o menor erro é escolhida.

- A função fit é onde todo o treinamento é realizado:

void fit(matrix &x, vector &y);

3. Predição:

Para a predição, um ponto de dados é classificado com base em se seu valor de característica está acima ou abaixo do limiar escolhido.

double predict(vector &x);
vector predict(matrix &x);

Comumente, os aprendizes fracos usados em métodos de ensemble como o AdaBoost incluem:


1.Stumps de Decisão/Árvores de Decisão:

Conforme descrito acima, stumps de decisão ou árvores de decisão rasas são comumente usados devido à sua simplicidade.

2. Modelos Lineares:

Modelos lineares como regressão logística ou SVMs lineares podem ser usados como aprendizes fracos.

3. Modelos Polinomiais:

Modelos polinomiais de grau mais alto podem capturar relações mais complexas, e usar polinomiais de baixo grau pode atuar como aprendizes fracos.

4. Redes Neurais (Rasas):

Redes neurais rasas com um pequeno número de camadas e neurônios são às vezes usadas.

5. Modelos Gaussianos:

Modelos gaussianos, como o Naive Bayes Gaussiano, podem ser empregados como aprendizes fracos.

A escolha de um aprendiz fraco depende das características específicas dos dados e do problema em questão. Na prática, stumps de decisão são populares devido à sua simplicidade e eficiência em algoritmos de boosting. A abordagem de ensemble do AdaBoost melhora o desempenho ao combinar as previsões desses aprendizes fracos.

Como um stump de decisão é um modelo, precisamos dar ao construtor da classe Adaboost os argumentos dos parâmetros do nosso modelo fraco.

class AdaBoost
  {
  
protected:
                     vector m_alphas;
                     vector classes_in_data;
                     uint m_min_split, m_max_depth;
                     
                     CDecisionTreeClassifier *weak_learners[]; //store weak_learner pointers for memory allocation tracking
                     CDecisionTreeClassifier *weak_learner;
                     
                     uint m_estimators;
                     
public:
                     AdaBoost(uint min_split, uint max_depth, uint n_estimators=50);
                    ~AdaBoost(void);
                    
                    void fit(matrix &x, vector &y);
                    int predict(vector &x);
                    vector predict(matrix &x);
  };

Este exemplo usa a árvore de decisão, mas qualquer modelo de aprendizado de máquina de classificação pode ser implementado.


Construindo a classe AdaBoost:

O termo número de estimadores refere-se ao número de aprendizes fracos (modelos base ou stumps de decisão) que são combinados para criar o aprendiz forte final em um algoritmo de aprendizado em conjunto. No contexto de algoritmos como AdaBoost ou gradient boosting, esse parâmetro é frequentemente denotado como n_estimators.

AdaBoost::AdaBoost(uint min_split, uint max_depth, uint n_estimators=50)
:m_estimators(n_estimators),
 m_min_split(min_split),
 m_max_depth(max_depth)
 {
   ArrayResize(weak_learners, n_estimators);   //Resizing the array to retain the number of base weak_learners
 }

A partir da seção protegida da classe, você viu o vetor m_alphas , enquanto também ouviu o termo weights várias vezes neste artigo. Abaixo está a explicação:


Valores de Alph

Os valores de alpha representam a contribuição ou peso atribuído a cada aprendiz fraco no conjunto. Esses valores são calculados com base no desempenho de cada aprendiz fraco durante o treinamento.

Valores de alpha mais altos são atribuídos a aprendizes fracos que têm bom desempenho na redução de erros de treinamento.

A fórmula para calcular alpha é geralmente dada por:

fórmula alfa adaboost

onde:

 é o erro ponderado do t-th aprendiz fraco.

Implementation:

double alpha = 0.5 * log((1-error) / (error + 1e-10));


Pesos:

Os vetores de pesos representam a importância de cada instância de treinamento em cada iteração.

Durante o treinamento, os pesos das instâncias classificadas incorretamente são aumentados para focar nos exemplos difíceis de classificar na próxima iteração.

A fórmula para atualizar os pesos das instâncias é geralmente dada por:

pesos adaboost

 é o peso da instância i na iteração 

 é o peso atribuído ao t-th aprendiz fraco.

 é o rótulo verdadeiro da instância 

 é a previsão do t-th aprendiz fraco na instância 

 é um fator de normalização para garantir que a soma dos pesos seja igual a 1.

Implementation:

 for (ulong j=0; j<m; j++)
    misclassified[j] = (preds[j] != y[j]);
 
 error = (misclassified * weights).Sum() / (double)weights.Sum();
 
//--- Calculate the weight of a weak learner in the final model

double alpha = 0.5 * log((1-error) / (error + 1e-10));

//--- Update instance weights

weights *= exp(-alpha * y * preds);
weights /= weights.Sum();


Treinando o modelo Adaboost:

Assim como outras técnicas de ensemble, n modelos (referidos como m_estimators na função abaixo) são usados para fazer previsões nos mesmos dados, o voto da maioria ou outras técnicas podem ser utilizadas para determinar o melhor resultado possível.

void AdaBoost::fit(matrix &x,vector &y)
 {
   m_alphas.Resize(m_estimators);  
   classes_in_data = MatrixExtend::Unique(y); //Find the target variables in the class
      
   ulong m = x.Rows(), n = x.Cols();
   vector weights(m); weights = weights.Fill(1.0) / m; //Initialize instance weights
   vector preds(m);
   vector misclassified(m);
   

   double error = 0;
   
   for (uint i=0; i<m_estimators; i++)
    {      

//---
      
      weak_learner = new CDecisionTreeClassifier(this.m_min_split, m_max_depth);             
              
      weak_learner.fit(x, y); //fitting the randomized data to the i-th weak_learner
      preds = weak_learner.predict(x); //making predictions for the i-th weak_learner
      
             
       for (ulong j=0; j<m; j++)
          misclassified[j] = (preds[j] != y[j]);
       
       error = (misclassified * weights).Sum() / (double)weights.Sum();
       
      //--- Calculate the weight of a weak learner in the final weak_learner
      
      double alpha = 0.5 * log((1-error) / (error + 1e-10));
      
      //--- Update instance weights
      
      weights *= exp(-alpha * y* preds);
      weights /= weights.Sum();
      
      //--- save a weak learner and its weight
      
      this.m_alphas[i] = alpha;
      this.weak_learners[i] = weak_learner;
    }
 }

Assim como qualquer outra técnica de ensemble, bootstrapping é crucial também. Sem ele, todos os modelos e os dados são simplesmente os mesmos, o que poderia fazer com que o desempenho de todos os modelos se tornasse indistinguível um do outro. O bootstrapping precisa ser implementado:

void AdaBoost::fit(matrix &x,vector &y)
 {
   m_alphas.Resize(m_estimators);  
   classes_in_data = MatrixExtend::Unique(y); //Find the target variables in the class
      
   ulong m = x.Rows(), n = x.Cols();
   vector weights(m); weights = weights.Fill(1.0) / m; //Initialize instance weights
   vector preds(m);
   vector misclassified(m);
   
//---

   matrix data = MatrixExtend::concatenate(x, y);
   matrix temp_data;
   
   matrix x_subset;
   vector y_subset;

   double error = 0;
   
   for (uint i=0; i<m_estimators; i++)
    {      
      
      temp_data = data;
      MatrixExtend::Randomize(temp_data, this.m_random_state, this.m_boostrapping);
      
       if (!MatrixExtend::XandYSplitMatrices(temp_data, x_subset, y_subset)) //Get randomized subsets
         {  
            ArrayRemove(weak_learners,i,1); //Delete the invalid weak_learner
            printf("%s %d Failed to split data",__FUNCTION__,__LINE__);
            continue;
         }

//---
      
      weak_learner = new CDecisionTreeClassifier(this.m_min_split, m_max_depth);             
              
      weak_learner.fit(x_subset, y_subset); //fitting the randomized data to the i-th weak_learner
      preds = weak_learner.predict(x_subset); //making predictions for the i-th weak_learner
      
      //printf("[%d] Accuracy %.3f ",i,Metrics::accuracy_score(y_subset, preds));
             
       for (ulong j=0; j<m; j++)
          misclassified[j] = (preds[j] != y_subset[j]);
       
       error = (misclassified * weights).Sum() / (double)weights.Sum();
       
      //--- Calculate the weight of a weak learner in the final weak_learner
      
      double alpha = 0.5 * log((1-error) / (error + 1e-10));
      
      //--- Update instance weights
      
      weights *= exp(-alpha * y_subset * preds);
      weights /= weights.Sum();
      
      //--- save a weak learner and its weight
      
      this.m_alphas[i] = alpha;
      this.weak_learners[i] = weak_learner;
    }
 }
O construtor da classe também teve que ser alterado:
class AdaBoost
  {
  
protected:
                     vector m_alphas;
                     vector classes_in_data;
                     int m_random_state;
                     bool m_boostrapping;
                     uint m_min_split, m_max_depth;
                     
                     CDecisionTreeClassifier *weak_learners[]; //store weak_learner pointers for memory allocation tracking
                     CDecisionTreeClassifier *weak_learner;
                     
                     uint m_estimators;
                     
public:
                     AdaBoost(uint min_split, uint max_depth, uint n_estimators=50, int random_state=42, bool bootstrapping=true);
                    ~AdaBoost(void);
                    
                    void fit(matrix &x, vector &y);
                    int predict(vector &x);
                    vector predict(matrix &x);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
AdaBoost::AdaBoost(uint min_split, uint max_depth, uint n_estimators=50, int random_state=42, bool bootstrapping=true)
:m_estimators(n_estimators),
 m_random_state(random_state),
 m_boostrapping(bootstrapping),
 m_min_split(min_split),
 m_max_depth(max_depth)
 {
   ArrayResize(weak_learners, n_estimators);   //Resizing the array to retain the number of base weak_learners
 }

Obtendo as Previsões da Maioria

Usando os pesos treinados, o classificador Adaboost determina a classe com o máximo de votos, significando que ela tem mais probabilidade de aparecer do que as outras.

int AdaBoost::predict(vector &x)
 {
   // Combine weak learners using weighted sum   
   
   vector weak_preds(m_estimators), 
          final_preds(m_estimators);
          
   for (uint i=0; i<this.m_estimators; i++)
     weak_preds[i] = this.weak_learners[i].predict(x);
  
  return (int)weak_preds[(this.m_alphas*weak_preds).ArgMax()]; //Majority decision class
 }

Agora vamos ver como podemos usar o modelo dentro de um Expert Advisor:

#include <MALE5\Ensemble\AdaBoost.mqh>

DecisionTree::AdaBoost *ada_boost_tree;
LogisticRegression::AdaBoost *ada_boost_logit;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
  
   string headers;
   matrix data = MatrixExtend::ReadCsv("iris.csv",headers);
   
   matrix x; vector y;
   MatrixExtend::XandYSplitMatrices(data,x,y);
   
   ada_boost_tree = new DecisionTree::AdaBoost(2,1,10,42);
   ada_boost_tree.fit(x,y);
   
   vector predictions = ada_boost_tree.predict(x);
   
   printf("Adaboost acc = %.3f",Metrics::accuracy_score(y, predictions));
 
//---
   return(INIT_SUCCEEDED);
  }

Usando o dataset iris.csv apenas para construir o modelo e para fins de depuração. Isso resultou em:

2024.01.17 17:52:27.914 AdaBoost Test (EURUSD,H1)       Adaboost acc = 0.960

Parece que nosso modelo está indo bem até agora, com valores de precisão em torno de 90%, depois que defini o random_state para -1, o que fará com que o GetTickCount seja usado como uma semente aleatória cada vez que o EA é executado, para que eu possa avaliar o modelo em um ambiente muito mais aleatório.

QK      0       17:52:27.914    AdaBoost Test (EURUSD,H1)       Adaboost acc = 0.960
LL      0       17:52:35.436    AdaBoost Test (EURUSD,H1)       Adaboost acc = 0.947
JD      0       17:52:42.806    AdaBoost Test (EURUSD,H1)       Adaboost acc = 0.960
IL      0       17:52:50.071    AdaBoost Test (EURUSD,H1)       Adaboost acc = 0.933
MD      0       17:52:57.822    AdaBoost Test (EURUSD,H1)       Adaboost acc = 0.967

Os mesmos padrões e estruturas de codificação podem ser seguidos para outros weak learners presentes em nossa biblioteca. Veja quando a regressão logística foi usada como um weak learner:

A única diferença em toda a classe é encontrada na função fit, onde o tipo de modelo implementado como weak learner é Regressão Logística:

void AdaBoost::fit(matrix &x,vector &y)
 {
   m_alphas.Resize(m_estimators);  
   classes_in_data = MatrixExtend::Unique(y); //Find the target variables in the class
      
   ulong m = x.Rows(), n = x.Cols();
   vector weights(m); weights = weights.Fill(1.0) / m; //Initialize instance weights
   vector preds(m);
   vector misclassified(m);
   
//---

   matrix data = MatrixExtend::concatenate(x, y);
   matrix temp_data;
   
   matrix x_subset;
   vector y_subset;

   double error = 0;
   
   for (uint i=0; i<m_estimators; i++)
    {      
      
      temp_data = data;
      MatrixExtend::Randomize(temp_data, this.m_random_state, this.m_boostrapping);
      
       if (!MatrixExtend::XandYSplitMatrices(temp_data, x_subset, y_subset)) //Get randomized subsets
         {  
            ArrayRemove(weak_learners,i,1); //Delete the invalid weak_learner
            printf("%s %d Failed to split data",__FUNCTION__,__LINE__);
            continue;
         }

//---
      
      weak_learner = new CLogisticRegression();             
              
      weak_learner.fit(x_subset, y_subset); //fitting the randomized data to the i-th weak_learner
      preds = weak_learner.predict(x_subset); //making predictions for the i-th weak_learner
             
       for (ulong j=0; j<m; j++)
          misclassified[j] = (preds[j] != y_subset[j]);
       
       error = (misclassified * weights).Sum() / (double)weights.Sum();
       
      //--- Calculate the weight of a weak learner in the final weak_learner
      
      double alpha = 0.5 * log((1-error) / (error + 1e-10));
      
      //--- Update instance weights
      
      weights *= exp(-alpha * y_subset * preds);
      weights /= weights.Sum();
      
      //--- save a weak learner and its weight
      
      this.m_alphas[i] = alpha;
      this.weak_learners[i] = weak_learner;
    }
 }


Modelos de IA com AdaBoost no Testador de Estratégias

Ao usar o indicador de banda de Bollinger aplicado ao preço de abertura, estamos tentando treinar nossos modelos para aprender a prever o próximo fechamento de candle, seja ele altista, baixista ou nenhum dos dois (MANTER).

Vamos construir um Expert Advisor para testar nossos modelos no ambiente de negociação, começando com o código para coletar os dados de treinamento:

Coletando os Dados de Treinamento:

//--- Data Collection for training the model

//--- x variables Bollinger band only
   
   matrix dataset;
   
   indicator_v.CopyIndicatorBuffer(bb_handle,0,0,train_bars); //Main LINE
   dataset = MatrixExtend::concatenate(dataset, indicator_v);
   
   indicator_v.CopyIndicatorBuffer(bb_handle,1,0,train_bars); //UPPER BB
   dataset = MatrixExtend::concatenate(dataset, indicator_v);
   
   indicator_v.CopyIndicatorBuffer(bb_handle,2,0,train_bars); //LOWER BB
   dataset = MatrixExtend::concatenate(dataset, indicator_v);
   
//--- Target Variable
   
   int size = CopyRates(Symbol(),PERIOD_CURRENT,0,train_bars,rates);
   vector y(size);
   
   switch(model)
     {
      case  DECISION_TREE:
         {
            for (ulong i=0; i<y.Size(); i++)
              {
                 if (rates[i].close > rates[i].open)
                   y[i] = 1; //buy signal
                 else if (rates[i].close < rates[i].open)
                   y[i] = 2; //sell signal 
                 else
                   y[i] = 0; //Hold signal
              }
         }
        break;
      case LOGISTIC_REGRESSION:
            for (ulong i=0; i<indicator_v.Size(); i++)
              {
                 y[i] = (rates[i].close > rates[i].open); //if close > open buy else sell
              }
        break;
     }
   
   dataset = MatrixExtend::concatenate(dataset, y); //Add the target variable to the dataset
   
   if (MQLInfoInteger(MQL_DEBUG))
    {
       Print("Data Head");
       MatrixExtend::PrintShort(dataset);
    }

Notou a mudança na criação da variável alvo? Como a árvore de decisão é versátil e pode lidar bem com múltiplas classes na variável alvo, ela tem a capacidade de classificar três padrões no mercado, COMPRAR, VENDER e MANTER. Ao contrário do modelo de regressão logística que tem a função sigmoide em seu núcleo e que classifica bem duas classes, 0 e 1, a melhor coisa é preparar a condição da variável alvo para ser COMPRAR ou VENDER.

Treinamento e Teste do Modelo Treinado:

Um Elefante na sala: 

MatrixExtend::TrainTestSplitMatrices(dataset,train_x,train_y,test_x,test_y,0.7,_random_state); 

Esta função divide os dados em amostras de treinamento e teste, dado um estado aleatório para embaralhamento, 70% dos dados para a amostra de teste, enquanto os outros 30% para teste.

Mas antes que possamos usar os dados recém-coletados, A Normalização ainda é crucial para o desempenho do modelo.

//--- Training and testing the trained model
   
   matrix train_x, test_x;
   vector train_y, test_y;
   
   MatrixExtend::TrainTestSplitMatrices(dataset,train_x,train_y,test_x,test_y,0.7,_random_state); //Train test split data | This function splits the data into training and testing sample given a random state and 70% of data to test while the rest 30% for testing
   
   train_x = scaler.fit_transform(train_x); //Standardize the training data
   test_x = scaler.transform(test_x); //Do the same for the test data
   
   Print("-----> ",EnumToString(model));
   
   vector preds;
   switch(model)
     {
      case  DECISION_TREE:
         ada_boost_tree = new DecisionTree::AdaBoost(tree_min_split, tree_max_depth, _n_estimators, -1, _bootstrapping);  //Building the 
        
        //--- Training 
         
         ada_boost_tree.fit(train_x, train_y);
        
         preds = ada_boost_tree.predict(train_x);
         printf("Train Accuracy %.3f",Metrics::accuracy_score(train_y, preds));
         
        //--- Testing
        
         preds = ada_boost_tree.predict(test_x);
         printf("Test Accuracy %.3f",Metrics::accuracy_score(test_y, preds));
         
        break;
      case LOGISTIC_REGRESSION:
         ada_boost_logit = new LogisticRegression::AdaBoost(_n_estimators,-1, _bootstrapping);
         
        //--- Training 
        
         ada_boost_logit.fit(train_x, train_y);
        
         preds = ada_boost_logit.predict(train_x);
         printf("Train Accuracy %.3f",Metrics::accuracy_score(train_y, preds));
         
        //--- Testing
        
         preds = ada_boost_logit.predict(test_x);
         printf("Test Accuracy %.3f",Metrics::accuracy_score(test_y, preds));
         
        break;
     }

Saídas:

PO      0       22:59:11.807    AdaBoost Test (EURUSD,H1)       -----> DECISION_TREE
CI      0       22:59:20.204    AdaBoost Test (EURUSD,H1)       Building Estimator [1/10] Accuracy Score 0.561
OD      0       22:59:27.883    AdaBoost Test (EURUSD,H1)       Building Estimator [2/10] Accuracy Score 0.601
NP      0       22:59:38.316    AdaBoost Test (EURUSD,H1)       Building Estimator [3/10] Accuracy Score 0.541
LO      0       22:59:48.327    AdaBoost Test (EURUSD,H1)       Building Estimator [4/10] Accuracy Score 0.549
LK      0       22:59:56.813    AdaBoost Test (EURUSD,H1)       Building Estimator [5/10] Accuracy Score 0.570
OF      0       23:00:09.552    AdaBoost Test (EURUSD,H1)       Building Estimator [6/10] Accuracy Score 0.517
GR      0       23:00:18.322    AdaBoost Test (EURUSD,H1)       Building Estimator [7/10] Accuracy Score 0.571
GI      0       23:00:29.254    AdaBoost Test (EURUSD,H1)       Building Estimator [8/10] Accuracy Score 0.556
HE      0       23:00:37.632    AdaBoost Test (EURUSD,H1)       Building Estimator [9/10] Accuracy Score 0.599
DS      0       23:00:47.522    AdaBoost Test (EURUSD,H1)       Building Estimator [10/10] Accuracy Score 0.567
OP      0       23:00:47.524    AdaBoost Test (EURUSD,H1)       Train Accuracy 0.590
OG      0       23:00:47.525    AdaBoost Test (EURUSD,H1)       Test Accuracy 0.513
MK      0       23:24:06.573    AdaBoost Test (EURUSD,H1)       Building Estimator [1/10] Accuracy Score 0.491
HK      0       23:24:06.575    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.43700
QO      0       23:24:06.575    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.43432
KP      0       23:24:06.576    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.43168
MD      0       23:24:06.577    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.42909
FI      0       23:24:06.578    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.42652
QJ      0       23:24:06.579    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.42400
IN      0       23:24:06.580    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.42151
NS      0       23:24:06.581    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.41906
GD      0       23:24:06.582    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.41664
DK      0       23:24:06.582    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.41425
IQ      0       23:24:06.585    AdaBoost Test (EURUSD,H1)       Building Estimator [2/10] Accuracy Score 0.477
JP      0       23:24:06.586    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.43700
DE      0       23:24:06.587    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.43432
RF      0       23:24:06.588    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.43168
KJ      0       23:24:06.588    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.42909
FO      0       23:24:06.589    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.42652
NP      0       23:24:06.590    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.42400
CD      0       23:24:06.591    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.42151
KI      0       23:24:06.591    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.41906
NM      0       23:24:06.592    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.41664
EM      0       23:24:06.592    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.41425
EO      0       23:24:06.593    AdaBoost Test (EURUSD,H1)       Building Estimator [3/10] Accuracy Score 0.477
KF      0       23:24:06.594    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.41931
HK      0       23:24:06.594    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.41690
RL      0       23:24:06.595    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.41452
IP      0       23:24:06.596    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.41217
KE      0       23:24:06.596    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.40985
DI      0       23:24:06.597    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.40757
IJ      0       23:24:06.597    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.40533
MO      0       23:24:06.598    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.40311
PS      0       23:24:06.599    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.40093
CG      0       23:24:06.600    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.39877
NE      0       23:24:06.601    AdaBoost Test (EURUSD,H1)       Building Estimator [4/10] Accuracy Score 0.499
EL      0       23:24:06.602    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.41931
MQ      0       23:24:06.603    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.41690
PE      0       23:24:06.603    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.41452
OF      0       23:24:06.604    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.41217
JK      0       23:24:06.605    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.40985
KO      0       23:24:06.606    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.40757
FP      0       23:24:06.606    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.40533
PE      0       23:24:06.607    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.40311
CI      0       23:24:06.608    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.40093
NI      0       23:24:06.609    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.39877
KS      0       23:24:06.610    AdaBoost Test (EURUSD,H1)       Building Estimator [5/10] Accuracy Score 0.499
QR      0       23:24:06.611    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.42037
MG      0       23:24:06.611    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.41794
LK      0       23:24:06.612    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.41555
ML      0       23:24:06.613    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.41318
PQ      0       23:24:06.614    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.41085
FE      0       23:24:06.614    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.40856
FF      0       23:24:06.615    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.40630
FJ      0       23:24:06.616    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.40407
KO      0       23:24:06.617    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.40187
NS      0       23:24:06.618    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.39970
EH      0       23:24:06.619    AdaBoost Test (EURUSD,H1)       Building Estimator [6/10] Accuracy Score 0.497
FH      0       23:24:06.620    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.41565
LM      0       23:24:06.621    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.41329
IQ      0       23:24:06.622    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.41096
KR      0       23:24:06.622    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.40867
LF      0       23:24:06.623    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.40640
NK      0       23:24:06.624    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.40417
OL      0       23:24:06.625    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.40197
RP      0       23:24:06.627    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.39980
OE      0       23:24:06.628    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.39767
EE      0       23:24:06.628    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.39556
QF      0       23:24:06.629    AdaBoost Test (EURUSD,H1)       Building Estimator [7/10] Accuracy Score 0.503
CN      0       23:24:06.630    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.41565
IR      0       23:24:06.631    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.41329
HG      0       23:24:06.632    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.41096
RH      0       23:24:06.632    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.40867
ML      0       23:24:06.633    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.40640
FQ      0       23:24:06.633    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.40417
QR      0       23:24:06.634    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.40197
NF      0       23:24:06.634    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.39980
EK      0       23:24:06.635    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.39767
CL      0       23:24:06.635    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.39556
LL      0       23:24:06.636    AdaBoost Test (EURUSD,H1)       Building Estimator [8/10] Accuracy Score 0.503
HD      0       23:24:06.637    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.44403
IH      0       23:24:06.638    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.44125
CM      0       23:24:06.638    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.43851
DN      0       23:24:06.639    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.43580
DR      0       23:24:06.639    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.43314
CG      0       23:24:06.640    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.43051
EK      0       23:24:06.640    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.42792
JL      0       23:24:06.641    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.42537
EQ      0       23:24:06.641    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.42285
OF      0       23:24:06.642    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.42037
GJ      0       23:24:06.642    AdaBoost Test (EURUSD,H1)       Building Estimator [9/10] Accuracy Score 0.469
GJ      0       23:24:06.643    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [1/10] mse 0.44403
ON      0       23:24:06.643    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [2/10] mse 0.44125
LS      0       23:24:06.644    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [3/10] mse 0.43851
HG      0       23:24:06.644    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [4/10] mse 0.43580
KH      0       23:24:06.645    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [5/10] mse 0.43314
FM      0       23:24:06.645    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [6/10] mse 0.43051
IQ      0       23:24:06.646    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [7/10] mse 0.42792
QR      0       23:24:06.646    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [8/10] mse 0.42537
IG      0       23:24:06.647    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [9/10] mse 0.42285
RH      0       23:24:06.647    AdaBoost Test (EURUSD,H1)       ---> Logistic regression build epoch [10/10] mse 0.42037
KS      0       23:24:06.648    AdaBoost Test (EURUSD,H1)       Building Estimator [10/10] Accuracy Score 0.469
NP      0       23:24:06.652    AdaBoost Test (EURUSD,H1)       Train Accuracy 0.491
GG      0       23:24:06.654    AdaBoost Test (EURUSD,H1)       Test Accuracy 0.447

Até agora, tudo bem! Vamos finalizar nosso Expert Advisor com as linhas de código capazes de executar negociações:

Obtendo os sinais de negociação:

void OnTick()
  {
//--- x variables Bollinger band only | The current buffer only this time

   indicator_v.CopyIndicatorBuffer(bb_handle,0,0,1); //Main LINE
   x_inputs[0] = indicator_v[0];
   indicator_v.CopyIndicatorBuffer(bb_handle,1,0,1); //UPPER BB
   x_inputs[1] = indicator_v[0];
   indicator_v.CopyIndicatorBuffer(bb_handle,2,0,1); //LOWER BB
   x_inputs[2] = indicator_v[0];
   
//---
   
   int signal = INT_MAX;
   switch(model)
     {
      case  DECISION_TREE:
        x_inputs = scaler.transform(x_inputs); //New inputs data must be normalized the same way
        signal = ada_boost_tree.predict(x_inputs);   
        break;
      case LOGISTIC_REGRESSION:
         x_inputs = scaler.transform(x_inputs); //New inputs data must be normalized the same way
         signal = ada_boost_logit.predict(x_inputs);
        break;
     }
  }

Lembre-se, 1 representa o sinal de compra para a árvore de decisão, 0 representa o sinal de compra para a regressão logística; 2 representa o sinal de venda para a árvore de decisão; 1 representa o sinal de venda para a regressão logística. Não nos importamos com o sinal 0 que representa manter para a árvore de decisão. Vamos unificar esses sinais para serem identificados como 0 e 1 para sinais de compra e venda, respectivamente.

case  DECISION_TREE:
  
  x_inputs = scaler.transform(x_inputs); //New inputs data must be normalized the same way
  signal = ada_boost_tree.predict(x_inputs);   
  
   if (signal == 1) //buy signal for decision tree
     signal = 0;
   else if (signal == 2)
     signal = 1;
   else
     signal = INT_MAX; //UNKNOWN NUMBER FOR HOLD
  break;

Uma estratégia simples feita a partir de nossos modelos:

 SymbolInfoTick(Symbol(), ticks);
 
 if (isnewBar(PERIOD_CURRENT))
  {        
   if (signal == 0) //buy signal
     {
        if (!PosExists(MAGIC_NUMBER, POSITION_TYPE_BUY)) 
          m_trade.Buy(lot_size, Symbol(), ticks.ask, ticks.ask-stop_loss*Point(), ticks.ask+take_profit*Point());
     }
     
   if (signal == 1)
     {
       if (!PosExists(MAGIC_NUMBER, POSITION_TYPE_SELL)) 
         m_trade.Sell(lot_size, Symbol(), ticks.bid, ticks.bid+stop_loss*Point(), ticks.bid-take_profit*Point());
     }
  }

Resultados no testador de estratégias | de janeiro de 2020 a fevereiro de 2023 | Intervalo de tempo de 1 HORA:

Árvore de Decisão Adaboost:

árvore de decisão adaboost

Regressão Logística Adaboost:

regressão logística adaboost 1hr tf

Ambos os desempenhos no INTERVALO DE TEMPO DE UMA HORA estão muito longe de serem bons. Uma das principais razões para isso é que nossa estratégia é baseada nas barras atuais. Em minha experiência, esse tipo de estratégia é mais adequado para intervalos de tempo maiores, pois uma única barra representa um movimento significativo, ao contrário das pequenas barras que ocorrem 24 vezes por dia. Vamos tentar o INTERVALO DE TEMPO DE 12 HORAS.

Todos os parâmetros foram mantidos os mesmos, exceto pelo train_bars, que foi reduzido de 1000 para 100, pois intervalos de tempo maiores não têm muitas barras para solicitar o histórico de preços no passado.

Árvore de Decisão Adaboost:

árvore de decisão adaboost

Regressão Logística Adaboost:

regressão logística adaboost 12 hr tf


Em conclusão:

AdaBoost emerge como um algoritmo potente capaz de melhorar significativamente o desempenho dos modelos de IA discutidos ao longo desta série de artigos. Embora venha com um custo computacional, o investimento se mostra válido quando implementado de forma judiciosa. AdaBoost tem encontrado aplicações em diversos setores e indústrias, incluindo finanças, entretenimento, educação, entre outros.

Ao concluirmos nossa exploração, é essencial reconhecer a versatilidade do algoritmo e sua capacidade de abordar desafios complexos de classificação, aproveitando a força coletiva dos aprendizes fracos. As Perguntas Frequentes (FAQs) abaixo visam oferecer clareza e insight, abordando questões comuns que podem surgir durante sua exploração do AdaBoost.


Perguntas Frequentes (FAQs) sobre Adaboost:


Pergunta: Como o AdaBoost funciona?

Resposta: O AdaBoost funciona treinando iterativamente aprendizes fracos (geralmente modelos simples como tocos de decisão) no conjunto de dados, ajustando os pesos das instâncias classificadas incorretamente a cada iteração. O modelo final é uma soma ponderada dos aprendizes fracos, com pesos maiores dados aos mais precisos.


Pergunta: O que são aprendizes fracos no AdaBoost?

Resposta: Aprendizes fracos são modelos simples que têm um desempenho ligeiramente melhor que o acaso. Tocos de decisão (árvores de decisão rasas) são comumente usados como aprendizes fracos no AdaBoost, mas outros algoritmos também podem servir a esse propósito.


Pergunta: Qual é o papel dos pesos das instâncias no AdaBoost?

Resposta: Os pesos das instâncias no AdaBoost controlam a importância de cada instância de treinamento durante o processo de aprendizado. Inicialmente, todos os pesos são definidos igualmente, e são ajustados a cada iteração para focar mais nas instâncias classificadas incorretamente, melhorando a capacidade do modelo de generalizar.


Pergunta: Como o AdaBoost lida com erros cometidos por aprendizes fracos?

Resposta: O AdaBoost atribui pesos maiores às instâncias classificadas incorretamente, forçando os aprendizes fracos subsequentes a focar mais na correção desses erros. O modelo final dá mais peso aos aprendizes fracos com taxas de erro mais baixas.


Pergunta: O AdaBoost é sensível a ruídos e outliers?

Resposta: O AdaBoost pode ser sensível a ruídos e outliers, pois tenta corrigir as classificações incorretas. Outliers podem receber pesos maiores, influenciando o modelo final. Aprendizes fracos robustos ou técnicas de pré-processamento de dados podem ser aplicados para mitigar essa sensibilidade.


Pergunta: O AdaBoost sofre de sobreajuste?

Resposta: O AdaBoost pode estar sujeito ao sobreajuste se os aprendizes fracos forem muito complexos ou se o conjunto de dados contiver ruídos. Usar aprendizes fracos mais simples e aplicar técnicas como validação cruzada pode ajudar a prevenir o sobreajuste.


Pergunta: O AdaBoost pode ser usado para problemas de regressão?

Resposta: O AdaBoost é projetado principalmente para tarefas de classificação, mas pode ser adaptado para regressão modificando o algoritmo para prever valores contínuos. Técnicas como AdaBoost.R2 existem para problemas de regressão.


Pergunta: Existem alternativas ao AdaBoost?

Resposta: Sim, existem outros métodos de aprendizado em conjunto, como Random Forest, Gradient Boosting e XGBoost. Cada método tem seus pontos fortes e fracos, e a escolha depende das características específicas dos dados e do problema em questão.


Pergunta: Em quais situações o AdaBoost é particularmente eficaz?

Resposta: O AdaBoost é eficaz ao lidar com uma variedade de aprendizes fracos e em cenários onde há necessidade de combinar múltiplos classificadores para criar um modelo robusto. Ele é frequentemente usado em detecção de faces, classificação de textos e outras aplicações do mundo real.


Para se manter atualizado sobre o progresso do desenvolvimento e correções de bugs deste algoritmo, bem como de muitos outros, por favor visite o repositório GitHub em https://github.com/MegaJoctan/MALE5.


Até mais.

Anexos:

Arquivo Descrição|Uso
Adaboost.mqh Contém classes de namespace Adaboost tanto para regressão logística quanto para a árvore de decisão.
Logistic Regression.mqh Contém a classe principal de regressão logística
MatrixExtend.mqh Contém funções adicionais de manipulação de matrizes
metrics.mqh Uma biblioteca contendo código para medir o desempenho de modelos de aprendizado de máquina
preprocessing.mqh Uma classe contendo funções para pré-processamento de dados para torná-los adequados para aprendizado de máquina
tree.mqh Biblioteca de árvore de decisão pode ser encontrada neste arquivo
AdaBoost Test.mq5(EA) O principal Expert Advisor de teste, todo o código explicado aqui é executado dentro deste arquivo

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14034

Arquivos anexados |
Compreendendo os Paradigmas de Programação (Parte 2): Uma Abordagem Orientada a Objetos para Desenvolver um Expert Advisor de Ação de Preço Compreendendo os Paradigmas de Programação (Parte 2): Uma Abordagem Orientada a Objetos para Desenvolver um Expert Advisor de Ação de Preço
Aprenda sobre o paradigma de programação orientada a objetos e sua aplicação no código MQL5. Este segundo artigo aprofunda-se nas especificidades da programação orientada a objetos, oferecendo experiência prática através de um exemplo prático. Você aprenderá como converter nosso expert advisor de ação de preço procedural desenvolvido anteriormente usando o indicador EMA e dados de preços de velas para um código orientado a objetos.
Inferência causal em problemas de classificação de séries temporais Inferência causal em problemas de classificação de séries temporais
Neste artigo, examinaremos a teoria da inferência causal usando aprendizado de máquina, bem como a implementação de uma abordagem personalizada em Python. A inferência causal e o pensamento causal têm suas raízes na filosofia e psicologia e desempenham um papel importante na nossa compreensão da realidade.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Indicador Customizado: Traçar os Pontos de Entradas Parciais em contas Netting Indicador Customizado: Traçar os Pontos de Entradas Parciais em contas Netting
Nesse artigo, veremos uma forma interessante e diferente de construir um indicador em MQL5. Ao invés de focar em uma tendência ou padrão gráfico, será no gerenciamento de nossas próprias posições, nas entradas e saídas parciais. Usaremos intensivamente arrays dinâmicos e algumas funções de negociação (Trade) relacionadas a histórico de transações e a posições abertas, naturalmente, para indicar no gráfico onde ocorreram essas negociações.