English
preview
Ein Algorithmus zur Auswahl von Merkmalen, der energiebasiertes Lernen in reinem MQL5 verwendet

Ein Algorithmus zur Auswahl von Merkmalen, der energiebasiertes Lernen in reinem MQL5 verwendet

MetaTrader 5Beispiele | 27 Juni 2024, 12:18
39 0
Francis Dube
Francis Dube

Einführung

Im Bereich des algorithmischen Handels hat der weit verbreitete Einsatz von maschinellem Lernen zur Anwendung von Data-Mining-Techniken geführt, um verborgene Muster in Finanzdaten aufzudecken. In diesem Umfeld stehen Praktiker oft vor der Herausforderung, aus einer Vielzahl von Variablen diejenigen herauszufiltern, die am ehesten zur Erreichung bestimmter Ziele oder zur Lösung bestimmter Probleme beitragen können. In diesem Artikel wird die Implementierung eines Algorithmus zur Auswahl von Merkmalen untersucht, mit dem die Relevanz einer Reihe von Kandidatenvariablen für eine bestimmte Vorhersageaufgabe bewertet werden soll.

Yun Li, Jennie Si, Guojing Zhou, Shasha Huang und Songcan Chen haben gemeinsam ein Forschungspapier mit dem Titel „FREL: A Stable Feature Selection Algorithm“ veröffentlicht. In diesem Beitrag wird ein Algorithmus mit dem Namen „Feature Weighting as Regularized Energy-Based Learning“ (FREL) vorgestellt, der als Merkmalsauswahl- oder Gewichtungsverfahren dient und sowohl Genauigkeit als auch Stabilität bieten soll. In unserer Diskussion geben wir einen Überblick über die theoretischen Grundlagen des regularisierten, energiebasierten Lernens und der Merkmalsgewichtung. Darüber hinaus veranschaulichen wir die Wirksamkeit des vorgeschlagenen Ansatzes durch die Implementierung eines MQL5-Beispielprogramms, das als Skript erstellt wurde, um das Potenzial der Methode als Werkzeug für die Merkmalsauswahl hervorzuheben.


Gewichtete Nächste-Nachbarn-Klassifizierung

Das FREL-Konzept basiert auf einer Technik, die als gewichtete Nächste-Nachbarn-Klassifikation bekannt ist und die Entfernungen zwischen Punkten in einem Datensatz nutzt, um Vorhersagen zu treffen. Durch die Festlegung geeigneter Gewichtungen für jedes Merkmal verbessert diese Methode die Vorhersagegenauigkeit. Die gewichtete Nächste-Nachbarn-Klassifizierung ist eine Variante des k-NN-Algorithmus (k-NN = k-nearest neighbor), der beim maschinellen Lernen für Klassifizierungsaufgaben weit verbreitet ist. Bei der standardmäßigen k-NN-Klassifikation untersucht der Algorithmus bei der Klassifizierung eines neuen Datenpunkts die k nächstgelegenen Datenpunkte im Trainingssatz und weist dem neuen Datenpunkt schließlich die Mehrheitsklasse unter diesen Nachbarn zu.

Bei der gewichteten Nearest-Neighbour-Klassifikation werden jedoch nicht einfach die Voten der nächsten Nachbarn addiert, sondern die Voten der einzelnen Nachbarn werden entsprechend ihrer Entfernung zum neuen Datenpunkt gewichtet. Der Grund dafür ist, dass nähere Nachbarn einen stärkeren Einfluss auf die Klassifizierungsentscheidung ausüben sollten als weiter entfernte Nachbarn. Bei diesem Gewichtungsprozess wird der Abstand zwischen dem neuen Datenpunkt und jedem Punkt im Trainingssatz berechnet. Zu den häufig verwendeten Abstandsmetriken gehören der euklidische Abstand, der Manhattan-Abstand oder die Kosinusähnlichkeit, die je nach den Merkmalen der Daten ausgewählt werden. In diesem Zusammenhang verwenden wir die Manhattan-Distanz, die auch als City-Block-Distanz bezeichnet wird, zwischen Datenpunkten. Die Formel zur Berechnung dieses Abstands lautet wie folgt. Wobei w die Gewichte sind und ein Testfall relativ zu anderen Trainingsdaten bewertet wird, die als Trainingsfall angegeben sind

Gewichtete Nächste-Nachbarn-Abstandsformel


Verstehen von energiebasierten Modellen

Das energiebasierte Modell dient beim maschinellen Lernen als vielseitiger Rahmen, der sowohl für überwachte als auch für nicht überwachte Lernaufgaben anwendbar ist. Es funktioniert nach dem Prinzip, verschiedenen Datenkonfigurationen Energiewerte zuzuordnen und ein Modell zu lernen, das in der Lage ist, zwischen erwünschten und unerwünschten Konfigurationen zu unterscheiden. Dies wird erreicht, indem die Energie der beobachteten Daten minimiert und die Energie der nicht beobachteten oder unerwünschten Datenkonfigurationen maximiert wird.

Das Herzstück energiebasierter Modelle ist die Definition einer Energiefunktion, die mit E() bezeichnet wird. Diese Funktion nimmt als Eingabe eine Konfiguration von Eingabevariablen oder Prädiktoren zusammen mit einem Satz von Modellparametern. Die Ausgabe der Energiefunktion gibt einen Hinweis auf die Relevanz der Konfiguration der Eingangsvariablen. Im Zusammenhang mit der Bewertung eines Regressionsmodells könnte die Energiefunktion beispielsweise als mittlerer quadratischer Fehler dargestellt werden. Wenn relevante Prädiktoren in die Gleichung für den mittleren quadratischen Fehler eingegeben werden, ist der Ausgabewert tendenziell kleiner, was eine höhere Relevanz widerspiegelt. Umgekehrt führen schlechte Prädiktoren zu größeren mittleren quadratischen Fehlerwerten. Die Energiefunktion ordnet jeder denkbaren Konfiguration von Variablen einen skalaren Wert zu.

Das Ziel des Trainings eines energiebasierten Modells ist es, die Parameter der Energiefunktion so zu erlernen, dass es relevanten Eingangsvariablen niedrige Energien und irrelevanten Variablen hohe Energien zuweist. Dazu muss eine Zielfunktion definiert werden, die hohe Energien für korrekte Variablen und niedrige Energien für falsche Variablen bestraft. Zu diesem Zweck soll diejenige Konfiguration fehlerhafter Variablen ermittelt werden, die die niedrigste Energie liefert und eine Stichprobe darstellt, die wahrscheinlich zu fehlerhaften Vorhersagen des Modells führt. Die nachstehende Funktion stellt die Energie der Konfiguration der Eingaben, x, und des Modellparameters, w, dar, die den falschen Wert, y, ausgibt, der zu niedrig ist, um von Konfigurationen der Eingabevariablen zu unterscheiden, die genaue Vorhersagen erzeugen. 

Energieformel für die falsche Konfiguration mit der niedrigsten Energie

Letztlich zielt die Zielfunktion darauf ab, die Diskrepanz zwischen der falschen Konfiguration mit der niedrigsten Energie und der nächstgelegenen richtigen Konfiguration der Variablen zu maximieren. Die Energie einer solchen Konfiguration ist unten angegeben.

Energieformel für die nächstgelegene korrekte Konfiguration der Variablen

Die Zielfunktion, die als Verlustfunktion bezeichnet wird, besteht aus einer gemittelten Verlustfunktion pro Stichprobe. Nachfolgend als Log-Verlust angegeben.

Durchschnittliche Verlustfunktion pro Stichprobe (log. Verlust)

Als Verlustfunktion pro Stichprobe können verschiedene Verlustkriterien dienen, wie z. B. Scharnierverlust, logarithmischer Verlust, quadratischer Verlust und quadratisch-exponentieller Verlust, wobei die Wahl von der Anwendung abhängt.

Zusammengefasst sind dies die grundlegenden Konzepte des FREL. Der folgende Abschnitt befasst sich mit den Besonderheiten des Algorithmus selbst.


Der FREL-Algorithmus

Um den FREL-Algorithmus effektiv anzuwenden, müssen einige grundlegende Überlegungen beachtet werden. Erstens ist es wichtig, die Trainingsdaten sorgfältig auszuwerten. FREL ist ideal für Datensätze geeignet, die eine Reihe von Kandidatenvariablen auf ein einziges Ziel abbilden. Ebenso wichtig ist es, sicherzustellen, dass die Variablen eine ähnliche Größenordnung haben. Wenn der FREL Kandidatenprädiktoren mit inkonsistenter Skalierung ausgesetzt wird, können die Endergebnisse erheblich verzerrt werden.

Zweitens: Da FREL ein energiebasiertes Lernverfahren ist, muss eine Energiefunktion definiert werden, die Gewichtungsparameter enthält. Daher sollte das verwendete Modell so konfiguriert sein, dass es eine Reihe von Kandidatenvariablen zusammen mit den entsprechenden Gewichtungen akzeptiert. Betrachtet man beispielsweise den mittleren quadratischen Fehler als Energiefunktion und handelt es sich bei dem Modell um ein Regressionsmodell, so ist die Einbeziehung von Gewichtungsparametern relativ einfach. Jedes Gewicht würde mit einem Prädiktorkandidaten gepaart werden.

Schließlich muss eine Verlustfunktion pro Stichprobe ausgewählt werden, um die Verlustfunktion zu bestimmen. Die Verlustfunktion, die die Gewichtungsparameter des Modells enthält, ist die Funktion (der Funktionen), die minimiert wird, um die optimalen Gewichte zu erhalten.

Die wichtigsten Schritte des FREL-Algorithmus sind wie folgt

Trainingsdaten-Matrix

  1. Beginnen wir mit einem Trainingsdatensatz, der n Beobachtungen mit d Kandidatenprädiktoren umfasst, die n Zielwerten entsprechen. Ziel ist es, aus der Menge der d Kandidaten die relevantesten Prädiktoren zu ermitteln, um die Zielwerte zu bestimmen. Dies führt dazu, dass jedem der d Prädiktoren eine Gewichtung zugewiesen wird, die die Bedeutung der Variablen im Vergleich zu den anderen angibt. Ein größeres Gewicht bedeutet eine größere Relevanz bei der Festlegung des Zielwerts. 
  2. Anfangs wiesen wir allen Gewichten den Wert 1 zu.
  3.  Die gewichtete Klassifizierung der nächsten Nachbarn werden auf jede Beobachtung in den Trainingsdaten angewendet, um die Konfiguration der falschen Variablen mit der niedrigsten Energie und die nächstgelegene Konfiguration der richtigen Variablen mit hoher Energie zu identifizieren. Wir verwenden diese Energiewerte, um den Verlust pro Probe unter Verwendung der ausgewählten Verlustfunktion zu berechnen.
  4.  Schließlich minimieren wir die objektive Verlustfunktion, optional mit der Regulierung, unter Verwendung eines geeigneten Optimierungsverfahrens. Dies ist der Kern des FREL-Algorithmus.
In ihrem Forschungspapier zeigen die Autoren auch eine Verbesserung des Kernalgorithmus durch den Einsatz von Bootstrapping. Die Stichproben müssen ohne Ersetzung durchgeführt werden, und die sich ergebenden Gewichtungen sind die gemittelten Werte aus jeder Bootstrap-Stichprobe.


MQL5-Implementierung von FREL

Die in diesem Text vorgestellte FREL-Implementierung nutzt die Powell‘sche Optimierungsmethode. Die verwendete Optimierungsmethode ist zwar nicht entscheidend, doch sollten die Ergebnisse bei allen Methoden relativ einheitlich sein. In dieser Implementierung wird die Methode von Powell als Klasse „PowellsMethod“ dargestellt, die in Powells.mqh definiert ist. Der FREL-Algorithmus ist in der Klasse „FREL“ gekapselt, abgeleitet von „PowellsMethod“, die in frel.mqh angegeben ist.

//+------------------------------------------------------------------+
   //| constructor                                                      |
   //+------------------------------------------------------------------+

                     FREL(matrix &in_data,int numboot=1, int bootsize=0)
     {
      m_data = in_data;
      m_num_boot=(numboot>0)?numboot:1;
      m_bootsize=(bootsize>2 && bootsize<=int(m_data.Rows()) && m_num_boot>1)?bootsize:int(m_data.Rows());
      
      
      if(ArrayResize(m_indices, int(m_data.Rows()))!=int(m_data.Rows()) ||
         ArrayResize(m_target_bin, int(m_data.Rows()))!=int(m_data.Rows()) ||
         ArrayResize(m_trial_weights, int(m_data.Cols()-1))!=int(m_data.Cols()-1) ||
         ArrayResize(m_work_weights, int(m_data.Cols()-1))!=int(m_data.Cols()-1)
        )
        {
         Print(__FUNCTION__, " error ", GetLastError());
         m_memory_allocated = false;
        }
      else
         m_memory_allocated = true;
     }

Schauen wir uns die Beschreibung des parametrischen Konstruktors an. Es wird mit mindestens einem Parameter aufgerufen: einer Matrix von Trainingsdaten. Es ist wichtig zu wissen, wie die Trainingsdaten in der Matrix strukturiert werden sollten. Jede Zeile steht für eine Beobachtung oder eine einzelne Stichprobe, während die Spalten die zu bewertenden Variablen oder Prädiktoren darstellen. Das Ziel sollte sich in der letzten Spalte der Matrix befinden. Die optionalen Parameter des Konstruktors werden in der nachstehenden Tabelle näher erläutert.

 Parameter Name
 Datentyp
Standardwert
 Beschreibung
numboot
integer
1
„numboot“ legt die Anzahl der Bootstraps fest, die durchgeführt werden sollen.
bootsize
integer
0
„bootsize“ definiert die Größe der einzelnen Bootstraps. Seien Sie vorsichtig bei der Einstellung dieses Parameters. Wenn ein Wert verwendet wird, der größer ist als die Anzahl der Beobachtungen in der Matrix, fällt „numboot“ automatisch auf 1 zurück und „bootsize“ auf die Anzahl der Beobachtungen.

Es gibt nur eine Methode, mit der sich die Nutzer vertraut machen müssen, um die Klasse „FREL“ zu nutzen: "WeighVars()."

//+-----------------------------------------------------------------------+
   //| Find the most relevant variables from a dataset of candidate variables|
   //+-----------------------------------------------------------------------+

   bool               WeighVars(int num_bins_target, double reg_factor,int &index[],double &weights[])
     {
      
      if(!m_memory_allocated)
        {
         Print(" INTERNAL ERROR ");
         return false;
        }
        
        
      if(num_bins_target<=1 || num_bins_target>int(m_data.Rows()))
       {
        Print(__FUNCTION__, " invalid function parameter: num_bins_target. Parameter should be >=2 ");
        return false;
       }  

      int ret=0;
      double target[], target_thresholds[] ;
      double sum ;

      int n_cases = int(m_data.Rows());
      m_reg_factor = MathAbs(reg_factor);
      m_loss = 0.0;


      if(ArrayResize(index,int(m_data.Cols()-1))!=int(m_data.Cols()-1) ||
         !np::vecAsArray(m_data.Col(m_data.Cols()-1),target)
        )
        {
         Print(__FUNCTION__, " error ", GetLastError());
         return false;
        }

      int k = num_bins_target ;
      if(!bin_array(target, k, target_thresholds, m_target_bin))
         return false;

      if(k<num_bins_target)
        {
         Print("error bins of target vector ", num_bins_target," : ", k);
         return false;
        }

      for(int i=0 ; i<n_cases ; i++)
        {
         if(m_target_bin[i] >= num_bins_target)
           {
            Print("error m_target_bin array at index ", i, " is ",m_target_bin[i], " should be less than ", num_bins_target);
            return false;
           }
        }

      ret = calc_wt(num_bins_target,m_loss,weights);

      if(ret<0)
         return false;

      sum = 0.0 ;
      for(ulong var=0 ; var<m_data.Cols()-1 ; var++)
        {
         weights[var] = m_data.Col(var).Std() * exp(weights[var]);
         sum += weights[var] ;
        }

      for(ulong var=0 ; var<m_data.Cols()-1 ; var++)
        {
         weights[var] *= 100.0 / sum ;
         index[var] = int(var) ;
        }

      MathQuickSortDescending(weights,index,0,int(weights.Size()-1)) ;

      return true;
     }

Diese Methode wertet die im Konstruktor angegebenen Trainingsdaten aus. Sie gibt einen booleschen Wert zurück, wobei „false“ anzeigt, dass der Vorgang nicht abgeschlossen werden konnte. Die Parameter dieser Methode sind wie folgt:

  • „num_bins_target“: Eine ganze Zahl, die die Anzahl der „bins“ angibt, in die die Zielwerte unterteilt werden. Dieser Parameter sollte auf eine beliebige ganze Zahl >= 2 aber <= der Anzahl der Beobachtungen in den Trainingsdaten gesetzt werden.
  • „reg_factor“: Ein positiver double-Wert, der den Grad der Regularisierung steuert. Ein Wert von 0 deaktiviert die Regularisierung.
  • „index[]“: Ein ganzzahliges Array, in das ein Teil der Ergebnisse der Operation geschrieben werden soll. Sie enthält die ursprünglichen Spaltenindizes, wie sie dem Konstruktor übergeben wurden, in absteigender Reihenfolge der Relevanz für das Ziel.
  • „weights[]“: Ein double-Array, das die optimalen Gewichtungen in absteigender Reihenfolge enthält.

Beim Aufruf von „WeighVars()“ werden die Zielwerte aus der Matrix extrahiert und in ein Array gestellt, um einen Aufruf der privaten Methode „bin_array()“ vorzubereiten, die das Array in ungefähr gleich große Kategorien segmentiert, „binnt“, und nach erfolgreicher Beendigung zwei Arrays ausgibt: „upperbound_thresholds[]“ ist ein Array mit den oberen Schwellenwerten für jedes Segment, während das Integer-Array „categories[]“ Indexwerte enthält, die das Segment darstellen, zu dem jeder entsprechende Zielwert gehört. Jeder dieser Werte wird überprüft, um sicherzustellen, dass alle Zielwerte korrekt „gebinnt“ wurden.

//+------------------------------------------------------------------+
   //| calculates the optimal weights of candidate variables            |
   //+------------------------------------------------------------------+

   int               calc_wt(int num_bins_target,double &loss_value, double &w[])
     {
      int ret,rand_error, class_count[] ;

      ret = 0;

      if(ArrayResize(class_count,num_bins_target)!=num_bins_target || (w.Size()!=uint(m_data.Cols()-1) && ArrayResize(w,int(m_data.Cols()-1))!=int(m_data.Cols()-1)))
        {
         Print(__FUNCTION__, " error ", GetLastError());
         return -1;
        }

      ArrayInitialize(w,0.0);
      loss_value = 0.0 ;

      for(ulong i=0 ; i<m_data.Rows() ; i++)
         m_indices[i] = int(i) ;
     
      for(int ibootstrap=0 ; ibootstrap<m_num_boot; ibootstrap++)
        { 
         Comment(" Bootstrap iteration ", ibootstrap+1);
           
         ArrayInitialize(class_count,0);

         int ii, j, k, m;

         ii = int (m_data.Rows()) ;
         while(ii > 1)
           {
            m = int (m_data.Rows()) - ii ;
            if(m >= m_bootsize)
               break ;
            j = (int)(MathRandomUniform(0.0,1.0,rand_error) * ii) ;
            if(j >= ii)
               j = ii - 1 ;
            k = m_indices[m] ;
            m_indices[m] = m_indices[m+j] ;
            m_indices[m+j] = k ;
            --ii ;
            ++class_count[m_target_bin[m_indices[m]]] ;
           }
           

         for(int i=0 ; i<num_bins_target ; i++)
           {
            if(class_count[i] < 2)
               Print(__FUNCTION__, "  class at ", i, " has less than 2 members. Consider adjusting Frel parameters. (number of partitions or bootstrap sample size)");
           }
            
         ArrayInitialize(m_trial_weights,0.0);

         ret += Optimize(m_trial_weights);
         loss_value += PowellsMethod::GetFret() ;

         for(ulong i=0 ; i<m_data.Cols()-1 ; i++)
            w[i] += m_trial_weights[i] ; 

        }

      for(ulong i=0 ; i<m_data.Cols()-1; i++)
        w[i] /= double(m_num_boot) ;

      return ret ;

     }

Die Gewichtsschätzung beginnt mit einem Aufruf von „calc_wt()“. Hier wird ein Bootstrap-Sampling durchgeführt, bei dem die Daten gemischt werden, bevor die ursprünglichen Gewichte optimiert werden. Die Optimierung erfolgt durch die übergeordnete Klassenmethode „Optimize()“. Die optimalen Gewichte für jeden Bootstrap werden in „w[]“ summiert und vor dem Beenden von „calc_wt()“ gemittelt.

//+------------------------------------------------------------------+
   //| function minimized by Powells optimization method                |
   //+------------------------------------------------------------------+
   virtual double          func(const double& p[])
     {
      double pen = 0.0 ;

      for(ulong i=0 ; i<m_data.Cols()-1 ; i++)
        {
         if(p[i] > 4.0)
           {
            m_work_weights[i] = exp(4.0) + p[i] - 4.0 ;
            pen += (p[i] - 4.0) * (p[i] - 4.0) ;
           }
         else
            if(p[i] < -3.0)
              {
               m_work_weights[i] = exp(-3.0) + p[i] + 3.0 ;
               pen += (p[i] + 3.0) * (p[i] + 3.0) ;
              }
            else
               m_work_weights[i] = exp(p[i]) ;
        }

      return (loss(m_work_weights) + pen) ;
     }

Denken Sie daran, dass die zu minimierende Funktion das Verlustfunktional ist, das durch eine überschriebene Methode der übergeordneten Klasse namens „func()“ dargestellt wird.

//+------------------------------------------------------------------+
   //| calculates the loss function                                     |
   //+------------------------------------------------------------------+
   double            loss(double &w[])
     {
      double totaloss = total_loss(w);

      totaloss/=double(m_data.Rows());

      if(m_reg_factor>0.0)
        {
         for(ulong i=0; i<m_data.Cols()-1;i++)
            totaloss+=m_reg_factor*pow(w[i],2.0);
        }

      return totaloss;
     }

Innerhalb von „func()“ wird die Methode „loss()“ aktiviert, die die Berechnung der Verlustfunktion pro Probe auslöst, die als private Methode „total_loss()“ implementiert ist.

//+------------------------------------------------------------------+
   //|  loss over all data                                              |
   //+------------------------------------------------------------------+

   double            total_loss(double &w[])
     {
      int category,first, other ;
      double  distance, top, bottom, loss ;

      loss = 0.0 ;
      for(int i=0; i<m_bootsize; i++)
        {
         other = m_indices[i] ;
         category = m_target_bin[other] ;
         top = bottom = DBL_MAX ;

         for(int iother=0 ; iother<m_bootsize; iother++)
           {
            first = m_indices[iother] ;
            if(first == other)
               continue ;

            distance = 0.0 ;
            for(ulong v=0 ; v<m_data.Cols()-1; v++)
              {
               distance += w[v] * fabs(m_data[other][v] - m_data[first][v]) ;
              }

            if(m_target_bin[first] == category)
              {
               if(distance < top)
                  top = distance ;
              }
            else
              {
               if(distance < bottom)
                  bottom = distance ;
              }
           }

         distance = top - bottom ;
         if(distance > 30.0)
            loss += distance ;
         else
            loss += log(1.0 + exp(distance));
        }

      return loss ;
     }

Nach Abschluss aller Bootstraps werden die gemittelten optimalen Gewichte in das vom Nutzer bereitgestellte Array „weights[]“ geschrieben. Bevor die Gewichte in absteigender Reihenfolge sortiert werden, werden sie so transformiert, dass sie sich zu 100 addieren, was die Interpretierbarkeit verbessert.


Ein Beispiel für die Merkmalsauswahl mit FREL

Um den FREL-Algorithmus zu demonstrieren, stellen wir das Skript „FrelExample.mq5“ zur Verfügung. Dieses Skript nutzt FREL, um einen zufällig generierten Datensatz mit Kandidatenvariablen und einem Ziel zu analysieren und die besten Prädiktoren zu ermitteln. Die Nutzer können alle Parameter des FREL-Algorithmus und bestimmte Merkmale des synthetischen Datensatzes anpassen. Dazu gehören die Gesamtzahl der Beobachtungen ( num_observations ) und die Anzahl der Kandidatenprädiktoren ( num_candidate_predictors ). Nachstehend finden Sie einen Ausschnitt, der die vom Nutzer einstellbaren Eingaben des Skripts veranschaulicht:

//---user adjustable input parameters
input int number_of_partitions = 8; //Number of partitions
input double regularization_factor = 0.0; //Regularization factor
input int number_of_bootstraps = 1;
input int bootstrap_size = 0;
input ulong num_observations = 2000;// Sample size of random dataset
input ulong num_candidate_predictors = 10;// Maximum number of candidate predictors in dataset

Das Skript erzeugt eine Zufallszahlenmatrix mit num_observations Zeilen und num_candidate_predictors + 1 Spalten. Die letzte Spalte wird mit der Summe der Spalten bei den Indizes 1, 3, 5 und 7 überschrieben, die als Zielvariable des Datensatzes dient.

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   srand(126);
//---check user input parameters
   if(number_of_partitions<2 || num_observations<10 || num_candidate_predictors<8)
     {
      Print("Invalid input parameters");
      return;
     }
//---the data
   matrix dataset;
//---initialize size of random dataset
   dataset.Init(num_observations,num_candidate_predictors+1);
//---fill dataset with random data
   dataset.Random(1.0,10.0);
//---set the target variable in the last column
   if(!dataset.Col(dataset.Col(1) + dataset.Col(3) + dataset.Col(5) + dataset.Col(7),num_candidate_predictors))
     {
      Print("error ", GetLastError());
      return;
     }
//---initialize Frel object
   FREL frel(dataset,number_of_bootstraps,bootstrap_size);
//---declare containers to recieve output from Frel operation
   double optimal_weights[];
   int index[];
//---
   ulong timeIT = GetTickCount64();
//---find the most relevant predictors
   if(!frel.WeighVars(number_of_partitions,regularization_factor,index,optimal_weights))
      return;
//---calculate runtime
   Print("Runtime of FREL ", GetTickCount64() - timeIT, " ms");
//---display results
   for(uint i = 0; i<optimal_weights.Size(); i++)
      Print("Predictor at Column index ", index[i], " weight ", optimal_weights[i]);

  }
//+------------------------------------------------------------------+

Ziel ist es, zu beobachten, ob der FREL die Variablen angemessen gewichten kann, indem er die Spalten 1, 3, 5 und 7 als diejenigen bezeichnet, die die stärkste Beziehung zum Ziel haben. Zunächst führen wir das Skript mit den Standardparametern aus, wobei wir beachten, dass die Regularisierung deaktiviert ist und nur ein Bootstrap angegeben ist.

Standardeinstellungen für das Frel-Skript

Ausgabe.

ON      0       18:12:30.906    FrelExample (BTCUSD,D1) Runtime of FREL 273375 ms
GD      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 24.46987538756267
IH      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 24.22319404776024
EL      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 22.26820806768701
LP      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 22.13748732798876
DD      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 1.162036446785271
KK      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 1.1532145209345603
RO      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 1.1496286906955606
RS      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 1.1472521997561425
NG      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 1.14561384476096
DK      0       18:12:30.906    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 1.14348946606884

Als Nächstes untersuchen wir die Auswirkungen der Regularisierung auf die geschätzten Gewichte, indem wir mit Regularisierungsgraden von 0,1 und 1,0 testen.

Frel mit Regularisierungsfaktor 0.1 Einstellungen

Ausgabe.

MQ      0       18:19:03.951    FrelExample (BTCUSD,D1) Runtime of FREL 331296 ms
QD      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 19.63442784832085
PK      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 19.009699240770477
GO      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 18.823288529399388
GQ      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 18.18026689510982
NE      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 4.106428447842871
KI      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 4.075425288243113
OM      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 4.070169243578418
MQ      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 4.051103060690134
FE      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 4.025271426001863
FJ      0       18:19:03.951    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 4.0239200200430805

Frel mit Regularisierungsfaktor 1.0 Einstellungen

Ausgabe.

HP      0       18:25:43.421    FrelExample (BTCUSD,D1) Runtime of FREL 362984 ms
FF      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 10.353013480731704
JJ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 10.227015183302557
IM      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 10.213781888319609
KQ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 10.079770794877978
PF      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 9.948300319843046
QJ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 9.938367489770178
KN      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 9.897336276433514
DQ      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 9.79559491756489
EF      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 9.774541742551756
CI      0       18:25:43.421    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 9.77227790660475

Die Ergebnisse der Regularisierungstests zeigen, dass sich die Gewichte auf andere Variablen verteilen und von den richtigen Variablen abweichen. Es ist wahrscheinlich, dass die Festlegung eines höheren Grades der Regularisierung zu weniger eindeutigen Gewichten führt, was es schwierig macht, nützliche von irrelevanten Variablen zu unterscheiden.

Wenn man sich die Laufzeitergebnisse unserer Tests ansieht, wird deutlich, dass FREL relativ langsam arbeitet. Der Engpass ist wahrscheinlich auf die Funktion „total_loss()“ zurückzuführen, die bei der Ausführung des Optimierers den gesamten Datensatz mehrfach durchlaufen muss. Um die Laufzeiteffizienz zu verbessern, führen wir zahlreiche Bootstraps mit einer kleineren Stichprobengröße durch. Die folgenden Ergebnisse stammen aus einem Lauf mit 100 Bootstraps von 40 Stichproben.

BootStrapped Frel Einstellungen

Ausgabe.

IN      0       18:30:55.441    FrelExample (BTCUSD,D1) Runtime of FREL 22985 ms
OK      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 3 weight 18.706272752181135
OL      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 1 weight 18.32079620338284
RS      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 5 weight 18.194009676469012
HG      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 7 weight 16.298306686632337
MI      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 4 weight 5.838867272535404
LM      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 9 weight 5.249285089162589
FQ      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 8 weight 4.791606631149278
DE      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 6 weight 4.770223641360407
KI      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 0 weight 3.974977300216029
KM      0       18:30:55.441    FrelExample (BTCUSD,D1) Predictor at Column index 2 weight 3.855654746910961


Schlussfolgerung

In diesem Artikel haben wir eine MQL5-Implementierung der Merkmalsgewichtung unter Verwendung der regulierten, energiebasierten Modellierung vorgestellt. Wir haben einen kurzen Überblick über die theoretischen Grundlagen des Algorithmus gegeben und seine Wirksamkeit anhand eines synthetischen Datensatzes demonstriert. Die Ergebnisse waren zwar vielversprechend, aber wir stellten fest, dass der Algorithmus einen erheblichen Rechenaufwand hat, was zu einer langsamen Analyse führte. Um dieses Problem zu lösen, schlugen wir die Verwendung mehrerer Bootstraps mit kleineren Stichprobengrößen vor, was die Ausführungsgeschwindigkeit des Algorithmus insgesamt deutlich verbesserte. Dennoch könnte unsere Implementierung von Multithreading oder GPU-Beschleunigung stark profitieren. Nichtsdestotrotz wird jeder, der sich für die Methode interessiert, dazu ermutigt, den Code seinen Bedürfnissen entsprechend anzupassen. Der Artikel enthält den gesamten besprochenen Code, wobei die einzelnen Quelldateien in der nachstehenden Tabelle aufgeführt sind.

Quelldatei
Beschreibung
Mql5\include\np.mqh
Eine Header-Datei mit verschiedenen Werkzeugen zur Vektor- und Matrixmanipulation
Mql5\include\Powells.mqh
Enthält die Definition der Klasse PowellsMethod, die die Powells-Methode der Funktionsminimierung implementiert
Mql5\include\frel.mqh
Enthält die Definition der FREL-Klasse, die die Merkmalsgewichtung als regularisierten energiebasierten Lernalgorithmus darstellt
Mql5\script\FrelExample.mq5
Ein Skript, das die Verwendung der FREL-Klasse demonstriert


Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/14865

Beigefügte Dateien |
frel.mqh (14.08 KB)
Powells.mqh (17.57 KB)
np.mqh (37.73 KB)
FrelExample.mq5 (2.52 KB)
Mql5.zip (12.76 KB)
Trianguläre Arbitrage mit Vorhersagen Trianguläre Arbitrage mit Vorhersagen
Dieser Artikel vereinfacht die Dreiecksarbitrage und zeigt Ihnen, wie Sie mit Hilfe von Prognosen und spezieller Software intelligenter mit Währungen handeln können, selbst wenn Sie neu auf dem Markt sind. Sind Sie bereit, mit Expertise zu handeln?
Klassische Strategien neu interpretieren: Rohöl Klassische Strategien neu interpretieren: Rohöl
In diesem Artikel greifen wir eine klassische Rohölhandelsstrategie wieder auf, um sie durch den Einsatz von Algorithmen des überwachten maschinellen Lernens zu verbessern. Wir werden ein Modell der kleinsten Quadrate konstruieren, um zukünftige Brent-Rohölpreise auf der Grundlage der Differenz zwischen Brent- und WTI-Rohölpreisen vorherzusagen. Unser Ziel ist es, einen Frühindikator für künftige Veränderungen der Brent-Preise zu ermitteln.
MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 19): Bayes'sche Inferenz MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 19): Bayes'sche Inferenz
Die Bayes'sche Inferenz ist die Anwendung des Bayes-Theorems, um die Wahrscheinlichkeitshypothese zu aktualisieren, wenn neue Informationen zur Verfügung stehen. Dies führt intuitiv zu einer Anpassung in der Zeitreihenanalyse, und so schauen wir uns an, wie wir dies bei der Erstellung von nutzerdefinierten Klassen nicht nur für das Signal, sondern auch für das Money-Management und Trailing-Stops nutzen können.
Aufbau eines Modells aus Kerzen, Trend und Nebenbedingungen (Teil 3): Erkennung von Trendänderungen bei der Verwendung dieses Systems Aufbau eines Modells aus Kerzen, Trend und Nebenbedingungen (Teil 3): Erkennung von Trendänderungen bei der Verwendung dieses Systems
In diesem Artikel wird untersucht, wie Wirtschaftsnachrichten, das Anlegerverhalten und verschiedene Faktoren die Trendumkehr an den Märkten beeinflussen können. Es enthält eine Videoerklärung und fährt fort mit der Integration von MQL5-Code in unser Programm, um Trendumkehrungen zu erkennen, uns zu warnen und geeignete Maßnahmen auf der Grundlage der Marktbedingungen zu ergreifen. Dieser Artikel knüpft an frühere Artikel der Reihe an.