source: branches/MetisMQI/src/main/java/weka/classifiers/rules/part/ClassifierDecList.java

Last change on this file was 29, checked in by gnappo, 15 years ago

Taggata versione per la demo e aggiunto branch.

File size: 10.6 KB
Line 
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 *    ClassifierDecList.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.classifiers.rules.part;
24
25import weka.classifiers.trees.j48.ClassifierSplitModel;
26import weka.classifiers.trees.j48.Distribution;
27import weka.classifiers.trees.j48.EntropySplitCrit;
28import weka.classifiers.trees.j48.ModelSelection;
29import weka.classifiers.trees.j48.NoSplit;
30import weka.core.Instance;
31import weka.core.Instances;
32import weka.core.RevisionHandler;
33import weka.core.RevisionUtils;
34import weka.core.Utils;
35
36import java.io.Serializable;
37
38/**
39 * Class for handling a rule (partial tree) for a decision list.
40 *
41 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
42 * @version $Revision: 1.13 $
43 */
44public class ClassifierDecList
45  implements Serializable, RevisionHandler {
46
47  /** for serialization */
48  private static final long serialVersionUID = 7284358349711992497L;
49
50  /** Minimum number of objects */
51  protected int m_minNumObj;
52 
53  /** To compute the entropy. */
54  protected static EntropySplitCrit m_splitCrit = new EntropySplitCrit();
55
56  /** The model selection method. */
57  protected ModelSelection m_toSelectModel;   
58
59  /** Local model at node. */ 
60  protected ClassifierSplitModel m_localModel; 
61
62  /** References to sons. */
63  protected ClassifierDecList [] m_sons;       
64 
65  /** True if node is leaf. */
66  protected boolean m_isLeaf;   
67
68  /** True if node is empty. */
69  protected boolean m_isEmpty;                 
70
71  /** The training instances. */
72  protected Instances m_train;                 
73
74  /** The pruning instances. */ 
75  protected Distribution m_test;               
76
77  /** Which son to expand? */ 
78  protected int indeX;         
79
80  /**
81   * Constructor - just calls constructor of class DecList.
82   */
83  public ClassifierDecList(ModelSelection toSelectLocModel, int minNum){
84
85    m_toSelectModel = toSelectLocModel;
86    m_minNumObj = minNum;
87   }
88 
89  /**
90   * Method for building a pruned partial tree.
91   *
92   * @exception Exception if something goes wrong
93   */
94  public void buildRule(Instances data) throws Exception {
95   
96    buildDecList(data, false);
97
98    cleanup(new Instances(data, 0));
99  }
100 
101  /**
102   * Builds the partial tree without hold out set.
103   *
104   * @exception Exception if something goes wrong
105   */
106  public void buildDecList(Instances data, boolean leaf) throws Exception {
107   
108    Instances [] localInstances,localPruneInstances;
109    int index,ind;
110    int i,j;
111    double sumOfWeights;
112    NoSplit noSplit;
113   
114    m_train = null;
115    m_test = null;
116    m_isLeaf = false;
117    m_isEmpty = false;
118    m_sons = null;
119    indeX = 0;
120    sumOfWeights = data.sumOfWeights();
121    noSplit = new NoSplit (new Distribution((Instances)data));
122    if (leaf)
123      m_localModel = noSplit;
124    else
125      m_localModel = m_toSelectModel.selectModel(data);
126    if (m_localModel.numSubsets() > 1) {
127      localInstances = m_localModel.split(data);
128      data = null;
129      m_sons = new ClassifierDecList [m_localModel.numSubsets()];
130      i = 0;
131      do {
132        i++;
133        ind = chooseIndex();
134        if (ind == -1) {
135          for (j = 0; j < m_sons.length; j++) 
136            if (m_sons[j] == null)
137              m_sons[j] = getNewDecList(localInstances[j],true);
138          if (i < 2) {
139            m_localModel = noSplit;
140            m_isLeaf = true;
141            m_sons = null;
142            if (Utils.eq(sumOfWeights,0))
143              m_isEmpty = true;
144            return;
145          }
146          ind = 0;
147          break;
148        } else 
149          m_sons[ind] = getNewDecList(localInstances[ind],false);
150      } while ((i < m_sons.length) && (m_sons[ind].m_isLeaf));
151     
152      // Choose rule
153      indeX = chooseLastIndex();
154    }else{
155      m_isLeaf = true;
156      if (Utils.eq(sumOfWeights, 0))
157        m_isEmpty = true;
158    }
159  }
160
161  /**
162   * Classifies an instance.
163   *
164   * @exception Exception if something goes wrong
165   */
166  public double classifyInstance(Instance instance)
167       throws Exception {
168
169    double maxProb = -1;
170    double currentProb;
171    int maxIndex = 0;
172    int j;
173
174    for (j = 0; j < instance.numClasses();
175         j++){
176      currentProb = getProbs(j,instance,1);
177      if (Utils.gr(currentProb,maxProb)){
178        maxIndex = j;
179        maxProb = currentProb;
180      }
181    }
182    if (Utils.eq(maxProb,0))
183      return -1.0;
184    else
185      return (double)maxIndex;
186  }
187
188  /**
189   * Returns class probabilities for a weighted instance.
190   *
191   * @exception Exception if something goes wrong
192   */
193  public final double [] distributionForInstance(Instance instance) 
194       throws Exception {
195               
196
197    double [] doubles =
198      new double[instance.numClasses()];
199
200    for (int i = 0; i < doubles.length; i++)
201      doubles[i] = getProbs(i,instance,1);
202   
203    return doubles;
204  }
205 
206  /**
207   * Returns the weight a rule assigns to an instance.
208   *
209   * @exception Exception if something goes wrong
210   */
211  public double weight(Instance instance) throws Exception {
212
213    int subset;
214
215    if (m_isLeaf)
216      return 1;
217    subset = m_localModel.whichSubset(instance);
218    if (subset == -1)
219      return (m_localModel.weights(instance))[indeX]*
220        m_sons[indeX].weight(instance);
221    if (subset == indeX)
222      return m_sons[indeX].weight(instance);
223    return 0;
224  }
225
226  /**
227   * Cleanup in order to save memory.
228   */
229  public final void cleanup(Instances justHeaderInfo) {
230
231    m_train = justHeaderInfo;
232    m_test = null;
233    if (!m_isLeaf)
234      for (int i = 0; i < m_sons.length; i++)
235        if (m_sons[i] != null)
236          m_sons[i].cleanup(justHeaderInfo);
237  }
238
239  /**
240   * Prints rules.
241   */
242  public String toString(){
243
244    try {
245      StringBuffer text;
246     
247      text = new StringBuffer();
248      if (m_isLeaf){
249        text.append(": ");
250        text.append(m_localModel.dumpLabel(0,m_train)+"\n");
251      }else{
252      dumpDecList(text);
253      //dumpTree(0,text);
254      }
255      return text.toString();
256    } catch (Exception e) {
257      return "Can't print rule.";
258    }
259  }
260
261  /**
262   * Returns a newly created tree.
263   *
264   * @exception Exception if something goes wrong
265   */
266  protected ClassifierDecList getNewDecList(Instances train, boolean leaf) 
267    throws Exception {
268         
269    ClassifierDecList newDecList = new ClassifierDecList(m_toSelectModel,
270                                                         m_minNumObj);
271    newDecList.buildDecList(train,leaf);
272   
273    return newDecList;
274  }
275 
276  /**
277   * Method for choosing a subset to expand.
278   */
279  public final int chooseIndex() {
280   
281    int minIndex = -1;
282    double estimated, min = Double.MAX_VALUE;
283    int i, j;
284
285    for (i = 0; i < m_sons.length; i++)
286      if (son(i) == null) {
287        if (Utils.sm(localModel().distribution().perBag(i),
288                     (double)m_minNumObj))
289          estimated = Double.MAX_VALUE;
290        else{
291          estimated = 0;
292          for (j = 0; j < localModel().distribution().numClasses(); j++) 
293            estimated -= m_splitCrit.logFunc(localModel().distribution().
294                                     perClassPerBag(i,j));
295          estimated += m_splitCrit.logFunc(localModel().distribution().
296                                   perBag(i));
297          estimated /= localModel().distribution().perBag(i);
298        }
299        if (Utils.smOrEq(estimated,0))
300          return i;
301        if (Utils.sm(estimated,min)) {
302          min = estimated;
303          minIndex = i;
304        }
305      }
306
307    return minIndex;
308  }
309 
310  /**
311   * Choose last index (ie. choose rule).
312   */
313  public final int chooseLastIndex() {
314   
315    int minIndex = 0;
316    double estimated, min = Double.MAX_VALUE;
317   
318    if (!m_isLeaf) 
319      for (int i = 0; i < m_sons.length; i++)
320        if (son(i) != null) {
321          if (Utils.grOrEq(localModel().distribution().perBag(i),
322                           (double)m_minNumObj)) {
323            estimated = son(i).getSizeOfBranch();
324            if (Utils.sm(estimated,min)) {
325              min = estimated;
326              minIndex = i;
327            }
328          }
329        }
330
331    return minIndex;
332  }
333 
334  /**
335   * Returns the number of instances covered by a branch
336   */
337  protected double getSizeOfBranch() {
338   
339    if (m_isLeaf) {
340      return -localModel().distribution().total();
341    } else
342      return son(indeX).getSizeOfBranch();
343  }
344
345  /**
346   * Help method for printing tree structure.
347   */
348  private void dumpDecList(StringBuffer text) throws Exception {
349   
350    text.append(m_localModel.leftSide(m_train));
351    text.append(m_localModel.rightSide(indeX, m_train));
352    if (m_sons[indeX].m_isLeaf){
353      text.append(": ");
354      text.append(m_localModel.dumpLabel(indeX,m_train)+"\n");
355    }else{
356      text.append(" AND\n");
357      m_sons[indeX].dumpDecList(text);
358    }
359  }
360
361  /**
362   * Dumps the partial tree (only used for debugging)
363   *
364   * @exception Exception Exception if something goes wrong
365   */
366  private void dumpTree(int depth,StringBuffer text)
367       throws Exception {
368   
369    int i,j;
370   
371    for (i=0;i<m_sons.length;i++){
372      text.append("\n");;
373      for (j=0;j<depth;j++)
374        text.append("|   ");
375      text.append(m_localModel.leftSide(m_train));
376      text.append(m_localModel.rightSide(i, m_train));
377      if (m_sons[i] == null)
378        text.append("null");
379      else if (m_sons[i].m_isLeaf){
380        text.append(": ");
381        text.append(m_localModel.dumpLabel(i,m_train));
382      }else
383        m_sons[i].dumpTree(depth+1,text);
384    }
385  }
386
387  /**
388   * Help method for computing class probabilities of
389   * a given instance.
390   *
391   * @exception Exception Exception if something goes wrong
392   */
393  private double getProbs(int classIndex,Instance instance,
394                          double weight) throws Exception {
395   
396    double [] weights;
397    int treeIndex;
398
399    if (m_isLeaf) {
400      return weight * localModel().classProb(classIndex, instance, -1);
401    } else {
402      treeIndex = localModel().whichSubset(instance);
403      if (treeIndex == -1) {
404        weights = localModel().weights(instance);
405        return son(indeX).getProbs(classIndex, instance, 
406                                   weights[indeX] * weight);
407      }else{
408        if (treeIndex == indeX) {
409          return son(indeX).getProbs(classIndex, instance, weight);
410        } else {
411          return 0;
412        }
413      }
414    }
415  }
416
417  /**
418   * Method just exists to make program easier to read.
419   */
420  protected ClassifierSplitModel localModel(){
421   
422    return (ClassifierSplitModel)m_localModel;
423  }
424
425  /**
426   * Method just exists to make program easier to read.
427   */
428  protected ClassifierDecList son(int index){
429   
430    return m_sons[index];
431  }
432 
433  /**
434   * Returns the revision string.
435   *
436   * @return            the revision
437   */
438  public String getRevision() {
439    return RevisionUtils.extract("$Revision: 1.13 $");
440  }
441}
Note: See TracBrowser for help on using the repository browser.