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

« back to all changes in this revision

Viewing changes to weka/classifiers/meta/Grading.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
 *    Grading.java
 
19
 *    Copyright (C) 2000 University of Waikato
 
20
 *
 
21
 */
 
22
 
 
23
package weka.classifiers.meta;
 
24
 
 
25
import weka.classifiers.Classifier;
 
26
import weka.core.Attribute;
 
27
import weka.core.FastVector;
 
28
import weka.core.Instance;
 
29
import weka.core.Instances;
 
30
import weka.core.TechnicalInformation;
 
31
import weka.core.TechnicalInformationHandler;
 
32
import weka.core.Utils;
 
33
import weka.core.TechnicalInformation.Field;
 
34
import weka.core.TechnicalInformation.Type;
 
35
 
 
36
import java.util.Random;
 
37
 
 
38
/**
 
39
 <!-- globalinfo-start -->
 
40
 * Implements Grading. The base classifiers are "graded".<br/>
 
41
 * <br/>
 
42
 * For more information, see<br/>
 
43
 * <br/>
 
44
 * A.K. Seewald, J. Fuernkranz: An Evaluation of Grading Classifiers. In: Advances in Intelligent Data Analysis: 4th International Conference, Berlin/Heidelberg/New York/Tokyo, 115-124, 2001.
 
45
 * <p/>
 
46
 <!-- globalinfo-end -->
 
47
 *
 
48
 <!-- technical-bibtex-start -->
 
49
 * BibTeX:
 
50
 * <pre>
 
51
 * &#64;inproceedings{Seewald2001,
 
52
 *    address = {Berlin/Heidelberg/New York/Tokyo},
 
53
 *    author = {A.K. Seewald and J. Fuernkranz},
 
54
 *    booktitle = {Advances in Intelligent Data Analysis: 4th International Conference},
 
55
 *    editor = {F. Hoffmann et al.},
 
56
 *    pages = {115-124},
 
57
 *    publisher = {Springer},
 
58
 *    title = {An Evaluation of Grading Classifiers},
 
59
 *    year = {2001}
 
60
 * }
 
61
 * </pre>
 
62
 * <p/>
 
63
 <!-- technical-bibtex-end -->
 
64
 *
 
65
 <!-- options-start -->
 
66
 * Valid options are: <p/>
 
67
 * 
 
68
 * <pre> -M &lt;scheme specification&gt;
 
69
 *  Full name of meta classifier, followed by options.
 
70
 *  (default: "weka.classifiers.rules.Zero")</pre>
 
71
 * 
 
72
 * <pre> -X &lt;number of folds&gt;
 
73
 *  Sets the number of cross-validation folds.</pre>
 
74
 * 
 
75
 * <pre> -S &lt;num&gt;
 
76
 *  Random number seed.
 
77
 *  (default 1)</pre>
 
78
 * 
 
79
 * <pre> -B &lt;classifier specification&gt;
 
80
 *  Full class name of classifier to include, followed
 
81
 *  by scheme options. May be specified multiple times.
 
82
 *  (default: "weka.classifiers.rules.ZeroR")</pre>
 
83
 * 
 
84
 * <pre> -D
 
85
 *  If set, classifier is run in debug mode and
 
86
 *  may output additional info to the console</pre>
 
87
 * 
 
88
 <!-- options-end -->
 
89
 *
 
90
 * @author Alexander K. Seewald (alex@seewald.at)
 
91
 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
 
92
 * @version $Revision: 1.12 $ 
 
93
 */
 
94
public class Grading 
 
95
  extends Stacking
 
96
  implements TechnicalInformationHandler {
 
97
 
 
98
  /** for serialization */
 
99
  static final long serialVersionUID = 5207837947890081170L;
 
100
  
 
101
  /** The meta classifiers, one for each base classifier. */
 
102
  protected Classifier [] m_MetaClassifiers = new Classifier[0];
 
103
 
 
104
  /** InstPerClass */
 
105
  protected double [] m_InstPerClass = null;
 
106
    
 
107
  /**
 
108
   * Returns a string describing classifier
 
109
   * @return a description suitable for
 
110
   * displaying in the explorer/experimenter gui
 
111
   */
 
112
  public String globalInfo() {
 
113
 
 
114
    return 
 
115
        "Implements Grading. The base classifiers are \"graded\".\n\n"
 
116
      + "For more information, see\n\n"
 
117
      + getTechnicalInformation().toString();
 
118
  }
 
119
 
 
120
  /**
 
121
   * Returns an instance of a TechnicalInformation object, containing 
 
122
   * detailed information about the technical background of this class,
 
123
   * e.g., paper reference or book this class is based on.
 
124
   * 
 
125
   * @return the technical information about this class
 
126
   */
 
127
  public TechnicalInformation getTechnicalInformation() {
 
128
    TechnicalInformation        result;
 
129
    
 
130
    result = new TechnicalInformation(Type.INPROCEEDINGS);
 
131
    result.setValue(Field.AUTHOR, "A.K. Seewald and J. Fuernkranz");
 
132
    result.setValue(Field.TITLE, "An Evaluation of Grading Classifiers");
 
133
    result.setValue(Field.BOOKTITLE, "Advances in Intelligent Data Analysis: 4th International Conference");
 
134
    result.setValue(Field.EDITOR, "F. Hoffmann et al.");
 
135
    result.setValue(Field.YEAR, "2001");
 
136
    result.setValue(Field.PAGES, "115-124");
 
137
    result.setValue(Field.PUBLISHER, "Springer");
 
138
    result.setValue(Field.ADDRESS, "Berlin/Heidelberg/New York/Tokyo");
 
139
    
 
140
    return result;
 
141
  }
 
142
 
 
143
  /**
 
144
   * Generates the meta data
 
145
   * 
 
146
   * @param newData the data to work on
 
147
   * @param random the random number generator used in the generation
 
148
   * @throws Exception if generation fails
 
149
   */
 
150
  protected void generateMetaLevel(Instances newData, Random random) 
 
151
    throws Exception {
 
152
 
 
153
    m_MetaFormat = metaFormat(newData);
 
154
    Instances [] metaData = new Instances[m_Classifiers.length];
 
155
    for (int i = 0; i < m_Classifiers.length; i++) {
 
156
      metaData[i] = metaFormat(newData);
 
157
    }
 
158
    for (int j = 0; j < m_NumFolds; j++) {
 
159
 
 
160
      Instances train = newData.trainCV(m_NumFolds, j, random);
 
161
      Instances test = newData.testCV(m_NumFolds, j);
 
162
 
 
163
      // Build base classifiers
 
164
      for (int i = 0; i < m_Classifiers.length; i++) {
 
165
        getClassifier(i).buildClassifier(train);
 
166
        for (int k = 0; k < test.numInstances(); k++) {
 
167
          metaData[i].add(metaInstance(test.instance(k),i));
 
168
        }
 
169
      }
 
170
    }
 
171
        
 
172
    // calculate InstPerClass
 
173
    m_InstPerClass = new double[newData.numClasses()];
 
174
    for (int i=0; i < newData.numClasses(); i++) m_InstPerClass[i]=0.0;
 
175
    for (int i=0; i < newData.numInstances(); i++) {
 
176
      m_InstPerClass[(int)newData.instance(i).classValue()]++;
 
177
    }
 
178
    
 
179
    m_MetaClassifiers = Classifier.makeCopies(m_MetaClassifier,
 
180
                                              m_Classifiers.length);
 
181
 
 
182
    for (int i = 0; i < m_Classifiers.length; i++) {
 
183
      m_MetaClassifiers[i].buildClassifier(metaData[i]);
 
184
    }
 
185
  }
 
186
 
 
187
  /**
 
188
   * Returns class probabilities for a given instance using the stacked classifier.
 
189
   * One class will always get all the probability mass (i.e. probability one).
 
190
   *
 
191
   * @param instance the instance to be classified
 
192
   * @throws Exception if instance could not be classified
 
193
   * successfully
 
194
   * @return the class distribution for the given instance
 
195
   */
 
196
  public double[] distributionForInstance(Instance instance) throws Exception {
 
197
 
 
198
    double maxPreds;
 
199
    int numPreds=0;
 
200
    int numClassifiers=m_Classifiers.length;
 
201
    int idxPreds;
 
202
    double [] predConfs = new double[numClassifiers];
 
203
    double [] preds;
 
204
 
 
205
    for (int i=0; i<numClassifiers; i++) {
 
206
      preds = m_MetaClassifiers[i].distributionForInstance(metaInstance(instance,i));
 
207
      if (m_MetaClassifiers[i].classifyInstance(metaInstance(instance,i))==1)
 
208
        predConfs[i]=preds[1];
 
209
      else
 
210
        predConfs[i]=-preds[0];
 
211
    }
 
212
    if (predConfs[Utils.maxIndex(predConfs)]<0.0) { // no correct classifiers
 
213
      for (int i=0; i<numClassifiers; i++)   // use neg. confidences instead
 
214
        predConfs[i]=1.0+predConfs[i];
 
215
    } else {
 
216
      for (int i=0; i<numClassifiers; i++)   // otherwise ignore neg. conf
 
217
        if (predConfs[i]<0) predConfs[i]=0.0;
 
218
    }
 
219
 
 
220
    /*System.out.print(preds[0]);
 
221
    System.out.print(":");
 
222
    System.out.print(preds[1]);
 
223
    System.out.println("#");*/
 
224
 
 
225
    preds=new double[instance.numClasses()];
 
226
    for (int i=0; i<instance.numClasses(); i++) preds[i]=0.0;
 
227
    for (int i=0; i<numClassifiers; i++) {
 
228
      idxPreds=(int)(m_Classifiers[i].classifyInstance(instance));
 
229
      preds[idxPreds]+=predConfs[i];
 
230
    }
 
231
 
 
232
    maxPreds=preds[Utils.maxIndex(preds)];
 
233
    int MaxInstPerClass=-100;
 
234
    int MaxClass=-1;
 
235
    for (int i=0; i<instance.numClasses(); i++) {
 
236
      if (preds[i]==maxPreds) {
 
237
        numPreds++;
 
238
        if (m_InstPerClass[i]>MaxInstPerClass) {
 
239
          MaxInstPerClass=(int)m_InstPerClass[i];
 
240
          MaxClass=i;
 
241
        }
 
242
      }
 
243
    }
 
244
 
 
245
    int predictedIndex;
 
246
    if (numPreds==1)
 
247
      predictedIndex = Utils.maxIndex(preds);
 
248
    else
 
249
    {
 
250
      // System.out.print("?");
 
251
      // System.out.print(instance.toString());
 
252
      // for (int i=0; i<instance.numClasses(); i++) {
 
253
      //   System.out.print("/");
 
254
      //   System.out.print(preds[i]);
 
255
      // }
 
256
      // System.out.println(MaxClass);
 
257
      predictedIndex = MaxClass;
 
258
    }
 
259
    double[] classProbs = new double[instance.numClasses()];
 
260
    classProbs[predictedIndex] = 1.0;
 
261
    return classProbs;
 
262
  }
 
263
 
 
264
  /**
 
265
   * Output a representation of this classifier
 
266
   * 
 
267
   * @return a string representation of the classifier
 
268
   */
 
269
  public String toString() {
 
270
 
 
271
    if (m_Classifiers.length == 0) {
 
272
      return "Grading: No base schemes entered.";
 
273
    }
 
274
    if (m_MetaClassifiers.length == 0) {
 
275
      return "Grading: No meta scheme selected.";
 
276
    }
 
277
    if (m_MetaFormat == null) {
 
278
      return "Grading: No model built yet.";
 
279
    }
 
280
    String result = "Grading\n\nBase classifiers\n\n";
 
281
    for (int i = 0; i < m_Classifiers.length; i++) {
 
282
      result += getClassifier(i).toString() +"\n\n";
 
283
    }
 
284
   
 
285
    result += "\n\nMeta classifiers\n\n";
 
286
    for (int i = 0; i < m_Classifiers.length; i++) {
 
287
      result += m_MetaClassifiers[i].toString() +"\n\n";
 
288
    }
 
289
 
 
290
    return result;
 
291
  }
 
292
 
 
293
  /**
 
294
   * Makes the format for the level-1 data.
 
295
   *
 
296
   * @param instances the level-0 format
 
297
   * @return the format for the meta data
 
298
   * @throws Exception if an error occurs
 
299
   */
 
300
  protected Instances metaFormat(Instances instances) throws Exception {
 
301
 
 
302
    FastVector attributes = new FastVector();
 
303
    Instances metaFormat;
 
304
    
 
305
    for (int i = 0; i<instances.numAttributes(); i++) {
 
306
        if ( i != instances.classIndex() ) {
 
307
            attributes.addElement(instances.attribute(i));
 
308
        }
 
309
    }
 
310
 
 
311
    FastVector nomElements = new FastVector(2);
 
312
    nomElements.addElement("0");
 
313
    nomElements.addElement("1");
 
314
    attributes.addElement(new Attribute("PredConf",nomElements));
 
315
 
 
316
    metaFormat = new Instances("Meta format", attributes, 0);
 
317
    metaFormat.setClassIndex(metaFormat.numAttributes()-1);
 
318
    return metaFormat;
 
319
  }
 
320
 
 
321
  /**
 
322
   * Makes a level-1 instance from the given instance.
 
323
   * 
 
324
   * @param instance the instance to be transformed
 
325
   * @param k index of the classifier
 
326
   * @return the level-1 instance
 
327
   * @throws Exception if an error occurs
 
328
   */
 
329
  protected Instance metaInstance(Instance instance, int k) throws Exception {
 
330
 
 
331
    double[] values = new double[m_MetaFormat.numAttributes()];
 
332
    Instance metaInstance;
 
333
    double predConf;
 
334
    int i;
 
335
    int maxIdx;
 
336
    double maxVal;
 
337
 
 
338
    int idx = 0;
 
339
    for (i = 0; i < instance.numAttributes(); i++) {
 
340
        if (i != instance.classIndex()) {
 
341
            values[idx] = instance.value(i);
 
342
            idx++;
 
343
        }
 
344
    }
 
345
 
 
346
    Classifier classifier = getClassifier(k);
 
347
 
 
348
    if (m_BaseFormat.classAttribute().isNumeric()) {
 
349
      throw new Exception("Class Attribute must not be numeric!");
 
350
    } else {
 
351
      double[] dist = classifier.distributionForInstance(instance);
 
352
      
 
353
      maxIdx=0;
 
354
      maxVal=dist[0];
 
355
      for (int j = 1; j < dist.length; j++) {
 
356
        if (dist[j]>maxVal) {
 
357
          maxVal=dist[j];
 
358
          maxIdx=j;
 
359
        }
 
360
      }
 
361
      predConf= (instance.classValue()==maxIdx) ? 1:0;
 
362
    }
 
363
    
 
364
    values[idx]=predConf;
 
365
    metaInstance = new Instance(1, values);
 
366
    metaInstance.setDataset(m_MetaFormat);
 
367
    return metaInstance;
 
368
  }
 
369
 
 
370
  /**
 
371
   * Main method for testing this class.
 
372
   *
 
373
   * @param argv should contain the following arguments:
 
374
   * -t training file [-T test file] [-c class index]
 
375
   */
 
376
  public static void main(String [] argv) {
 
377
    runClassifier(new Grading(), argv);
 
378
  }
 
379
}
 
380