Aprendizaje automático y data science (Parte 05): Árboles de decisión usando como ejemplo las condiciones meteorológicas para jugar al tenis
¿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.
¡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:
- Regresión lineal
- Regresión logística
- Árboles de decisión
- Máquinas de vectores soporte
- Bosques aleatorios
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.
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:
- ID3 — extensión de D3
- C4.5 — sucesor de ID3
- CART — árbol de clasificación y regresión
- CHAID — la detección automática de interacción de chi-cuadrado (CHAID), realiza divisiones de varios niveles al calcular árboles de clasificación
- 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.
- Árboles de clasificación
- Á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).
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.
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:
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.
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.
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
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)]
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
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.
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.
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.
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.
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í.
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
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso