![Ein Algorithmus zur Auswahl von Merkmalen, der energiebasiertes Lernen in reinem MQL5 verwendet](https://c.mql5.com/2/78/A_feature_selection_algorithm_using_energy_based_learning_in_pure_MQL5_600x314.jpg)
Ein Algorithmus zur Auswahl von Merkmalen, der energiebasiertes Lernen in reinem MQL5 verwendet
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
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.
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.
Die Zielfunktion, die als Verlustfunktion bezeichnet wird, besteht aus einer gemittelten Verlustfunktion pro Stichprobe. Nachfolgend als Log-Verlust angegeben.
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
- 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.
- Anfangs wiesen wir allen Gewichten den Wert 1 zu.
- 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.
- Schließlich minimieren wir die objektive Verlustfunktion, optional mit der Regulierung, unter Verwendung eines geeigneten Optimierungsverfahrens. Dies ist der Kern des FREL-Algorithmus.
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.
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.
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
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.
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
![Trianguläre Arbitrage mit Vorhersagen](https://c.mql5.com/2/78/Triangular_arbitrage_with_predictions___LOGO___1.png)
![Klassische Strategien neu interpretieren: Rohöl](https://c.mql5.com/2/79/Reimagining_Classic_Strategies____Crude_Oil____LOGO___5.png)
![MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 19): Bayes'sche Inferenz](https://c.mql5.com/2/78/MQL5_Wizard_Techniques_you_should_know_7Part_19q____LOGO.png)
![Aufbau eines Modells aus Kerzen, Trend und Nebenbedingungen (Teil 3): Erkennung von Trendänderungen bei der Verwendung dieses Systems](https://c.mql5.com/2/78/Building_A_Candlestick_Trend_Constraint_Model_Part_3___LOGO.png)
![MQL5 - Sprache von Handelsstrategien, eingebaut ins Kundenterminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.