~ubuntu-branches/ubuntu/precise/weka/precise

« back to all changes in this revision

Viewing changes to weka/classifiers/trees/j48/ClassifierTree.java

  • Committer: Bazaar Package Importer
  • Author(s): Soeren Sonnenburg
  • Date: 2008-02-24 09:18:45 UTC
  • Revision ID: james.westby@ubuntu.com-20080224091845-1l8zy6fm6xipbzsr
Tags: upstream-3.5.7+tut1
ImportĀ upstreamĀ versionĀ 3.5.7+tut1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *    This program is free software; you can redistribute it and/or modify
 
3
 *    it under the terms of the GNU General Public License as published by
 
4
 *    the Free Software Foundation; either version 2 of the License, or
 
5
 *    (at your option) any later version.
 
6
 *
 
7
 *    This program is distributed in the hope that it will be useful,
 
8
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
 *    GNU General Public License for more details.
 
11
 *
 
12
 *    You should have received a copy of the GNU General Public License
 
13
 *    along with this program; if not, write to the Free Software
 
14
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
15
 */
 
16
 
 
17
/*
 
18
 *    ClassifierTree.java
 
19
 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
 
20
 *
 
21
 */
 
22
 
 
23
package weka.classifiers.trees.j48;
 
24
 
 
25
import weka.core.Capabilities;
 
26
import weka.core.CapabilitiesHandler;
 
27
import weka.core.Drawable;
 
28
import weka.core.Instance;
 
29
import weka.core.Instances;
 
30
import weka.core.Utils;
 
31
 
 
32
import java.io.Serializable;
 
33
 
 
34
/**
 
35
 * Class for handling a tree structure used for
 
36
 * classification.
 
37
 *
 
38
 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
 
39
 * @version $Revision: 1.21 $
 
40
 */
 
41
public class ClassifierTree 
 
42
  implements Drawable, Serializable, CapabilitiesHandler {
 
43
 
 
44
  /** for serialization */
 
45
  static final long serialVersionUID = -8722249377542734193L;
 
46
  
 
47
  /** The model selection method. */  
 
48
  protected ModelSelection m_toSelectModel;     
 
49
 
 
50
  /** Local model at node. */
 
51
  protected ClassifierSplitModel m_localModel;  
 
52
 
 
53
  /** References to sons. */
 
54
  protected ClassifierTree [] m_sons;           
 
55
 
 
56
  /** True if node is leaf. */
 
57
  protected boolean m_isLeaf;                   
 
58
 
 
59
  /** True if node is empty. */
 
60
  protected boolean m_isEmpty;                  
 
61
 
 
62
  /** The training instances. */
 
63
  protected Instances m_train;                  
 
64
 
 
65
  /** The pruning instances. */
 
66
  protected Distribution m_test;     
 
67
 
 
68
  /** The id for the node. */
 
69
  protected int m_id;
 
70
 
 
71
  /** 
 
72
   * For getting a unique ID when outputting the tree (hashcode isn't
 
73
   * guaranteed unique) 
 
74
   */
 
75
  private static long PRINTED_NODES = 0;
 
76
 
 
77
  /**
 
78
   * Gets the next unique node ID.
 
79
   *
 
80
   * @return the next unique node ID.
 
81
   */
 
82
  protected static long nextID() {
 
83
 
 
84
    return PRINTED_NODES ++;
 
85
  }
 
86
 
 
87
  /**
 
88
   * Resets the unique node ID counter (e.g.
 
89
   * between repeated separate print types)
 
90
   */
 
91
  protected static void resetID() {
 
92
 
 
93
    PRINTED_NODES = 0;
 
94
  }
 
95
 
 
96
  /**
 
97
   * Constructor. 
 
98
   */
 
99
  public ClassifierTree(ModelSelection toSelectLocModel) {
 
100
    
 
101
    m_toSelectModel = toSelectLocModel;
 
102
  }
 
103
 
 
104
  /**
 
105
   * Returns default capabilities of the classifier tree.
 
106
   *
 
107
   * @return      the capabilities of this classifier tree
 
108
   */
 
109
  public Capabilities getCapabilities() {
 
110
    return new Capabilities(this);
 
111
  }
 
112
 
 
113
  /**
 
114
   * Method for building a classifier tree.
 
115
   *
 
116
   * @param data the data to build the tree from
 
117
   * @throws Exception if something goes wrong
 
118
   */
 
119
  public void buildClassifier(Instances data) throws Exception {
 
120
 
 
121
    // can classifier tree handle the data?
 
122
    getCapabilities().testWithFail(data);
 
123
 
 
124
    // remove instances with missing class
 
125
    data = new Instances(data);
 
126
    data.deleteWithMissingClass();
 
127
    
 
128
    buildTree(data, false);
 
129
  }
 
130
 
 
131
  /**
 
132
   * Builds the tree structure.
 
133
   *
 
134
   * @param data the data for which the tree structure is to be
 
135
   * generated.
 
136
   * @param keepData is training data to be kept?
 
137
   * @throws Exception if something goes wrong
 
138
   */
 
139
  public void buildTree(Instances data, boolean keepData) throws Exception {
 
140
    
 
141
    Instances [] localInstances;
 
142
 
 
143
    if (keepData) {
 
144
      m_train = data;
 
145
    }
 
146
    m_test = null;
 
147
    m_isLeaf = false;
 
148
    m_isEmpty = false;
 
149
    m_sons = null;
 
150
    m_localModel = m_toSelectModel.selectModel(data);
 
151
    if (m_localModel.numSubsets() > 1) {
 
152
      localInstances = m_localModel.split(data);
 
153
      data = null;
 
154
      m_sons = new ClassifierTree [m_localModel.numSubsets()];
 
155
      for (int i = 0; i < m_sons.length; i++) {
 
156
        m_sons[i] = getNewTree(localInstances[i]);
 
157
        localInstances[i] = null;
 
158
      }
 
159
    }else{
 
160
      m_isLeaf = true;
 
161
      if (Utils.eq(data.sumOfWeights(), 0))
 
162
        m_isEmpty = true;
 
163
      data = null;
 
164
    }
 
165
  }
 
166
 
 
167
  /**
 
168
   * Builds the tree structure with hold out set
 
169
   *
 
170
   * @param train the data for which the tree structure is to be
 
171
   * generated.
 
172
   * @param test the test data for potential pruning
 
173
   * @param keepData is training Data to be kept?
 
174
   * @throws Exception if something goes wrong
 
175
   */
 
176
  public void buildTree(Instances train, Instances test, boolean keepData)
 
177
       throws Exception {
 
178
    
 
179
    Instances [] localTrain, localTest;
 
180
    int i;
 
181
    
 
182
    if (keepData) {
 
183
      m_train = train;
 
184
    }
 
185
    m_isLeaf = false;
 
186
    m_isEmpty = false;
 
187
    m_sons = null;
 
188
    m_localModel = m_toSelectModel.selectModel(train, test);
 
189
    m_test = new Distribution(test, m_localModel);
 
190
    if (m_localModel.numSubsets() > 1) {
 
191
      localTrain = m_localModel.split(train);
 
192
      localTest = m_localModel.split(test);
 
193
      train = test = null;
 
194
      m_sons = new ClassifierTree [m_localModel.numSubsets()];
 
195
      for (i=0;i<m_sons.length;i++) {
 
196
        m_sons[i] = getNewTree(localTrain[i], localTest[i]);
 
197
        localTrain[i] = null;
 
198
        localTest[i] = null;
 
199
      }
 
200
    }else{
 
201
      m_isLeaf = true;
 
202
      if (Utils.eq(train.sumOfWeights(), 0))
 
203
        m_isEmpty = true;
 
204
      train = test = null;
 
205
    }
 
206
  }
 
207
 
 
208
  /** 
 
209
   * Classifies an instance.
 
210
   *
 
211
   * @param instance the instance to classify
 
212
   * @return the classification
 
213
   * @throws Exception if something goes wrong
 
214
   */
 
215
  public double classifyInstance(Instance instance) 
 
216
    throws Exception {
 
217
 
 
218
    double maxProb = -1;
 
219
    double currentProb;
 
220
    int maxIndex = 0;
 
221
    int j;
 
222
 
 
223
    for (j = 0; j < instance.numClasses(); j++) {
 
224
      currentProb = getProbs(j, instance, 1);
 
225
      if (Utils.gr(currentProb,maxProb)) {
 
226
        maxIndex = j;
 
227
        maxProb = currentProb;
 
228
      }
 
229
    }
 
230
 
 
231
    return (double)maxIndex;
 
232
  }
 
233
 
 
234
  /**
 
235
   * Cleanup in order to save memory.
 
236
   * 
 
237
   * @param justHeaderInfo
 
238
   */
 
239
  public final void cleanup(Instances justHeaderInfo) {
 
240
 
 
241
    m_train = justHeaderInfo;
 
242
    m_test = null;
 
243
    if (!m_isLeaf)
 
244
      for (int i = 0; i < m_sons.length; i++)
 
245
        m_sons[i].cleanup(justHeaderInfo);
 
246
  }
 
247
 
 
248
  /** 
 
249
   * Returns class probabilities for a weighted instance.
 
250
   *
 
251
   * @param instance the instance to get the distribution for
 
252
   * @param useLaplace whether to use laplace or not
 
253
   * @return the distribution
 
254
   * @throws Exception if something goes wrong
 
255
   */
 
256
  public final double [] distributionForInstance(Instance instance,
 
257
                                                 boolean useLaplace) 
 
258
       throws Exception {
 
259
 
 
260
    double [] doubles = new double[instance.numClasses()];
 
261
 
 
262
    for (int i = 0; i < doubles.length; i++) {
 
263
      if (!useLaplace) {
 
264
        doubles[i] = getProbs(i, instance, 1);
 
265
      } else {
 
266
        doubles[i] = getProbsLaplace(i, instance, 1);
 
267
      }
 
268
    }
 
269
 
 
270
    return doubles;
 
271
  }
 
272
 
 
273
  /**
 
274
   * Assigns a uniqe id to every node in the tree.
 
275
   * 
 
276
   * @param lastID the last ID that was assign
 
277
   * @return the new current ID
 
278
   */
 
279
  public int assignIDs(int lastID) {
 
280
 
 
281
    int currLastID = lastID + 1;
 
282
 
 
283
    m_id = currLastID;
 
284
    if (m_sons != null) {
 
285
      for (int i = 0; i < m_sons.length; i++) {
 
286
        currLastID = m_sons[i].assignIDs(currLastID);
 
287
      }
 
288
    }
 
289
    return currLastID;
 
290
  }
 
291
 
 
292
  /**
 
293
   *  Returns the type of graph this classifier
 
294
   *  represents.
 
295
   *  @return Drawable.TREE
 
296
   */   
 
297
  public int graphType() {
 
298
      return Drawable.TREE;
 
299
  }
 
300
 
 
301
  /**
 
302
   * Returns graph describing the tree.
 
303
   *
 
304
   * @throws Exception if something goes wrong
 
305
   * @return the tree as graph
 
306
   */
 
307
  public String graph() throws Exception {
 
308
 
 
309
    StringBuffer text = new StringBuffer();
 
310
 
 
311
    assignIDs(-1);
 
312
    text.append("digraph J48Tree {\n");
 
313
    if (m_isLeaf) {
 
314
      text.append("N" + m_id 
 
315
                  + " [label=\"" + 
 
316
                  m_localModel.dumpLabel(0,m_train) + "\" " + 
 
317
                  "shape=box style=filled ");
 
318
      if (m_train != null && m_train.numInstances() > 0) {
 
319
        text.append("data =\n" + m_train + "\n");
 
320
        text.append(",\n");
 
321
 
 
322
      }
 
323
      text.append("]\n");
 
324
    }else {
 
325
      text.append("N" + m_id 
 
326
                  + " [label=\"" + 
 
327
                  m_localModel.leftSide(m_train) + "\" ");
 
328
      if (m_train != null && m_train.numInstances() > 0) {
 
329
        text.append("data =\n" + m_train + "\n");
 
330
        text.append(",\n");
 
331
     }
 
332
      text.append("]\n");
 
333
      graphTree(text);
 
334
    }
 
335
    
 
336
    return text.toString() +"}\n";
 
337
  }
 
338
 
 
339
  /**
 
340
   * Returns tree in prefix order.
 
341
   *
 
342
   * @throws Exception if something goes wrong
 
343
   * @return the prefix order
 
344
   */
 
345
  public String prefix() throws Exception {
 
346
    
 
347
    StringBuffer text;
 
348
 
 
349
    text = new StringBuffer();
 
350
    if (m_isLeaf) {
 
351
      text.append("["+m_localModel.dumpLabel(0,m_train)+"]");
 
352
    }else {
 
353
      prefixTree(text);
 
354
    }
 
355
    
 
356
    return text.toString();
 
357
  }
 
358
 
 
359
  /**
 
360
   * Returns source code for the tree as an if-then statement. The 
 
361
   * class is assigned to variable "p", and assumes the tested 
 
362
   * instance is named "i". The results are returned as two stringbuffers: 
 
363
   * a section of code for assignment of the class, and a section of
 
364
   * code containing support code (eg: other support methods).
 
365
   *
 
366
   * @param className the classname that this static classifier has
 
367
   * @return an array containing two stringbuffers, the first string containing
 
368
   * assignment code, and the second containing source for support code.
 
369
   * @throws Exception if something goes wrong
 
370
   */
 
371
  public StringBuffer [] toSource(String className) throws Exception {
 
372
    
 
373
    StringBuffer [] result = new StringBuffer [2];
 
374
    if (m_isLeaf) {
 
375
      result[0] = new StringBuffer("    p = " 
 
376
        + m_localModel.distribution().maxClass(0) + ";\n");
 
377
      result[1] = new StringBuffer("");
 
378
    } else {
 
379
      StringBuffer text = new StringBuffer();
 
380
      StringBuffer atEnd = new StringBuffer();
 
381
 
 
382
      long printID = ClassifierTree.nextID();
 
383
 
 
384
      text.append("  static double N") 
 
385
        .append(Integer.toHexString(m_localModel.hashCode()) + printID)
 
386
        .append("(Object []i) {\n")
 
387
        .append("    double p = Double.NaN;\n");
 
388
 
 
389
      text.append("    if (")
 
390
        .append(m_localModel.sourceExpression(-1, m_train))
 
391
        .append(") {\n");
 
392
      text.append("      p = ")
 
393
        .append(m_localModel.distribution().maxClass(0))
 
394
        .append(";\n");
 
395
      text.append("    } ");
 
396
      for (int i = 0; i < m_sons.length; i++) {
 
397
        text.append("else if (" + m_localModel.sourceExpression(i, m_train) 
 
398
                    + ") {\n");
 
399
        if (m_sons[i].m_isLeaf) {
 
400
          text.append("      p = " 
 
401
                      + m_localModel.distribution().maxClass(i) + ";\n");
 
402
        } else {
 
403
          StringBuffer [] sub = m_sons[i].toSource(className);
 
404
          text.append(sub[0]);
 
405
          atEnd.append(sub[1]);
 
406
        }
 
407
        text.append("    } ");
 
408
        if (i == m_sons.length - 1) {
 
409
          text.append('\n');
 
410
        }
 
411
      }
 
412
 
 
413
      text.append("    return p;\n  }\n");
 
414
 
 
415
      result[0] = new StringBuffer("    p = " + className + ".N");
 
416
      result[0].append(Integer.toHexString(m_localModel.hashCode()) +  printID)
 
417
        .append("(i);\n");
 
418
      result[1] = text.append(atEnd);
 
419
    }
 
420
    return result;
 
421
  }
 
422
 
 
423
  /**
 
424
   * Returns number of leaves in tree structure.
 
425
   * 
 
426
   * @return the number of leaves
 
427
   */
 
428
  public int numLeaves() {
 
429
    
 
430
    int num = 0;
 
431
    int i;
 
432
    
 
433
    if (m_isLeaf)
 
434
      return 1;
 
435
    else
 
436
      for (i=0;i<m_sons.length;i++)
 
437
        num = num+m_sons[i].numLeaves();
 
438
        
 
439
    return num;
 
440
  }
 
441
 
 
442
  /**
 
443
   * Returns number of nodes in tree structure.
 
444
   * 
 
445
   * @return the number of nodes
 
446
   */
 
447
  public int numNodes() {
 
448
    
 
449
    int no = 1;
 
450
    int i;
 
451
    
 
452
    if (!m_isLeaf)
 
453
      for (i=0;i<m_sons.length;i++)
 
454
        no = no+m_sons[i].numNodes();
 
455
    
 
456
    return no;
 
457
  }
 
458
 
 
459
  /**
 
460
   * Prints tree structure.
 
461
   * 
 
462
   * @return the tree structure
 
463
   */
 
464
  public String toString() {
 
465
 
 
466
    try {
 
467
      StringBuffer text = new StringBuffer();
 
468
      
 
469
      if (m_isLeaf) {
 
470
        text.append(": ");
 
471
        text.append(m_localModel.dumpLabel(0,m_train));
 
472
      }else
 
473
        dumpTree(0,text);
 
474
      text.append("\n\nNumber of Leaves  : \t"+numLeaves()+"\n");
 
475
      text.append("\nSize of the tree : \t"+numNodes()+"\n");
 
476
 
 
477
      return text.toString();
 
478
    } catch (Exception e) {
 
479
      return "Can't print classification tree.";
 
480
    }
 
481
  }
 
482
 
 
483
  /**
 
484
   * Returns a newly created tree.
 
485
   *
 
486
   * @param data the training data
 
487
   * @return the generated tree
 
488
   * @throws Exception if something goes wrong
 
489
   */
 
490
  protected ClassifierTree getNewTree(Instances data) throws Exception {
 
491
         
 
492
    ClassifierTree newTree = new ClassifierTree(m_toSelectModel);
 
493
    newTree.buildTree(data, false);
 
494
    
 
495
    return newTree;
 
496
  }
 
497
 
 
498
  /**
 
499
   * Returns a newly created tree.
 
500
   *
 
501
   * @param train the training data
 
502
   * @param test the pruning data.
 
503
   * @return the generated tree
 
504
   * @throws Exception if something goes wrong
 
505
   */
 
506
  protected ClassifierTree getNewTree(Instances train, Instances test) 
 
507
       throws Exception {
 
508
         
 
509
    ClassifierTree newTree = new ClassifierTree(m_toSelectModel);
 
510
    newTree.buildTree(train, test, false);
 
511
    
 
512
    return newTree;
 
513
  }
 
514
 
 
515
  /**
 
516
   * Help method for printing tree structure.
 
517
   *
 
518
   * @param depth the current depth
 
519
   * @param text for outputting the structure
 
520
   * @throws Exception if something goes wrong
 
521
   */
 
522
  private void dumpTree(int depth, StringBuffer text) 
 
523
       throws Exception {
 
524
    
 
525
    int i,j;
 
526
    
 
527
    for (i=0;i<m_sons.length;i++) {
 
528
      text.append("\n");;
 
529
      for (j=0;j<depth;j++)
 
530
        text.append("|   ");
 
531
      text.append(m_localModel.leftSide(m_train));
 
532
      text.append(m_localModel.rightSide(i, m_train));
 
533
      if (m_sons[i].m_isLeaf) {
 
534
        text.append(": ");
 
535
        text.append(m_localModel.dumpLabel(i,m_train));
 
536
      }else
 
537
        m_sons[i].dumpTree(depth+1,text);
 
538
    }
 
539
  }
 
540
 
 
541
  /**
 
542
   * Help method for printing tree structure as a graph.
 
543
   *
 
544
   * @param text for outputting the tree
 
545
   * @throws Exception if something goes wrong
 
546
   */
 
547
  private void graphTree(StringBuffer text) throws Exception {
 
548
    
 
549
    for (int i = 0; i < m_sons.length; i++) {
 
550
      text.append("N" + m_id  
 
551
                  + "->" + 
 
552
                  "N" + m_sons[i].m_id +
 
553
                  " [label=\"" + m_localModel.rightSide(i,m_train).trim() + 
 
554
                  "\"]\n");
 
555
      if (m_sons[i].m_isLeaf) {
 
556
        text.append("N" + m_sons[i].m_id +
 
557
                    " [label=\""+m_localModel.dumpLabel(i,m_train)+"\" "+ 
 
558
                    "shape=box style=filled ");
 
559
        if (m_train != null && m_train.numInstances() > 0) {
 
560
          text.append("data =\n" + m_sons[i].m_train + "\n");
 
561
          text.append(",\n");
 
562
        }
 
563
        text.append("]\n");
 
564
      } else {
 
565
        text.append("N" + m_sons[i].m_id +
 
566
                    " [label=\""+m_sons[i].m_localModel.leftSide(m_train) + 
 
567
                    "\" ");
 
568
        if (m_train != null && m_train.numInstances() > 0) {
 
569
          text.append("data =\n" + m_sons[i].m_train + "\n");
 
570
          text.append(",\n");
 
571
        }
 
572
        text.append("]\n");
 
573
        m_sons[i].graphTree(text);
 
574
      }
 
575
    }
 
576
  }
 
577
 
 
578
  /**
 
579
   * Prints the tree in prefix form
 
580
   * 
 
581
   * @param text the buffer to output the prefix form to
 
582
   * @throws Exception if something goes wrong
 
583
   */
 
584
  private void prefixTree(StringBuffer text) throws Exception {
 
585
 
 
586
    text.append("[");
 
587
    text.append(m_localModel.leftSide(m_train)+":");
 
588
    for (int i = 0; i < m_sons.length; i++) {
 
589
      if (i > 0) {
 
590
        text.append(",\n");
 
591
      }
 
592
      text.append(m_localModel.rightSide(i, m_train));
 
593
    }
 
594
    for (int i = 0; i < m_sons.length; i++) {
 
595
      if (m_sons[i].m_isLeaf) {
 
596
        text.append("[");
 
597
        text.append(m_localModel.dumpLabel(i,m_train));
 
598
        text.append("]");
 
599
      } else {
 
600
        m_sons[i].prefixTree(text);
 
601
      }
 
602
    }
 
603
    text.append("]");
 
604
  }
 
605
 
 
606
  /**
 
607
   * Help method for computing class probabilities of 
 
608
   * a given instance.
 
609
   *
 
610
   * @param classIndex the class index
 
611
   * @param instance the instance to compute the probabilities for
 
612
   * @param weight the weight to use
 
613
   * @return the laplace probs
 
614
   * @throws Exception if something goes wrong
 
615
   */
 
616
  private double getProbsLaplace(int classIndex, Instance instance, double weight) 
 
617
    throws Exception {
 
618
    
 
619
    double prob = 0;
 
620
    
 
621
    if (m_isLeaf) {
 
622
      return weight * localModel().classProbLaplace(classIndex, instance, -1);
 
623
    } else {
 
624
      int treeIndex = localModel().whichSubset(instance);
 
625
      if (treeIndex == -1) {
 
626
        double[] weights = localModel().weights(instance);
 
627
        for (int i = 0; i < m_sons.length; i++) {
 
628
          if (!son(i).m_isEmpty) {
 
629
        prob += son(i).getProbsLaplace(classIndex, instance, 
 
630
                                             weights[i] * weight);
 
631
          }
 
632
        }
 
633
        return prob;
 
634
      } else {
 
635
        if (son(treeIndex).m_isEmpty) {
 
636
          return weight * localModel().classProbLaplace(classIndex, instance, 
 
637
                                                        treeIndex);
 
638
        } else {
 
639
          return son(treeIndex).getProbsLaplace(classIndex, instance, weight);
 
640
        }
 
641
      }
 
642
    }
 
643
  }
 
644
 
 
645
  /**
 
646
   * Help method for computing class probabilities of 
 
647
   * a given instance.
 
648
   * 
 
649
   * @param classIndex the class index
 
650
   * @param instance the instance to compute the probabilities for
 
651
   * @param weight the weight to use
 
652
   * @return the probs
 
653
   * @throws Exception if something goes wrong
 
654
   */
 
655
  private double getProbs(int classIndex, Instance instance, double weight) 
 
656
    throws Exception {
 
657
    
 
658
    double prob = 0;
 
659
    
 
660
    if (m_isLeaf) {
 
661
      return weight * localModel().classProb(classIndex, instance, -1);
 
662
    } else {
 
663
      int treeIndex = localModel().whichSubset(instance);
 
664
      if (treeIndex == -1) {
 
665
        double[] weights = localModel().weights(instance);
 
666
        for (int i = 0; i < m_sons.length; i++) {
 
667
          if (!son(i).m_isEmpty) {
 
668
            prob += son(i).getProbs(classIndex, instance, 
 
669
                                    weights[i] * weight);
 
670
          }
 
671
        }
 
672
        return prob;
 
673
      } else {
 
674
        if (son(treeIndex).m_isEmpty) {
 
675
          return weight * localModel().classProb(classIndex, instance, 
 
676
                                                 treeIndex);
 
677
        } else {
 
678
          return son(treeIndex).getProbs(classIndex, instance, weight);
 
679
        }
 
680
      }
 
681
    }
 
682
  }
 
683
 
 
684
  /**
 
685
   * Method just exists to make program easier to read.
 
686
   */
 
687
  private ClassifierSplitModel localModel() {
 
688
    
 
689
    return (ClassifierSplitModel)m_localModel;
 
690
  }
 
691
  
 
692
  /**
 
693
   * Method just exists to make program easier to read.
 
694
   */
 
695
  private ClassifierTree son(int index) {
 
696
    
 
697
    return (ClassifierTree)m_sons[index];
 
698
  }
 
699
}
 
700
 
 
701
 
 
702
 
 
703