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.
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.
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.
19
* Copyright (C) 2000 University of Waikato
23
package weka.classifiers.meta;
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;
36
import java.util.Random;
39
<!-- globalinfo-start -->
40
* Implements Grading. The base classifiers are "graded".<br/>
42
* For more information, see<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.
46
<!-- globalinfo-end -->
48
<!-- technical-bibtex-start -->
51
* @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.},
57
* publisher = {Springer},
58
* title = {An Evaluation of Grading Classifiers},
63
<!-- technical-bibtex-end -->
65
<!-- options-start -->
66
* Valid options are: <p/>
68
* <pre> -M <scheme specification>
69
* Full name of meta classifier, followed by options.
70
* (default: "weka.classifiers.rules.Zero")</pre>
72
* <pre> -X <number of folds>
73
* Sets the number of cross-validation folds.</pre>
75
* <pre> -S <num>
79
* <pre> -B <classifier specification>
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>
85
* If set, classifier is run in debug mode and
86
* may output additional info to the console</pre>
90
* @author Alexander K. Seewald (alex@seewald.at)
91
* @author Eibe Frank (eibe@cs.waikato.ac.nz)
92
* @version $Revision: 1.12 $
96
implements TechnicalInformationHandler {
98
/** for serialization */
99
static final long serialVersionUID = 5207837947890081170L;
101
/** The meta classifiers, one for each base classifier. */
102
protected Classifier [] m_MetaClassifiers = new Classifier[0];
105
protected double [] m_InstPerClass = null;
108
* Returns a string describing classifier
109
* @return a description suitable for
110
* displaying in the explorer/experimenter gui
112
public String globalInfo() {
115
"Implements Grading. The base classifiers are \"graded\".\n\n"
116
+ "For more information, see\n\n"
117
+ getTechnicalInformation().toString();
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.
125
* @return the technical information about this class
127
public TechnicalInformation getTechnicalInformation() {
128
TechnicalInformation result;
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");
144
* Generates the meta data
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
150
protected void generateMetaLevel(Instances newData, Random random)
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);
158
for (int j = 0; j < m_NumFolds; j++) {
160
Instances train = newData.trainCV(m_NumFolds, j, random);
161
Instances test = newData.testCV(m_NumFolds, j);
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));
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()]++;
179
m_MetaClassifiers = Classifier.makeCopies(m_MetaClassifier,
180
m_Classifiers.length);
182
for (int i = 0; i < m_Classifiers.length; i++) {
183
m_MetaClassifiers[i].buildClassifier(metaData[i]);
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).
191
* @param instance the instance to be classified
192
* @throws Exception if instance could not be classified
194
* @return the class distribution for the given instance
196
public double[] distributionForInstance(Instance instance) throws Exception {
200
int numClassifiers=m_Classifiers.length;
202
double [] predConfs = new double[numClassifiers];
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];
210
predConfs[i]=-preds[0];
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];
216
for (int i=0; i<numClassifiers; i++) // otherwise ignore neg. conf
217
if (predConfs[i]<0) predConfs[i]=0.0;
220
/*System.out.print(preds[0]);
221
System.out.print(":");
222
System.out.print(preds[1]);
223
System.out.println("#");*/
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];
232
maxPreds=preds[Utils.maxIndex(preds)];
233
int MaxInstPerClass=-100;
235
for (int i=0; i<instance.numClasses(); i++) {
236
if (preds[i]==maxPreds) {
238
if (m_InstPerClass[i]>MaxInstPerClass) {
239
MaxInstPerClass=(int)m_InstPerClass[i];
247
predictedIndex = Utils.maxIndex(preds);
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]);
256
// System.out.println(MaxClass);
257
predictedIndex = MaxClass;
259
double[] classProbs = new double[instance.numClasses()];
260
classProbs[predictedIndex] = 1.0;
265
* Output a representation of this classifier
267
* @return a string representation of the classifier
269
public String toString() {
271
if (m_Classifiers.length == 0) {
272
return "Grading: No base schemes entered.";
274
if (m_MetaClassifiers.length == 0) {
275
return "Grading: No meta scheme selected.";
277
if (m_MetaFormat == null) {
278
return "Grading: No model built yet.";
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";
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";
294
* Makes the format for the level-1 data.
296
* @param instances the level-0 format
297
* @return the format for the meta data
298
* @throws Exception if an error occurs
300
protected Instances metaFormat(Instances instances) throws Exception {
302
FastVector attributes = new FastVector();
303
Instances metaFormat;
305
for (int i = 0; i<instances.numAttributes(); i++) {
306
if ( i != instances.classIndex() ) {
307
attributes.addElement(instances.attribute(i));
311
FastVector nomElements = new FastVector(2);
312
nomElements.addElement("0");
313
nomElements.addElement("1");
314
attributes.addElement(new Attribute("PredConf",nomElements));
316
metaFormat = new Instances("Meta format", attributes, 0);
317
metaFormat.setClassIndex(metaFormat.numAttributes()-1);
322
* Makes a level-1 instance from the given instance.
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
329
protected Instance metaInstance(Instance instance, int k) throws Exception {
331
double[] values = new double[m_MetaFormat.numAttributes()];
332
Instance metaInstance;
339
for (i = 0; i < instance.numAttributes(); i++) {
340
if (i != instance.classIndex()) {
341
values[idx] = instance.value(i);
346
Classifier classifier = getClassifier(k);
348
if (m_BaseFormat.classAttribute().isNumeric()) {
349
throw new Exception("Class Attribute must not be numeric!");
351
double[] dist = classifier.distributionForInstance(instance);
355
for (int j = 1; j < dist.length; j++) {
356
if (dist[j]>maxVal) {
361
predConf= (instance.classValue()==maxIdx) ? 1:0;
364
values[idx]=predConf;
365
metaInstance = new Instance(1, values);
366
metaInstance.setDataset(m_MetaFormat);
371
* Main method for testing this class.
373
* @param argv should contain the following arguments:
374
* -t training file [-T test file] [-c class index]
376
public static void main(String [] argv) {
377
runClassifier(new Grading(), argv);