English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
preview
Aprendizaje automático y data science (Parte 05): Árboles de decisión usando como ejemplo las condiciones meteorológicas para jugar al tenis

Aprendizaje automático y data science (Parte 05): Árboles de decisión usando como ejemplo las condiciones meteorológicas para jugar al tenis

MetaTrader 5Trading | 30 agosto 2022, 16:59
687 0
Omega J Msigwa
Omega J Msigwa

¿Qué es un árbol de decisión?

Un árbol de decisión es una técnica de aprendizaje automático supervisado que se usa para la categorización o ejecución de predicciones basadas en las respuestas a un conjunto previo de preguntas. El modelo es una forma de aprendizaje supervisado, es decir, el modelo es entrenado y probado con un conjunto de datos que contiene la categorización deseada.

Un árbol de decisión no siempre ofrece respuestas o soluciones claras. En cambio, puede proporcionar distintas variantes para que el científico de datos tome su propia decisión fundamentada en función de ellas. Los árboles de decisión imitan el pensamiento humano, por lo tanto, para los científicos de datos suele ser fácil comprender e interpretar los resultados.

Imagen para el artículo sobre árboles de decisión

¡Terminología!

En el primer artículo de esta serie, olvidé describir la terminología del aprendizaje supervisado y no supervisado. Ahora corregiré este error.


Aprendizaje supervisado

El aprendizaje supervisado es un enfoque en la creación de inteligencia artificial (IA) en el que un algoritmo informático se entrena con datos de entrada y datos de salida etiquetados. El modelo se entrena hasta que pueda descubrir los patrones y relaciones subyacentes entre las entradas y las salidas etiquetadas. Esto le permite obtener resultados más precisos al encontrarse con datos nunca antes vistos.

A diferencia del aprendizaje supervisado, en el aprendizaje no supervisado, el algoritmo se presenta con datos sin etiquetar y está diseñado para descubrir patrones o similitudes por sí mismo.

Los algoritmos comúnmente usados en los programas de aprendizaje supervisado incluyen los siguientes:

La principal diferencia entre el aprendizaje supervisado y el no supervisado es cómo aprende el algoritmo. El aprendizaje no supervisado ofrece al algoritmo datos no etiquetados como conjunto de entrenamiento. A diferencia del aprendizaje supervisado, no hay valores de salida correctos. El algoritmo identifica patrones y similitudes en los datos, en lugar de vincularlos con algunas medidas externas. En otras palabras, los algoritmos pueden trabajar libremente para aprender más sobre los datos y encontrar cosas interesantes o inesperadas que no buscábamos. 

Ahora estamos trabajando con el aprendizaje supervisado; en próximos artículos, aprenderemos sobre el aprendizaje no supervisado.


¿Cómo funcionan los árboles de decisión?

Los árboles de decisión usan un conjunto de algoritmos para tomar decisiones sobre la división de un nodo en dos o más nodos de un subconjunto. La creación de subnodos aumenta la homogeneidad de los subnodos resultantes. En otras palabras, podemos decir que la pureza del nodo aumenta respecto a la variable objetivo. El algoritmo del árbol de decisiones divide los nodos entre todas las variables disponibles y luego selecciona la división que genera como resultado los subnodos más homogéneos.

Ejemplo de árbol de decisión

La selección del algoritmo se basa en el tipo de variables objetivo.

A continuación, mostramos los algoritmos utilizados en el árbol de decisión:

  1. ID3 — extensión de D3
  2. C4.5 — sucesor de ID3
  3. CART — árbol de clasificación y regresión
  4. CHAID — la detección automática de interacción de chi-cuadrado (CHAID), realiza divisiones de varios niveles al calcular árboles de clasificación
  5. MARS — splines de regresión adaptativa multivariante

En este artículo, crearemos un árbol de decisión basado en el algoritmo ID3; los otros algoritmos los analizaremos y aplicaremos en futuros artículos de esta serie.


Objetivo del árbol de decisión

El objetivo principal del algoritmo del árbol de decisión es separar los datos en datos "mixtos" y "puros" o datos próximos a los nodos. Por ejemplo, tenemos una cesta de manzanas mezcladas con naranjas. Cuando el árbol de decisiones aprenda cómo se ven las manzanas en cuanto a su color y tamaño, dividirá las frutas: las manzanas en una cesta y las naranjas en otra.


Algoritmo ID3

El algoritmo ID3 (Iterative Dichotomiser 3) es un algoritmo que iterativamente (repetidamente) dicotomiza (divide) objetos en dos o más grupos en cada paso.

Fue desarrollado por John R. Quinlan. El algoritmo ID3 usa un enfoque «codicioso» de arriba hacia abajo para construir un árbol de decisión. El enfoque de arriba hacia abajo significa que el árbol comienza a construir el árbol desde la parte superior, mientras que "codicioso" significa que en cada iteración elegimos la mejor función en este momento para crear un nodo.

Por lo general, ID3 solo se usa para tareas de clasificación con datos nominales (principalmente datos que no se pueden medir).

Existen dos tipos de árboles de decisión.

  1. Árboles de clasificación
  2. Árboles de regresión

1. Árboles de clasificación

Los árboles de clasificación son similares al árbol que analizaremos en este artículo: tenemos características sin valores numéricos u ordenados continuos que queremos clasificar.

Los árboles de clasificación clasifican los elementos en categorías.

2. Árboles de regresión

Se construyen con valores ordenados y con valores continuos.

El árbol de decisión predice valores numéricos.


Pasos del algoritmo ID3

1. Empieza con el conjunto de datos original como nodo raíz.

Al crear la biblioteca básica, usaremos un conjunto simple de datos sobre el juego del tenis bajo ciertas condiciones climáticas. Aquí tenemos una descripción general de nuestro pequeño conjunto de datos (14 filas en total).

Juego de tenis y conjunto de datos meteorológicos del árbol de decisión

Para dibujar un árbol de decisión con este algoritmo, deberemos comprender qué atributos ofrecen el mayor beneficio informativo de todos los atributos. Me explico.

Uno de estos atributos (columnas) deberá ser el nodo raíz para empezar. Pero, ¿cómo decidimos qué columna será el nodo raíz? Aquí usaremos la ganancia de información.

Ganancia de información

La ganancia de información calcula la reducción de la entropía y mide cómo de bien una característica determinada separa/clasifica las clases objetivo. La función con la mayor ganancia de información se elegirá como la mejor.

Fórmula para obtener información con árboles de decisión

Entropía

La entropía es la medida de la incertidumbre de una variable aleatoria que caracteriza una impureza en una muestra dada.

Fórmula de la entropía:

Fórmula de la entropía del árbol de decisión

Lo primero que debemos hacer es encontrar la entropía de todo el conjunto de datos, es decir, encontrar la entropía de las variables objetivo, ya que todas estas columnas se proyectan en la columna objetivo de PlayTennis.

Columna objetivo de la variable para jugar al tenis

Vamos a escribir algo de código. 

Sabemos con certeza que antes de buscar la entropía de las variables objetivo, deberemos marcar el número total de valores negativos etiquetados como No y los valores positivos etiquetados como Yes. Estos valores nos ayudarán a encontrar las probabilidades de los elementos dentro de nuestra columna. Para obtener dichos valores, escribiremos el código sobre qué sucederá dentro de la función de entropía.

double CDecisionTree::Entropy(int &SampleNumbers[],int total)
 {
    double Entropy = 0;
    double entropy_out =0; //the value of entropy that will be returned
     
     for (int i=0; i<ArraySize(SampleNumbers); i++)
        {                   
              double probability1 = Proba(SampleNumbers[i],total); 
              Entropy += probability1 * log2(probability1);
        }
     
    entropy_out = -Entropy;
    
    return(entropy_out);
 }

La función se comprende de un solo vistazo, especialmente si hemos estudiado la fórmula, pero será mejor echar un vistazo al array SampleNumbers[]. Las muestras son lo que se encuentra dentro de la columna. Los patrones pueden funcionar como clases. Por ejemplo, en esta columna objetivo, nuestros ejemplos serán Yes y No.

Si ejecutamos con éxito la función en la columna TargetArray, veremos el siguiente resultado:

12:37:48.394    TestScript      There are 5 No
12:37:48.394    TestScript      There are 9 Yes
12:37:48.394    TestScript      There are 2 classes
12:37:48.394    TestScript      "No"  "Yes"
12:37:48.394    TestScript      5     9
12:37:48.394    TestScript      Total contents = 14

Tenemos estos valores, así que podemos seguir buscando la entropía usando la siguiente fórmula.

Fórmula de la entropía para los árboles de decisión

Si observamos detenidamente la fórmula, notaremos que el logaritmo con el que estamos tratando es un logaritmo de base 2, es decir, un logaritmo binario (ver enlace para más información). Para encontrar el logaritmo de base 2, dividiremos log2 por el logaritmo del valor del argumento.

double CDecisionTree::log2(double value)
 {
   return (log10(value)/log10(2));
 }

Como la base es la misma, todo está bien.

También escribí el código para la función Proba(), que nos permitirá obtener la probabilidad de la clase de valores. Aquí la tenemos:

double CDecisionTree::Proba(int number,double total)
 {
    return(number/total);
 }

Un elefante en la habitación. Para encontrar la probabilidad de un elemento en una columna, determinaremos cuántas veces ha aparecido y lo dividiremos por el número total de todos los elementos en esa columna. Probablemente haya notado que hay 5 elementos con un valor No y 9 elementos con un valor Yes, por lo que resultará así:

probabilidad No = 5/14 (número total de elementos) = 0.357142..

probabilidad Yes = 9/14 = 0.6428571...

Finalmente, para encontrar la entropía de una columna de atributo/conjunto de datos

     for (int i=0; i<ArraySize(SampleNumbers); i++)
        {                   
              double probability1 = Proba(SampleNumbers[i],total); 
              Entropy += probability1 * log2(probability1);
        }
      entropy_out = -Entropy;
    

Si ejecutamos esta función para la variable Target, obtendremos lo siguiente: 

13:37:54.273    TestScript      Proba1 0.35714285714285715
13:37:54.273    TestScript      Proba1 0.6428571428571429
13:37:54.273    TestScript      Entropy of the entire dataset = 0.9402859586706309

¡Ta-dam!

Ahora conocemos la entropía de todo el conjunto de datos, que es básicamente la entropía de los valores y, además, tenemos una función para encontrar la entropía. Vamos a encontrar la entropía de cada columna en el conjunto de datos.

Así que ahora tenemos la entropía de todo el conjunto de datos. El siguiente paso será encontrar la entropía de los miembros dentro de cada columna de la variable independiente. El objetivo tras la localización de este tipo de entropía en variables independientes es encontrar la ganancia de información para cada columna de datos.

Antes de usar nuestra biblioteca para determinar la entropía de la columna Outlook, la calcularemos manualmente para tener una idea más clara de lo que estamos haciendo.

A saber, estamos comparando la columna de Outlook con su variable objetivo.

Columnas de Outlook frente a PlayTennis

outlook vs playtennis

A diferencia de la forma en que buscamos la entropía de todo el conjunto de datos, también llamada entropía de la variable objetivo, para encontrar la entropía de la variable independiente, deberemos referirnos a la variable Target, ya que esta es nuestra meta.

Valores en la columna de pronóstico de Outlook 

Tenemos tres valores distintos: Sunny (soleado), Overcast (nublado) y Rain (lluvia). Necesitaremos encontrar la entropía de cada uno de estos valores con respecto a su variable objetivo.

Muestra Sunny (muestras Sunny positivas y negativas) = [2 positivas (Yes), 3 negativas (No)]

Árbol de decisión Sunny 

Hemos encontrado el número de resultados positivos y negativos. Resulta que la probabilidad de una decisión positiva Yes para jugar al tenis en un día soleado sería:

probabilidad1 = 2 (número de veces que ha aparecido Yes) / 5 (número total de días soleados)

es decir, 2/5 = 0.4

Y viceversa

La probabilidad de que no haya tenis en un día soleado será igual a 0,6, es decir, 3/5 = 0,6

Y finalmente, la entropía del juego en un día soleado será así (miremos la fórmula)

Entropy(Sunny) = - (P1*log2P1 + P2*log2P2)
Entropy(Sunny) = -(0.4*log2 0.4 + 0.6*log2 0.6)

Entropy(Sunny) =  0.97095

Ahora encontraremos la entropía del clima nublado Overcast 

Árbol de decisión de entropía nublada

Muestras en tiempo nublado.

Muestras positivas 4( con el valor Yes en la columna target). Muestras negativas 0 (con el valor No en la columna Target). Esta situación supone una excepción.

Excepciones en el algoritmo ID3

Cuando se dan cero (0) muestras negativas, al tiempo que hay muestras positivas, o viceversa, cero (0) muestras positivas al tiempo que hay negativas, la entropía estará ligada a cero (0).

Entonces podemos considerar que este es un nodo puro, no necesita dividirse más, ya que tiene muestras homogéneas. Para entender mejor esto, dibujaremos un árbol.

Otra excepción:

Cuando encontramos un número igual de muestras positivas y negativas, matemáticamente la entropía será igual a la unidad (1).

La única excepción con la que deberemos lidiar de manera efectiva es cuando hay un valor cero en las muestras, porque el cero puede provocar un error de división por cero. Aquí tenemos una nueva función con la capacidad de procesar dichas excepciones.

double CDecisionTree::Entropy(int &SampleNumbers[],int total)
 {
    double Entropy = 0;
    double entropy_out =0; //the value of entropy that will be returned
     
     for (int i=0; i<ArraySize(SampleNumbers); i++)
        {       
            if (SampleNumbers[i] == 0) { Entropy = 0; break; } //Exception
            
              double probability1 = Proba(SampleNumbers[i],total); 
              Entropy += probability1 * log2(probability1);
        }
     
     if (Entropy==0)     entropy_out = 0;  //handle the exception
     else                entropy_out = -Entropy;
    
    return(entropy_out);
 }

Finalmente, vamos a encontrar la entropía de la lluvia.

Árbol de decisión de la entropía de la lluvia

Muestras de lluvia

Hay 3 muestras positivas (con el valor Yes en la columna Target).

Hay 2 muestras negativas (con el valor No en la columna Target).

Esta es la entropía del juego del tenis en un día lluvioso.

Entropy(Rain) = - (P1*log2P1 + P2*log2P2)
Entropy(Rain) = -(0.6*log2 0.6 + 0.4*log2 0.4)

Entropy(Rain) =  0.97095

Estos son los valores de la entropía que hemos obtenido de la columna Outlook.

Entropía de la columna Outlook
Entropy(Sunny) =  0.97095
Entropy(Overcast) = 0
Entropy(Rain) =  0.97095  

Bien, ahora calculamos la entropía de las muestras manualmente. Si ejecutamos nuestro programa para encontrar estas entropías, el resultado será el que sigue:

PD      0       13:47:20.571    TestScript      <<<<<<<<    Parent Entropy  0.94029  A = 0  >>>>>>>> 
FL      0       13:47:20.571    TestScript         <<<<<   C O L U M N  Outlook   >>>>>  
CL      0       13:47:20.571    TestScript           <<   Sunny   >> total > 5
MH      0       13:47:20.571    TestScript      "No"  "Yes"
DM      0       13:47:20.571    TestScript      3 2
CQ      0       13:47:20.571    TestScript      Entropy of Sunny = 0.97095
LD      0       13:47:20.571    TestScript           <<   Overcast   >> total > 4
OI      0       13:47:20.571    TestScript      "No"  "Yes"
MJ      0       13:47:20.571    TestScript      0 4
CM      0       13:47:20.571    TestScript      Entropy of Overcast = 0.00000
JD      0       13:47:20.571    TestScript           <<   Rain   >> total > 5
GN      0       13:47:20.571    TestScript      "No"  "Yes"
JH      0       13:47:20.571    TestScript      2 3
HR      0       13:47:20.571    TestScript      Entropy of Rain = 0.97095

Usaremos estos valores para encontrar la ganancia de información usando la fórmula que hemos analizado anteriormente.

Árboles de decisión y ganancia de información

Ahora, le propongo echar un vistazo a cómo encontraremos la entropía manualmente, para que quede más claro lo que sucede al otro lado de la puerta.

Ganancia de información (Information Gain IG) = Entropía de todo el conjunto de datos - La suma de los productos de la probabilidad de la muestra y su entropía.

IG = E(dataset) - ( Prob(sunny) * E(sunny) + Prob(Overcast)*E(Overcast) + Prob(Rain)*E(Rain) )

IG = 0.9402 - ( 5/14 * (0.97095) + 4/14 * (0) + 5/14(0.97095) )

IG = 0.2467 (es la ganancia de información de la columna de pronóstico Outlook)

Cuando convertimos la fórmula en código, obtenemos lo que sigue:

double CDecisionTree::InformationGain(double parent_entropy, double &EntropyArr[], int &ClassNumbers[], int rows_)
 {
    double IG = 0;
    
    for (int i=0; i<ArraySize(EntropyArr); i++)
      {  
        double prob = ClassNumbers[i]/double(rows_); 
        IG += prob * EntropyArr[i];
      }
     
     return(parent_entropy - IG);
 }

Llamada de la función

    if (m_debug)  printf("<<<<<<  Column Information Gain %.5f >>>>>> \n",IGArr[i]);

Resultado

PF      0       13:47:20.571    TestScript      <<<<<<  Column Information Gain 0.24675 >>>>>> 

Ahora necesitaremos repetir el proceso para todas las columnas y encontrar su ganancia de información. El resultado será el siguiente:

RH      0       13:47:20.571    TestScript (EURUSD,H1)  Default Parent Entropy 0.9402859586706309
PD      0       13:47:20.571    TestScript (EURUSD,H1)  <<<<<<<<    Parent Entropy  0.94029  A = 0  >>>>>>>> 
FL      0       13:47:20.571    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Outlook   >>>>>  
CL      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Sunny   >> total > 5
MH      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
DM      0       13:47:20.571    TestScript (EURUSD,H1)  3 2
CQ      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Sunny = 0.97095
LD      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Overcast   >> total > 4
OI      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
MJ      0       13:47:20.571    TestScript (EURUSD,H1)  0 4
CM      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Overcast = 0.00000
JD      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Rain   >> total > 5
GN      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
JH      0       13:47:20.571    TestScript (EURUSD,H1)  2 3
HR      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Rain = 0.97095
PF      0       13:47:20.571    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.24675 >>>>>> 
QP      0       13:47:20.571    TestScript (EURUSD,H1)  
KH      0       13:47:20.571    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Temp   >>>>>  
PR      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Hot   >> total > 4
QF      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
OS      0       13:47:20.571    TestScript (EURUSD,H1)  2 2
NK      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Hot = 1.00000
GO      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Mild   >> total > 6
OD      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
KQ      0       13:47:20.571    TestScript (EURUSD,H1)  2 4
GJ      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Mild = 0.91830
HQ      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Cool   >> total > 4
OJ      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
OO      0       13:47:20.571    TestScript (EURUSD,H1)  1 3
IH      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Cool = 0.81128
OR      0       13:47:20.571    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.02922 >>>>>> 
ID      0       13:47:20.571    TestScript (EURUSD,H1)  
HL      0       13:47:20.571    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Humidity   >>>>>  
FH      0       13:47:20.571    TestScript (EURUSD,H1)       <<   High   >> total > 7
KM      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
HF      0       13:47:20.571    TestScript (EURUSD,H1)  4 3
GQ      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of High = 0.98523
QK      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Normal   >> total > 7
GR      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
DD      0       13:47:20.571    TestScript (EURUSD,H1)  1 6
OF      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Normal = 0.59167
EJ      0       13:47:20.571    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.15184 >>>>>> 
EL      0       13:47:20.571    TestScript (EURUSD,H1)  
GE      0       13:47:20.571    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Wind   >>>>>  
IQ      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Weak   >> total > 8
GE      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
EO      0       13:47:20.571    TestScript (EURUSD,H1)  2 6
LI      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Weak = 0.81128
FS      0       13:47:20.571    TestScript (EURUSD,H1)       <<   Strong   >> total > 6
CK      0       13:47:20.571    TestScript (EURUSD,H1)  "No"  "Yes"
ML      0       13:47:20.571    TestScript (EURUSD,H1)  3 3
HO      0       13:47:20.571    TestScript (EURUSD,H1)  Entropy of Strong = 1.00000
LE      0       13:47:20.571    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.04813 >>>>>> 
IE      0       13:47:20.571    TestScript (EURUSD,H1)  


Una vez hayamos obtenido la ganancia de información para todas las columnas, procederemos a construir el árbol de decisión. Pero ¿cómo?

El propósito de este proceso inicial era encontrar la ganancia de información para todas las columnas, para que uno pudiera decidir qué columna sería el nodo raíz. La columna cuya ganancia de información sea mayor que la del resto, se convertirá en el nodo raíz. En este caso, la columna de pronóstico Outlook tiene la mayor ganancia de información, por lo que se convertirá en el nodo raíz de nuestro árbol de decisión. Vamos a construir el árbol ahora.

Primera división del árbol de decisión

La biblioteca ofrece esta información de predicción al ejecutarse el script de prueba. El script, adjunto al final del artículo, muestra mucha información en el modo de depuración de la biblioteca usado por defecto.

Ya hemos obtenido la ganancia de información; ahora la almacenaremos en un array de valores double que guardará todos los datos sobre la ganancia. En última instancia, el valor máximo dentro del array será el valor objetivo.

         //--- Finding the Information Gain
                        
                        ArrayResize(IGArr,i+1); //information gains matches the columns number
                        
                        IGArr[i] = InformationGain(P_EntropyArr[A],EntropyArr,ClassNumbers,rows);
                        
                        max_gain = ArrayMaximum(IGArr); 

El resultado de la llamada será el siguiente. 
QR      0       13:47:20.571    TestScript (EURUSD,H1)  Parent Noce will be Outlook with IG = 0.24675
IK      0       13:47:20.574    TestScript (EURUSD,H1)  Parent Entropy Array and Class Numbers
NL      0       13:47:20.574    TestScript (EURUSD,H1)  "Sunny"    "Overcast" "Rain"    
NH      0       13:47:20.574    TestScript (EURUSD,H1)  0.9710 0.0000 0.9710
FR      0       13:47:20.574    TestScript (EURUSD,H1)  5 4 5

Una pequeña explicación adicional sobre el árbol que hemos creado hasta ahora.

Explicaciones del árbol de decisión

Este el primer paso (muy importante, por otra parte), en el que encontramos el nodo raíz y lo dividimos en ramas y hojas. Vamos a seguir dividiendo los datos hasta que no quede nada que dividir. Aquí continuaremos el proceso de separación de la rama con el valor Sunny y la rama con el valor Rain.

La columna Overcastconsta de valores homogéneos (es pura), por lo que podemos decir que está completamente clasificada. En un árbol de decisión, dicho estado se denomina hoja. No generará ramas.

Pero antes de continuar con la división de datos, hay algunos pasos importantes que seguir en el conjunto de datos actual que tenemos.

CLASIFICACIÓN DE LA MATRIZ RESTANTE DEL CONJUNTO DE DATOS

Necesitamos clasificar la matriz restante del conjunto de datos para organizar las filas con los mismos valores en orden ascendente. Esto resultará útil para crear ramas y hojas con contenido uniforme (que es exactamente lo que buscamos).

void CDecisionTree::MatrixClassify(string &dataArr[],string &Classes[], int cols)
 {
   string ClassifiedArr[];
   ArrayResize(ClassifiedArr,ArraySize(dataArr));
   
   int fill_start = 0, fill_ends = 0;
   int index = 0;
   for (int i = 0; i<ArraySize(Classes); i++)
     {
      int start = 0;  int curr_col = 0;
      for (int j = 0; j<ArraySize(dataArr); j++)
        { 
          curr_col++;
          
            if (Classes[i] == dataArr[j])
              {
                //printf("Classes[%d] = %s dataArr[%d] = %s ",i,Classes[i],j,dataArr[j]);
                
                 if (curr_col == 1) 
                     fill_start =  j;
                 else
                   {
                      if (j>curr_col)
                        fill_start = j - (curr_col-1);
                      else fill_start = (curr_col-1) - j;
                          
                      fill_start  = fill_start;
                      //Print("j ",j," j-currcol ",j-(curr_col-1)," curr_col ",curr_col," columns ",cols," fill start ",fill_start );
                      
                   }
                 
                 fill_ends = fill_start + cols; 
                 
                 //printf("fillstart %d fillends %d j index = %d i = %d ",fill_start,fill_ends,j,i);
//---
                  //if (ArraySize(ClassifiedArr) >= ArraySize(dataArr)) break;
                  //Print("ArraySize Classified Arr ",ArraySize(ClassifiedArr)," dataArr size ",ArraySize(dataArr)," i ",i);
                  
                  
                  for (int k=fill_start; k<fill_ends; k++)
                    {
                      index++;
                      //printf(" k %d index %d",k,index);
                      //printf("dataArr[%d] = %s index = %d",k,dataArr[k],index-1);
                      ClassifiedArr[index-1] = dataArr[k];
                    }
                    
                if (index >= ArraySize(dataArr)) break; //might be infinite loop if this occurs
              }
              
          if (curr_col == cols) curr_col = 0;
        } 
         
      if (index >= ArraySize(dataArr)) break; //might be infinite loop if this occurs
     }
     
    ArrayCopy(dataArr,ClassifiedArr);
    ArrayFree(ClassifiedArr);
 }

¿Por qué hemos comentado tanto código? La biblioteca aún necesita algo de trabajo, y se necesitan comentarios para la depuración. Seguramente, podrá jugar con ellos.

Bien, ahora llamamos a la función, mostramos el resultado, y obtenemos lo siguiente:

JG      0       13:47:20.574    TestScript (EURUSD,H1)  Classified matrix dataset
KL      0       13:47:20.574    TestScript (EURUSD,H1)  "Outlook"     "Temp"        "Humidity"    "Wind"        "PlayTennis "
GS      0       13:47:20.574    TestScript (EURUSD,H1)  [ 
QF      0       13:47:20.574    TestScript (EURUSD,H1)  "Sunny" "Hot"   "High"  "Weak"  "No"   
DN      0       13:47:20.574    TestScript (EURUSD,H1)  "Sunny"  "Hot"    "High"   "Strong" "No"    
JF      0       13:47:20.574    TestScript (EURUSD,H1)  "Sunny" "Mild"  "High"  "Weak"  "No"   
ND      0       13:47:20.574    TestScript (EURUSD,H1)  "Sunny"  "Cool"   "Normal" "Weak"   "Yes"   
PN      0       13:47:20.574    TestScript (EURUSD,H1)  "Sunny"  "Mild"   "Normal" "Strong" "Yes"   
EH      0       13:47:20.574    TestScript (EURUSD,H1)  "Overcast" "Hot"      "High"     "Weak"     "Yes"     
MH      0       13:47:20.574    TestScript (EURUSD,H1)  "Overcast" "Cool"     "Normal"   "Strong"   "Yes"     
MN      0       13:47:20.574    TestScript (EURUSD,H1)  "Overcast" "Mild"     "High"     "Strong"   "Yes"     
DN      0       13:47:20.574    TestScript (EURUSD,H1)  "Overcast" "Hot"      "Normal"   "Weak"     "Yes"     
MG      0       13:47:20.574    TestScript (EURUSD,H1)  "Rain" "Mild" "High" "Weak" "Yes" 
QO      0       13:47:20.574    TestScript (EURUSD,H1)  "Rain"   "Cool"   "Normal" "Weak"   "Yes"   
LN      0       13:47:20.574    TestScript (EURUSD,H1)  "Rain"   "Cool"   "Normal" "Strong" "No"    
LE      0       13:47:20.574    TestScript (EURUSD,H1)  "Rain"   "Mild"   "Normal" "Weak"   "Yes"   
FE      0       13:47:20.574    TestScript (EURUSD,H1)  "Rain"   "Mild"   "High"   "Strong" "No"    
GS      0       13:47:20.574    TestScript (EURUSD,H1)  ] 
DH      0       13:47:20.574    TestScript (EURUSD,H1)  columns = 5 rows = 70

La función opera como por arte de magia.

Pasemos al siguiente paso importante. 

ELIMINACIÓN DE LOS NODOS HOJA DEL CONJUNTO DE DATOS

Antes de la próxima iteración de todo el proceso, será muy importante eliminar los nodos hoja (finales), ya que no crearán ninguna rama. Lógico, ¿verdad? Por cierto, son nodos de valores "puros".

Eliminamos todas las filas con valor de hoja Leaf Node. En nuestro caso, eliminaremos todas las líneas con el clima Overcast.

    //--- Search if there is zero entropy in the Array
         
            int zero_entropy_index = 0;
            bool zero_entropy = false;
            for (int e=0; e<ArraySize(P_EntropyArr); e++)
              if (P_EntropyArr[e] == 0) { zero_entropy = true; zero_entropy_index=e; break; }
            
            if (zero_entropy) //if there is zero in the Entropy Array 
              {
                MatrixRemoveRow(m_dataset,p_Classes[zero_entropy_index],cols);    
               
                rows_total = ArraySize(m_dataset); //New number of total rows from Array   
                 if (m_debug)
                  {
                    printf("%s is A LEAF NODE its Rows have been removed from the dataset remaining Dataset is ..",p_Classes[zero_entropy_index]);
                    ArrayPrint(DataColumnNames);
                    MatrixPrint(m_dataset,cols,rows_total);
                  }
                
                //we also remove the entropy from the Array and its information everywhere else from the parent Node That we are going to build next
                
                ArrayRemove(P_EntropyArr,zero_entropy_index,1);
                ArrayRemove(p_Classes,zero_entropy_index,1);
                ArrayRemove(p_ClassNumbers,zero_entropy_index,1);
              }
            
            if (m_debug)  
             Print("rows total ",rows_total," ",p_Classes[zero_entropy_index]," ",p_ClassNumbers[zero_entropy_index]);
            
            

Después de ejecutar este código, obtendremos el siguiente resultado:

NQ      0       13:47:20.574    TestScript (EURUSD,H1)  Overcast is A LEAF NODE its Rows have been removed from the dataset remaining Dataset is ..
GP      0       13:47:20.574    TestScript (EURUSD,H1)  "Outlook"     "Temp"        "Humidity"    "Wind"        "PlayTennis "
KG      0       13:47:20.574    TestScript (EURUSD,H1)  [ 
FS      0       13:47:20.575    TestScript (EURUSD,H1)  "Sunny" "Hot"   "High"  "Weak"  "No"   
GK      0       13:47:20.575    TestScript (EURUSD,H1)  "Sunny"  "Hot"    "High"   "Strong" "No"    
EI      0       13:47:20.575    TestScript (EURUSD,H1)  "Sunny" "Mild"  "High"  "Weak"  "No"   
IP      0       13:47:20.575    TestScript (EURUSD,H1)  "Sunny"  "Cool"   "Normal" "Weak"   "Yes"   
KK      0       13:47:20.575    TestScript (EURUSD,H1)  "Sunny"  "Mild"   "Normal" "Strong" "Yes"   
JK      0       13:47:20.575    TestScript (EURUSD,H1)  "Rain" "Mild" "High" "Weak" "Yes" 
FL      0       13:47:20.575    TestScript (EURUSD,H1)  "Rain"   "Cool"   "Normal" "Weak"   "Yes"   
GK      0       13:47:20.575    TestScript (EURUSD,H1)  "Rain"   "Cool"   "Normal" "Strong" "No"    
OI      0       13:47:20.575    TestScript (EURUSD,H1)  "Rain"   "Mild"   "Normal" "Weak"   "Yes"   
IQ      0       13:47:20.575    TestScript (EURUSD,H1)  "Rain"   "Mild"   "High"   "Strong" "No"    
LG      0       13:47:20.575    TestScript (EURUSD,H1)  ] 
IL      0       13:47:20.575    TestScript (EURUSD,H1)  columns = 5 rows = 50
HE      0       13:47:20.575    TestScript (EURUSD,H1)  rows total 50 Rain 5

¡Ta-dam!

Y el último proceso, pero no menos importante, en esta etapa:

ELIMINACIÓN DE UN NODO PRINCIPAL O RAÍZ DE UN CONJUNTO DE DATOS

Como ya lo hemos definido como nodo raíz y lo hemos dibujado en nuestro árbol, ya no lo necesitaremos para nuestro conjunto de datos. Solo los valores sin clasificar deberán permanecer en el conjunto de datos.

//---    REMOVING THE PARENT/ ROOT NODE FROM OUR DATASET

            MatrixRemoveColumn(m_dataset,max_gain,cols);
         
         // After removing the columns assign the new values to these global variables
         
            cols = cols-1;   // remove that one column that has been removed
            rows_total = rows_total - single_rowstotal; //remove the size of one column rows
            
         // we also remove the column from column names Array
            ArrayRemove(DataColumnNames,max_gain,1);

//---

            printf("Column %d removed from the Matrix, The remaining dataset is",max_gain+1);
            ArrayPrint(DataColumnNames);
            MatrixPrint(m_dataset,cols,rows_total);

El resultado de este bloque de código será: 

OM      0       13:47:20.575    TestScript (EURUSD,H1)  Column 1 removed from the Matrix, The remaining dataset is
ON      0       13:47:20.575    TestScript (EURUSD,H1)  "Temp"        "Humidity"    "Wind"        "PlayTennis "
HF      0       13:47:20.575    TestScript (EURUSD,H1)  [ 
CR      0       13:47:20.575    TestScript (EURUSD,H1)  "Hot"  "High" "Weak" "No"  
JE      0       13:47:20.575    TestScript (EURUSD,H1)  "Hot"    "High"   "Strong" "No"    
JR      0       13:47:20.575    TestScript (EURUSD,H1)  "Mild" "High" "Weak" "No"  
NG      0       13:47:20.575    TestScript (EURUSD,H1)  "Cool"   "Normal" "Weak"   "Yes"   
JI      0       13:47:20.575    TestScript (EURUSD,H1)  "Mild"   "Normal" "Strong" "Yes"   
PR      0       13:47:20.575    TestScript (EURUSD,H1)  "Mild" "High" "Weak" "Yes" 
JJ      0       13:47:20.575    TestScript (EURUSD,H1)  "Cool"   "Normal" "Weak"   "Yes"   
QQ      0       13:47:20.575    TestScript (EURUSD,H1)  "Cool"   "Normal" "Strong" "No"    
OG      0       13:47:20.575    TestScript (EURUSD,H1)  "Mild"   "Normal" "Weak"   "Yes"   
KD      0       13:47:20.575    TestScript (EURUSD,H1)  "Mild"   "High"   "Strong" "No"    
DR      0       13:47:20.575    TestScript (EURUSD,H1)  ] 

¡Ta-dam!

La razón por la que hemos podido dejar ciertas partes del conjunto de datos con tanta certeza, es porque la biblioteca dibuja un árbol que deja pistas sobre la dirección hacia la que se dirige el conjunto de datos. En estos momentos, tenemos un árbol así.

Archivo de texto del árbol de decisión

Se ve feo, pero resulta suficiente para la demostración. Intentaremos crearlo con HTML en la próxima serie de artículos; espero que me eche una mano con esto. El enlace a mi repositorio de GitHub está más abajo. Ahora debemos terminar lo comenzado, para ello, describiremos el proceso restante de ensamblaje del árbol. Esto es lo que se mostrará en el log a medida que repitamos el proceso una y otra vez hasta que no quede nada por dividir.

HI      0       13:47:20.575    TestScript (EURUSD,H1)  Final Parent Entropy Array and Class Numbers
RK      0       13:47:20.575    TestScript (EURUSD,H1)  "Sunny" "Rain" 
CL      0       13:47:20.575    TestScript (EURUSD,H1)  0.9710 0.9710
CE      0       13:47:20.575    TestScript (EURUSD,H1)  5 5
EH      0       13:47:20.575    TestScript (EURUSD,H1)  <<<<<<<<    Parent Entropy  0.97095  A = 1  >>>>>>>> 
OF      0       13:47:20.575    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Temp   >>>>>  
RP      0       13:47:20.575    TestScript (EURUSD,H1)       <<   Hot   >> total > 2
MD      0       13:47:20.575    TestScript (EURUSD,H1)  "No"  "Yes"
MQ      0       13:47:20.575    TestScript (EURUSD,H1)  2 0
QE      0       13:47:20.575    TestScript (EURUSD,H1)  Entropy of Hot = 0.00000
FQ      0       13:47:20.575    TestScript (EURUSD,H1)       <<   Mild   >> total > 5
KJ      0       13:47:20.575    TestScript (EURUSD,H1)  "No"  "Yes"
NO      0       13:47:20.575    TestScript (EURUSD,H1)  2 3
DH      0       13:47:20.575    TestScript (EURUSD,H1)  Entropy of Mild = 0.97095
IS      0       13:47:20.575    TestScript (EURUSD,H1)       <<   Cool   >> total > 3
KH      0       13:47:20.575    TestScript (EURUSD,H1)  "No"  "Yes"
LM      0       13:47:20.575    TestScript (EURUSD,H1)  1 2
FN      0       13:47:20.575    TestScript (EURUSD,H1)  Entropy of Cool = 0.91830
KD      0       13:47:20.575    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.20999 >>>>>> 
EF      0       13:47:20.575    TestScript (EURUSD,H1)  
DJ      0       13:47:20.575    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Humidity   >>>>>  
HJ      0       13:47:20.575    TestScript (EURUSD,H1)       <<   High   >> total > 5
OS      0       13:47:20.575    TestScript (EURUSD,H1)  "No"  "Yes"
FD      0       13:47:20.575    TestScript (EURUSD,H1)  4 1
NG      0       13:47:20.575    TestScript (EURUSD,H1)  Entropy of High = 0.72193
KM      0       13:47:20.575    TestScript (EURUSD,H1)       <<   Normal   >> total > 5
CP      0       13:47:20.575    TestScript (EURUSD,H1)  "No"  "Yes"
JR      0       13:47:20.575    TestScript (EURUSD,H1)  1 4
MD      0       13:47:20.575    TestScript (EURUSD,H1)  Entropy of Normal = 0.72193
EL      0       13:47:20.575    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.24902 >>>>>> 
IN      0       13:47:20.575    TestScript (EURUSD,H1)  
CS      0       13:47:20.575    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Wind   >>>>>  
OS      0       13:47:20.575    TestScript (EURUSD,H1)       <<   Weak   >> total > 6
CK      0       13:47:20.575    TestScript (EURUSD,H1)  "No"  "Yes"
GM      0       13:47:20.575    TestScript (EURUSD,H1)  2 4
OO      0       13:47:20.575    TestScript (EURUSD,H1)  Entropy of Weak = 0.91830
HE      0       13:47:20.575    TestScript (EURUSD,H1)       <<   Strong   >> total > 4
GI      0       13:47:20.575    TestScript (EURUSD,H1)  "No"  "Yes"
OJ      0       13:47:20.575    TestScript (EURUSD,H1)  3 1
EM      0       13:47:20.575    TestScript (EURUSD,H1)  Entropy of Strong = 0.81128
PG      0       13:47:20.575    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.09546 >>>>>> 
EG      0       13:47:20.575    TestScript (EURUSD,H1)  
HK      0       13:47:20.575    TestScript (EURUSD,H1)  Parent Noce will be Humidity with IG = 0.24902
OI      0       13:47:20.578    TestScript (EURUSD,H1)  Parent Entropy Array and Class Numbers
JO      0       13:47:20.578    TestScript (EURUSD,H1)  "High"   "Normal" "Cool"  
QJ      0       13:47:20.578    TestScript (EURUSD,H1)  0.7219 0.7219 0.9183
QO      0       13:47:20.578    TestScript (EURUSD,H1)  5 5 3
PJ      0       13:47:20.578    TestScript (EURUSD,H1)  Classified matrix dataset
NM      0       13:47:20.578    TestScript (EURUSD,H1)  "Temp"        "Humidity"    "Wind"        "PlayTennis "
EF      0       13:47:20.578    TestScript (EURUSD,H1)  [ 
FM      0       13:47:20.578    TestScript (EURUSD,H1)  "Hot"  "High" "Weak" "No"  
OD      0       13:47:20.578    TestScript (EURUSD,H1)  "Hot"    "High"   "Strong" "No"    
GR      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild" "High" "Weak" "No"  
QG      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild" "High" "Weak" "Yes" 
JD      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild"   "High"   "Strong" "No"    
KS      0       13:47:20.578    TestScript (EURUSD,H1)  "Cool"   "Normal" "Weak"   "Yes"   
OJ      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild"   "Normal" "Strong" "Yes"   
CL      0       13:47:20.578    TestScript (EURUSD,H1)  "Cool"   "Normal" "Weak"   "Yes"   
LJ      0       13:47:20.578    TestScript (EURUSD,H1)  "Cool"   "Normal" "Strong" "No"    
NH      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild"   "Normal" "Weak"   "Yes"   
ER      0       13:47:20.578    TestScript (EURUSD,H1)  ] 
LI      0       13:47:20.578    TestScript (EURUSD,H1)  columns = 4 rows = 40
CQ      0       13:47:20.578    TestScript (EURUSD,H1)  rows total 36 High 5
GH      0       13:47:20.578    TestScript (EURUSD,H1)  Column 2 removed from the Matrix, The remaining dataset is
MP      0       13:47:20.578    TestScript (EURUSD,H1)  "Temp"        "Wind"        "PlayTennis "
QG      0       13:47:20.578    TestScript (EURUSD,H1)  [ 
LL      0       13:47:20.578    TestScript (EURUSD,H1)  "Hot"  "Weak" "No"  
OE      0       13:47:20.578    TestScript (EURUSD,H1)  "Hot"    "Strong" "No"    
QQ      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild" "Weak" "No"  
QE      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild" "Weak" "Yes" 
LQ      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild"   "Strong" "No"    
HE      0       13:47:20.578    TestScript (EURUSD,H1)  "Cool" "Weak" "Yes" 
RM      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild"   "Strong" "Yes"   
PF      0       13:47:20.578    TestScript (EURUSD,H1)  "Cool" "Weak" "Yes" 
MR      0       13:47:20.578    TestScript (EURUSD,H1)  "Cool"   "Strong" "No"    
IF      0       13:47:20.578    TestScript (EURUSD,H1)  "Mild" "Weak" "Yes" 
EN      0       13:47:20.578    TestScript (EURUSD,H1)  ] 
ME      0       13:47:20.578    TestScript (EURUSD,H1)  columns = 3 rows = 22
ER      0       13:47:20.578    TestScript (EURUSD,H1)  Final Parent Entropy Array and Class Numbers
HK      0       13:47:20.578    TestScript (EURUSD,H1)  "High"   "Normal" "Cool"  
CQ      0       13:47:20.578    TestScript (EURUSD,H1)  0.7219 0.7219 0.9183
OK      0       13:47:20.578    TestScript (EURUSD,H1)  5 5 3
NS      0       13:47:20.578    TestScript (EURUSD,H1)  <<<<<<<<    Parent Entropy  0.91830  A = 2  >>>>>>>> 
JM      0       13:47:20.578    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Temp   >>>>>  
CG      0       13:47:20.578    TestScript (EURUSD,H1)       <<   Hot   >> total > 2
DM      0       13:47:20.578    TestScript (EURUSD,H1)  "No"  "Yes"
LF      0       13:47:20.578    TestScript (EURUSD,H1)  2 0
HN      0       13:47:20.578    TestScript (EURUSD,H1)  Entropy of Hot = 0.00000
OJ      0       13:47:20.578    TestScript (EURUSD,H1)       <<   Mild   >> total > 5
JS      0       13:47:20.578    TestScript (EURUSD,H1)  "No"  "Yes"
GD      0       13:47:20.578    TestScript (EURUSD,H1)  2 3
QG      0       13:47:20.578    TestScript (EURUSD,H1)  Entropy of Mild = 0.97095
LL      0       13:47:20.578    TestScript (EURUSD,H1)       <<   Cool   >> total > 3
JQ      0       13:47:20.578    TestScript (EURUSD,H1)  "No"  "Yes"
IR      0       13:47:20.578    TestScript (EURUSD,H1)  1 2
OE      0       13:47:20.578    TestScript (EURUSD,H1)  Entropy of Cool = 0.91830
RO      0       13:47:20.578    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.15733 >>>>>> 
PO      0       13:47:20.578    TestScript (EURUSD,H1)  
JS      0       13:47:20.578    TestScript (EURUSD,H1)     <<<<<   C O L U M N  Wind   >>>>>  
JR      0       13:47:20.578    TestScript (EURUSD,H1)       <<   Weak   >> total > 6
NH      0       13:47:20.578    TestScript (EURUSD,H1)  "No"  "Yes"
JM      0       13:47:20.578    TestScript (EURUSD,H1)  2 4
JL      0       13:47:20.578    TestScript (EURUSD,H1)  Entropy of Weak = 0.91830
QD      0       13:47:20.578    TestScript (EURUSD,H1)       <<   Strong   >> total > 4
JN      0       13:47:20.578    TestScript (EURUSD,H1)  "No"  "Yes"
JK      0       13:47:20.578    TestScript (EURUSD,H1)  3 1
DM      0       13:47:20.578    TestScript (EURUSD,H1)  Entropy of Strong = 0.81128
JF      0       13:47:20.578    TestScript (EURUSD,H1)  <<<<<<  Column Information Gain 0.04281 >>>>>> 
DG      0       13:47:20.578    TestScript (EURUSD,H1)  
LI      0       13:47:20.578    TestScript (EURUSD,H1)  Parent Noce will be Temp with IG = 0.15733
LH      0       13:47:20.584    TestScript (EURUSD,H1)  Parent Entropy Array and Class Numbers
GR      0       13:47:20.584    TestScript (EURUSD,H1)  "Hot"  "Mild" "Cool"
CD      0       13:47:20.584    TestScript (EURUSD,H1)  0.0000 0.9710 0.9183
GN      0       13:47:20.584    TestScript (EURUSD,H1)  2 5 3
CK      0       13:47:20.584    TestScript (EURUSD,H1)  Classified matrix dataset
RL      0       13:47:20.584    TestScript (EURUSD,H1)  "Temp"        "Wind"        "PlayTennis "
NK      0       13:47:20.584    TestScript (EURUSD,H1)  [ 
CQ      0       13:47:20.584    TestScript (EURUSD,H1)  "Hot"  "Weak" "No"  
LI      0       13:47:20.584    TestScript (EURUSD,H1)  "Hot"    "Strong" "No"    
JM      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild" "Weak" "No"  
NI      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild" "Weak" "Yes" 
CL      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild"   "Strong" "No"    
KI      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild"   "Strong" "Yes"   
LR      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild" "Weak" "Yes" 
KJ      0       13:47:20.584    TestScript (EURUSD,H1)  "Cool" "Weak" "Yes" 
IQ      0       13:47:20.584    TestScript (EURUSD,H1)  "Cool" "Weak" "Yes" 
DE      0       13:47:20.584    TestScript (EURUSD,H1)  "Cool"   "Strong" "No"    
NR      0       13:47:20.584    TestScript (EURUSD,H1)  ] 
OI      0       13:47:20.584    TestScript (EURUSD,H1)  columns = 3 rows = 30
OO      0       13:47:20.584    TestScript (EURUSD,H1)  Hot is A LEAF NODE its Rows have been removed from the dataset remaining Dataset is ..
HL      0       13:47:20.584    TestScript (EURUSD,H1)  "Temp"        "Wind"        "PlayTennis "
DJ      0       13:47:20.584    TestScript (EURUSD,H1)  [ 
DL      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild" "Weak" "No"  
LH      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild" "Weak" "Yes" 
QL      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild"   "Strong" "No"    
MH      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild"   "Strong" "Yes"   
RQ      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild" "Weak" "Yes" 
MI      0       13:47:20.584    TestScript (EURUSD,H1)  "Cool" "Weak" "Yes" 
KQ      0       13:47:20.584    TestScript (EURUSD,H1)  "Cool" "Weak" "Yes" 
FD      0       13:47:20.584    TestScript (EURUSD,H1)  "Cool"   "Strong" "No"    
HQ      0       13:47:20.584    TestScript (EURUSD,H1)  ] 
NN      0       13:47:20.584    TestScript (EURUSD,H1)  columns = 3 rows = 24
IF      0       13:47:20.584    TestScript (EURUSD,H1)  rows total 24 Mild 5
CO      0       13:47:20.584    TestScript (EURUSD,H1)  Column 1 removed from the Matrix, The remaining dataset is
DM      0       13:47:20.584    TestScript (EURUSD,H1)  "Wind"        "PlayTennis "
PD      0       13:47:20.584    TestScript (EURUSD,H1)  [ 
LN      0       13:47:20.584    TestScript (EURUSD,H1)  "Weak" "No"  
JI      0       13:47:20.584    TestScript (EURUSD,H1)  "Weak" "Yes" 
EL      0       13:47:20.584    TestScript (EURUSD,H1)  "Strong" "No"    
GO      0       13:47:20.584    TestScript (EURUSD,H1)  "Strong" "Yes"   
JG      0       13:47:20.584    TestScript (EURUSD,H1)  "Weak" "Yes" 
JN      0       13:47:20.584    TestScript (EURUSD,H1)  "Weak" "Yes" 
JE      0       13:47:20.584    TestScript (EURUSD,H1)  "Weak" "Yes" 
EP      0       13:47:20.584    TestScript (EURUSD,H1)  "Strong" "No"    
HK      0       13:47:20.584    TestScript (EURUSD,H1)  ] 
PP      0       13:47:20.584    TestScript (EURUSD,H1)  columns = 2 rows = 10
HG      0       13:47:20.584    TestScript (EURUSD,H1)  Final Parent Entropy Array and Class Numbers
FQ      0       13:47:20.584    TestScript (EURUSD,H1)  "Mild" "Cool"
OF      0       13:47:20.584    TestScript (EURUSD,H1)  0.9710 0.9183
IO      0       13:47:20.584    TestScript (EURUSD,H1)  5 3


A continuación, mostramos la función que construye un árbol. Esta parte del código me pareció bastante complicada e incomprensible, a pesar de que al realizar el cálculo manual, el proceso parecía bastante sencillo. Por lo tanto, he decidido analizarlo con detalle en esta sección.


void CDecisionTree::BuildTree(void)
 {   
    int ClassNumbers[];
    
    int max_gain = 0;
    double IGArr[]; 
    //double parent_entropy = Entropy(p_ClassNumbers,single_rowstotal);
    
    string p_Classes[];     //parent classes
    double P_EntropyArr[];  //Parent Entropy
    int p_ClassNumbers[]; //parent/ Target variable class numbers
    
    GetClasses(TargetArr,m_DatasetClasses,p_ClassNumbers);
    
    ArrayResize(P_EntropyArr,1);
    P_EntropyArr[0] = Entropy(p_ClassNumbers,single_rowstotal);

//--- temporary disposable arrays for parent node information

   string TempP_Classes[];
   double TempP_EntropyArr[];
   int    TempP_ClassNumbers[];
   
//---

    if (m_debug) Print("Default Parent Entropy ",P_EntropyArr[0]);
   
    int cols = m_colschosen; 
     
        
      for (int A =0; A<ArraySize(P_EntropyArr); A++)  
        {
           printf("<<<<<<<<    Parent Entropy  %.5f  A = %d  >>>>>>>> ",P_EntropyArr[A],A);
           
           
             for (int i=0; i<cols-1; i++) //вычитаем единицу, чтобы удалить независимую переменную
               {
                  int rows = ArraySize(m_dataset)/cols;
                    
                    string Arr[]; //ArrayFor the current column
                    string ArrTarg[]; //Array for the current target
                    
                    ArrayResize(Arr,rows);
                    ArrayResize(ArrTarg,rows);
                    
                       printf("   <<<<<   C O L U M N  %s   >>>>>  ",DataColumnNames[i]);
                       int index_target=cols-1;
                       for (int j=0; j<rows; j++) //get column data and its target column
                          {
                              int index = i+j * cols;
                              //Print("index ",index);
                              Arr[j] = m_dataset[index];
         
                              //printf("ArrTarg[%d] = %s m_dataset[%d] =%s ",j,ArrTarg[j],index_target,m_dataset[index_target]);
                              ArrTarg[j] = m_dataset[index_target];
                              
                              //printf("Arr[%d] = %s ArrTarg[%d] = %s ",j,Arr[j],j,ArrTarg[j]); 
                              
                              index_target += cols; //the last index of all the columns
                          }  
           
         //--- Finding the Entropy
                        
                     //The function to find the Entropy of samples in a given column inside its loop
                        //then restores all the entropy into one array
                
                        
         //--- Finding the Information Gain
                  
                        //The Function to find the information gain from the entropy array above

         //---

                        if (i == max_gain)
                         { 
                          //The Function to find the information gain from the entropy array above
                        //store it to the parent information gain
                         }
                  
         //---
                  
                  ZeroMemory(ClassNumbers);
                  ZeroMemory(SamplesNumbers);
                  
               }
               
         //---- Get the parent Entropy, class and class numbers
               // here we store the obtained parent class from the information gain metric then we store them into a parent array
                  ArrayCopy(p_Classes,TempP_Classes);
                  ArrayCopy(P_EntropyArr,TempP_EntropyArr);
                  ArrayCopy(p_ClassNumbers,TempP_ClassNumbers);
               
         //---
         
            string Node[1]; 
            Node[0] = DataColumnNames[max_gain];
            
            if (m_debug)
            printf("Parent Node will be %s with IG = %.5f",Node[0],IGArr[max_gain]);
            
            if (A == 0)
             DrawTree(Node,"parent",A);

             DrawTree(p_Classes,"child",A);
            
       
            
         //---  CLASSIFY THE MATRIX
         MatrixClassify(m_dataset,p_Classes,cols);
         
          
         //--- Search if there is zero entropy in Array if there is any remove its data from the dataset
                 

            if (P_EntropyArr[e] == 0) { zero_entropy = true; zero_entropy_index=e; break; }
            
            if (zero_entropy) //if there is zero in the Entropy Array 
              {
                MatrixRemoveRow(m_dataset,p_Classes[zero_entropy_index],cols);    
               
                rows_total = ArraySize(m_dataset); //New number of total rows from Array   
           
                
                //we also remove the entropy from the Array and its information everywhere else from the parent Node That we are going to build next
                
                ArrayRemove(P_EntropyArr,zero_entropy_index,1);
                ArrayRemove(p_Classes,zero_entropy_index,1);
                ArrayRemove(p_ClassNumbers,zero_entropy_index,1);
              }
            
            if (m_debug)  
             Print("rows total ",rows_total," ",p_Classes[zero_entropy_index]," ",p_ClassNumbers[zero_entropy_index]);
            
//---    REMOVING THE PARENT/ ROOT NODE FROM OUR DATASET

            MatrixRemoveColumn(m_dataset,max_gain,cols);
         
         // After removing the columns assign the new values to these global variables
         
            cols = cols-1;   // remove that one column that has been removed
            rows_total = rows_total - single_rowstotal; //remove the size of one column rows
            
         // we also remove the column from column names Array
            ArrayRemove(DataColumnNames,max_gain,1);

            
//---

         
      }

      
 }


Conclusión

En el material de hoy, hemos analizado los cálculos básicos relacionados con los árboles de clasificación. Este es un tema demasiado complejo y largo para tratarlo en un solo artículo. Espero terminarlo en el próximo artículo, o en dos, a lo sumo. Eso sí, la biblioteca ya tiene casi todo lo necesario para comenzar a construir algoritmos de árboles de decisión y resolver problemas comerciales con la ayuda de estos.

¡Gracias por su atención! Aquí hay un enlace a mi github:https://github.com/MegaJoctan/DecisionTree-Classification-tree-MQL5.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/11061

Archivos adjuntos |
decisiontree_2.zip (42.95 KB)
Redes neuronales: así de sencillo (Parte 18): Reglas asociativas Redes neuronales: así de sencillo (Parte 18): Reglas asociativas
Como continuación de esta serie, hoy presentamos otro tipo de tarea relacionada con los métodos de aprendizaje no supervisado: la búsqueda de reglas asociativas. Este tipo de tarea se usó por primera vez en el comercio minorista para analizar las cestas de la compra. En este artículo, hablaremos de las posibilidades que ofrece el uso de dichos algoritmos en el trading.
Características del Wizard MQL5 que debe conocer (Parte 1): Análisis de regresión Características del Wizard MQL5 que debe conocer (Parte 1): Análisis de regresión
De manera consciente o inconsciente, el tráder moderno está casi siempre en busca de nuevas ideas, probando constantemente nuevas estrategias, modificándolas y descartando las que han fracasado. Este proceso de investigación requiere mucho tiempo y se ve acompañado por muchos errores. En esta serie de artículos, intentaré demostrar que el Wizard MQL5 es un verdadero apoyo para el tráder. Gracias al Wizard, el tráder podrá ahorrar tiempo a la hora de poner en práctica sus ideas. Asimismo, podrá reducir la probabilidad de que surjan errores por duplicación de código. En lugar de perder el tiempo con el código, los tráders tendrán la posibilidad de poner en práctica su filosofía comercial.
Aprendiendo a diseñar un sistema de trading con Ichimoku Aprendiendo a diseñar un sistema de trading con Ichimoku
Este artículo continúa la serie sobre la construcción de sistemas comerciales basados en los indicadores más populares. Esta vez hablaremos del indicador Iсhimoku y crearemos un sistema comercial basado en sus indicadores.
Metamodelos en el aprendizaje automático y el trading: Timing original de las órdenes comerciales Metamodelos en el aprendizaje automático y el trading: Timing original de las órdenes comerciales
Metamodelos en el aprendizaje automático: Creación automática de sistemas comerciales sin apenas intervención humana: el Modelo decide por sí mismo cómo y cuándo comerciar.