/*********************************************************************** This file is part of KEEL-software, the Data Mining tool for regression, classification, clustering, pattern mining and so on. Copyright (C) 2004-2010 F. Herrera (herrera@decsai.ugr.es) L. S�nchez (luciano@uniovi.es) J. Alcal�-Fdez (jalcala@decsai.ugr.es) S. Garc�a (sglopez@ujaen.es) A. Fern�ndez (alberto.fernandez@ujaen.es) J. Luengo (julianlm@decsai.ugr.es) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ **********************************************************************/ package keel.Algorithms.Decision_Trees.Target; /** * <p>Title: </p> * * <p>Description: </p> * * <p>Copyright: Copyright (c) 2007</p> * * <p>Company: </p> * * @author not attributable * @version 1.0 */ import org.core.Randomize; public class Tree implements Comparable { Tree hijoD, hijoI; //los dos hijos (arbol binario) Tree padre; //mi padre Nodo nodo; //informacion relevante (<at,op,valor> � clase> boolean isLeaf; //si corresponde a un nodo hoja double fitness; boolean n_e, marcado; myDataset train; int indiceNodoT, indiceNodo; double prob1_var, prob2_var; /** Number of Leafs in the tree */ public static int nodosT, nodos; public static int maxNodos = 100; public static int bienCubiertos; /** Number of examples for each leaf/class **/ public static int ejemplos[][]; public Tree() { } public Tree(Tree pae, myDataset train, double pSplit, boolean primero, double prob1, double prob2) { this.train = train; this.prob1_var = prob1; this.prob2_var = prob2; padre = pae; if (primero) { isLeaf = false; nodosT = 0; nodos = 0; indiceNodo = nodos; indiceNodoT = -1; nodo = new Nodo(isLeaf, train, prob1, prob2); hijoD = new Tree(this, train, pSplit, false, prob1, prob2); hijoI = new Tree(this, train, pSplit, false, prob1, prob2); } else { if ( (nodos < maxNodos) && (Randomize.Rand() < pSplit)) { //yo soy un nodo interior isLeaf = false; nodo = new Nodo(isLeaf, train, prob1, prob2); hijoD = new Tree(this, train, pSplit, false, prob1, prob2); hijoI = new Tree(this, train, pSplit, false, prob1, prob2); nodos++; indiceNodo = nodos; indiceNodoT = -1; } else { indiceNodoT = nodosT; indiceNodo = -1; nodosT++; isLeaf = true; //es el �ltimo nodo = new Nodo(isLeaf, train, prob1, prob2); } } n_e = true; } public Tree copia(Tree padre) { Tree t = new Tree(); t.padre = padre; /*if (t.padre != null){ t.padre = this.padre.copia(); }else{ t.padre = null; }*/ try { t.nodo = nodo.copia(); } catch (java.lang.NullPointerException e) { System.err.println(this.printString()); System.exit(0); } t.fitness = this.fitness; t.n_e = this.n_e; t.train = this.train; t.indiceNodo = this.indiceNodo; t.isLeaf = this.isLeaf; t.prob1_var = this.prob1_var; t.prob2_var = this.prob2_var; if (!this.isLeaf) { t.hijoD = this.hijoD.copia(t); t.hijoI = this.hijoI.copia(t); } return t; } public String printString() { StringBuffer text = new StringBuffer(); printTree(0, text); return text.toString(); } /** Function to print the tree. * * @param depth Depth of the node in the tree. * @param text The tree. * */ private void printTree(int depth, StringBuffer text) { String aux = ""; for (int k = 0; k < depth; k++) { aux += "\t"; } text.append(aux); if (isLeaf) { //text.append(nodo.printString() + " ["+indiceNodoT+"]\n"); text.append(nodo.printString() + " \n"); } else { /*text.append("[" + indiceNodo + "/" + marcado + "] if ( " + nodo.printString() + " ) then{\n");*/ text.append(" if ( " + nodo.printString() + " ) then{\n"); hijoI.printTree(depth + 1, text); text.append(aux + "else{ \n"); hijoD.printTree(depth + 1, text); } text.append(aux + "}\n"); } private void calculaNodosTerminales() { if (isLeaf) { indiceNodoT = nodosT; nodosT++; } else { hijoI.calculaNodosTerminales(); hijoD.calculaNodosTerminales(); } } private void calculaNodos() { if (isLeaf) { //nada marcado = true; } else { indiceNodo = nodos; nodos++; //soy un nodo marcado = false; //para contar luego hijoI.calculaNodos(); hijoD.calculaNodos(); } } public int elijeNodo() { nodos = 0; this.calculaNodos(); int nodo = Randomize.RandintClosed(0, nodos - 2); return nodo; } /*public Tree clone() { Tree arbol = new Tree(); //copiar cosas... return arbol; }*/ public double evaluar() { double Dbic; int clases = train.getnClasses(); //Recalculo nodosT porque es variable de clase y da mal rollo... nodosT = 0; calculaNodosTerminales(); ejemplos = new int[nodosT][clases]; boolean[] ejemplitos = new boolean[train.size()]; for (int i = 0; i < ejemplitos.length; i++) { ejemplitos[i] = true; //todos cubiertos... } //System.err.println("Arbol: \n"+this.printString()); bienCubiertos = 0; algoritmoEvaluacion(ejemplitos); //Ahora hago el recuento: double DT, dt; Dbic = DT = 0; boolean salir = false; for (int i = 0; (i < nodosT) && (!salir); i++) { double aux = 0; int nt = 0; for (int j = 0; j < clases; j++) { nt += ejemplos[i][j]; } for (int j = 0; (j < clases) && (!salir); j++) { if (ejemplos[i][j] > 0) { aux += ejemplos[i][j] * Math.log(1.0 * nt/ejemplos[i][j]); //System.err.println("Nodo["+i+"], Clase["+j+"]: "+(1.0 * nt / ejemplos[i][j])); }/*else { aux = Double.MAX_VALUE; salir = true; }*/ } //System.err.println("Mira -> "+aux); dt = 2 * aux; DT += dt; } Dbic = DT + ( (clases + 1) * nodosT - 1) * Math.log(train.size()); n_e = false; fitness = Dbic; return Dbic; } public double evaluar2() { double Dbic; int clases = train.getnClasses(); //Recalculo nodosT porque es variable de clase y da mal rollo... nodosT = 0; calculaNodosTerminales(); ejemplos = new int[nodosT][clases]; boolean[] ejemplitos = new boolean[train.size()]; for (int i = 0; i < ejemplitos.length; i++) { ejemplitos[i] = true; //todos cubiertos... } //System.err.println("Arbol: \n"+this.printString()); bienCubiertos = 0; algoritmoEvaluacion(ejemplitos); //Ahora hago el recuento: double DT, dt; Dbic = DT = 0; boolean salir = false; int nt = 0; /*for(int i = 0; i < nodosT; i++){ nt+=ejemplos[indiceNodoT][nodo.claseInt]; }*/ Dbic = train.size() - bienCubiertos; /*if (nodosT == 1){ System.err.println("Mira -> " + bienCubiertos); }*/ //System.err.println("DT: "+DT+", Jarl:"+( (clases + 1) * nodosT - 1) * Math.log(train.size())); n_e = false; fitness = Dbic; return Dbic; } private void algoritmoEvaluacion(boolean[] ejemplitos) { if (isLeaf) { //pues me cojo todos los ejemplitos y los guardo en ejemplos para este nodooooooo for (int i = 0; i < ejemplitos.length; i++) { if (ejemplitos[i]) { //esta cubierto en este camino //System.err.println("Para el nodo["+indiceNodoT+"/"+nodosT+"] escojo la clase "+train.getOutputAsInteger(i)); ejemplos[indiceNodoT][train.getOutputAsInteger(i)]++; //Un ejemplo mas para el nodo/clase } } //Asocio la clase a la de mas ejemplos cubiertos int clase = 0; int ejemplosCubiertos = ejemplos[indiceNodoT][0]; int[] cubiertos = new int[train.getnClasses()]; cubiertos[0] = ejemplosCubiertos; for (int i = 1; i < train.getnClasses(); i++) { if (ejemplos[indiceNodoT][clase] < ejemplos[indiceNodoT][i]) { clase = i; ejemplosCubiertos = ejemplos[indiceNodoT][i]; } cubiertos[i] = ejemplos[indiceNodoT][i]; } nodo.clase = train.nombreClase(clase); nodo.claseInt = clase; bienCubiertos += ejemplosCubiertos; /*System.err.print("Para el nodo["+indiceNodo+"]: "); for (int i = 0; i < train.getnClasses(); i++){ System.err.print("Clase "+train.nombreClase(i)+" : "+cubiertos[i]+", "); } System.err.println("");*/ } else { //System.err.println("Para el nodo["+indiceNodo+"/"+nodosT+"] sigo investigando..."); //genero dos conjuntos de ejemplitos segun esten cubiertos por el nodo boolean[] ejemplitosI = new boolean[ejemplitos.length]; boolean[] ejemplitosD = new boolean[ejemplitos.length]; ejemplitosI = ejemplitos.clone(); ejemplitosD = ejemplitos.clone(); for (int i = 0; i < ejemplitos.length; i++) { if (ejemplitos[i]) { if (nodo.cubre(i)) { ejemplitosD[i] = false; //lo cubre el nodo izquierdo y no esta en los ejemplos del derecho } else { ejemplitosI[i] = false; //al reves que el anterior } } } hijoI.algoritmoEvaluacion(ejemplitosI); hijoD.algoritmoEvaluacion(ejemplitosD); } } public void nodeSwap(int nodoYo, int nodoPadre, Tree padre) { //primero busco los dos nodos nodos = 0; this.calculaNodos(); Nodo miNodo = buscar(nodoYo); nodos = 0; padre.calculaNodos(); Nodo suNodo = padre.buscar(nodoPadre); //ahora simplemente intercambio su informacion Nodo aux = miNodo.copia(); miNodo.copiar(suNodo); suNodo.copiar(aux); } private Nodo buscar(int codigoNodo) { this.marcado = true; if (indiceNodo == codigoNodo) { return nodo.copia(); } else { if (!hijoI.marcado) { return hijoI.buscar(codigoNodo); } else if (!hijoD.marcado) { return hijoD.buscar(codigoNodo); } return padre.buscar(codigoNodo); } } public void treeSwap(int nodoYo, int nodoPadre, Tree padre) { //primero busco los dos nodos nodos = 0; this.calculaNodos(); Nodo miNodo = buscar(nodoYo); nodos = 0; padre.calculaNodos(); Nodo suNodo = padre.buscar(nodoPadre); //ahora simplemente intercambio los punteros Nodo aux = miNodo; miNodo = suNodo; suNodo = aux; } public void splitSet(int nodo) { //primero busco los dos nodos nodos = 0; this.calculaNodos(); Nodo miNodo = buscar(nodo); miNodo.splitSet(miNodo.atributos[0], prob1_var, prob2_var); } public void splitRule(int nodo) { //primero busco los dos nodos nodos = 0; this.calculaNodos(); Nodo miNodo = buscar(nodo); if (miNodo.numAtributos > 1) { if (Randomize.Rand() < 0.5) { miNodo.asignaPesos(0.5); } else { miNodo.nuevo(prob1_var, prob2_var); } } else { miNodo.nuevo(prob1_var, prob2_var); } } public String clasificar(double[] ejemplo) { if (isLeaf) { return nodo.clase; } else { if (nodo.cubre(ejemplo)) { return hijoI.clasificar(ejemplo); } else { return hijoD.clasificar(ejemplo); } } } /** * Funcion de minimizacion del fitness * @param a Object Otro arbol * @return int el valor para la comparativa */ public int compareTo(Object a) { if ( ( (Tree) a).fitness > this.fitness) { return -1; } if ( ( (Tree) a).fitness < this.fitness) { return 1; } return 0; } }