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

« back to all changes in this revision

Viewing changes to weka/classifiers/mi/MDD.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
 * MDD.java
 
19
 * Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
 
20
 *
 
21
 */
 
22
 
 
23
package weka.classifiers.mi;
 
24
 
 
25
import weka.classifiers.Classifier;
 
26
import weka.core.Capabilities;
 
27
import weka.core.FastVector;
 
28
import weka.core.Instance;
 
29
import weka.core.Instances;
 
30
import weka.core.MultiInstanceCapabilitiesHandler;
 
31
import weka.core.Optimization;
 
32
import weka.core.Option;
 
33
import weka.core.OptionHandler;
 
34
import weka.core.SelectedTag;
 
35
import weka.core.Tag;
 
36
import weka.core.TechnicalInformation;
 
37
import weka.core.TechnicalInformationHandler;
 
38
import weka.core.Utils;
 
39
import weka.core.Capabilities.Capability;
 
40
import weka.core.TechnicalInformation.Field;
 
41
import weka.core.TechnicalInformation.Type;
 
42
import weka.filters.Filter;
 
43
import weka.filters.unsupervised.attribute.Normalize;
 
44
import weka.filters.unsupervised.attribute.ReplaceMissingValues;
 
45
import weka.filters.unsupervised.attribute.Standardize;
 
46
 
 
47
import java.util.Enumeration;
 
48
import java.util.Vector;
 
49
 
 
50
/**
 
51
 <!-- globalinfo-start -->
 
52
 * Modified Diverse Density algorithm, with collective assumption.<br/>
 
53
 * <br/>
 
54
 * More information about DD:<br/>
 
55
 * <br/>
 
56
 * Oded Maron (1998). Learning from ambiguity.<br/>
 
57
 * <br/>
 
58
 * O. Maron, T. Lozano-Perez (1998). A Framework for Multiple Instance Learning. Neural Information Processing Systems. 10.
 
59
 * <p/>
 
60
 <!-- globalinfo-end -->
 
61
 * 
 
62
 <!-- technical-bibtex-start -->
 
63
 * BibTeX:
 
64
 * <pre>
 
65
 * &#64;phdthesis{Maron1998,
 
66
 *    author = {Oded Maron},
 
67
 *    school = {Massachusetts Institute of Technology},
 
68
 *    title = {Learning from ambiguity},
 
69
 *    year = {1998}
 
70
 * }
 
71
 * 
 
72
 * &#64;article{Maron1998,
 
73
 *    author = {O. Maron and T. Lozano-Perez},
 
74
 *    journal = {Neural Information Processing Systems},
 
75
 *    title = {A Framework for Multiple Instance Learning},
 
76
 *    volume = {10},
 
77
 *    year = {1998}
 
78
 * }
 
79
 * </pre>
 
80
 * <p/>
 
81
 <!-- technical-bibtex-end -->
 
82
 * 
 
83
 <!-- options-start -->
 
84
 * Valid options are: <p/>
 
85
 * 
 
86
 * <pre> -D
 
87
 *  Turn on debugging output.</pre>
 
88
 * 
 
89
 * <pre> -N &lt;num&gt;
 
90
 *  Whether to 0=normalize/1=standardize/2=neither.
 
91
 *  (default 1=standardize)</pre>
 
92
 * 
 
93
 <!-- options-end -->
 
94
 *    
 
95
 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
 
96
 * @author Xin Xu (xx5@cs.waikato.ac.nz)
 
97
 * @version $Revision: 1.3 $ 
 
98
 */
 
99
public class MDD 
 
100
  extends Classifier 
 
101
  implements OptionHandler, MultiInstanceCapabilitiesHandler,
 
102
             TechnicalInformationHandler {
 
103
  
 
104
  /** for serialization */
 
105
  static final long serialVersionUID = -7273119490545290581L;
 
106
 
 
107
  /** The index of the class attribute */
 
108
  protected int m_ClassIndex;
 
109
 
 
110
  protected double[] m_Par;
 
111
 
 
112
  /** The number of the class labels */
 
113
  protected int m_NumClasses;
 
114
 
 
115
  /** Class labels for each bag */
 
116
  protected int[] m_Classes;
 
117
 
 
118
  /** MI data */ 
 
119
  protected double[][][] m_Data;
 
120
 
 
121
  /** All attribute names */
 
122
  protected Instances m_Attributes;
 
123
 
 
124
  /** The filter used to standardize/normalize all values. */
 
125
  protected Filter m_Filter =null;
 
126
 
 
127
  /** Whether to normalize/standardize/neither, default:standardize */
 
128
  protected int m_filterType = FILTER_STANDARDIZE;
 
129
 
 
130
  /** Normalize training data */
 
131
  public static final int FILTER_NORMALIZE = 0;
 
132
  /** Standardize training data */
 
133
  public static final int FILTER_STANDARDIZE = 1;
 
134
  /** No normalization/standardization */
 
135
  public static final int FILTER_NONE = 2;
 
136
  /** The filter to apply to the training data */
 
137
  public static final Tag [] TAGS_FILTER = {
 
138
    new Tag(FILTER_NORMALIZE, "Normalize training data"),
 
139
    new Tag(FILTER_STANDARDIZE, "Standardize training data"),
 
140
    new Tag(FILTER_NONE, "No normalization/standardization"),
 
141
  };
 
142
 
 
143
  /** The filter used to get rid of missing values. */
 
144
  protected ReplaceMissingValues m_Missing = new ReplaceMissingValues();
 
145
 
 
146
  /**
 
147
   * Returns a string describing this filter
 
148
   *
 
149
   * @return a description of the filter suitable for
 
150
   * displaying in the explorer/experimenter gui
 
151
   */
 
152
  public String globalInfo() {
 
153
    return 
 
154
        "Modified Diverse Density algorithm, with collective assumption.\n\n"
 
155
      + "More information about DD:\n\n"
 
156
      + getTechnicalInformation().toString();
 
157
  }
 
158
 
 
159
  /**
 
160
   * Returns an instance of a TechnicalInformation object, containing 
 
161
   * detailed information about the technical background of this class,
 
162
   * e.g., paper reference or book this class is based on.
 
163
   * 
 
164
   * @return the technical information about this class
 
165
   */
 
166
  public TechnicalInformation getTechnicalInformation() {
 
167
    TechnicalInformation        result;
 
168
    TechnicalInformation        additional;
 
169
    
 
170
    result = new TechnicalInformation(Type.PHDTHESIS);
 
171
    result.setValue(Field.AUTHOR, "Oded Maron");
 
172
    result.setValue(Field.YEAR, "1998");
 
173
    result.setValue(Field.TITLE, "Learning from ambiguity");
 
174
    result.setValue(Field.SCHOOL, "Massachusetts Institute of Technology");
 
175
    
 
176
    additional = result.add(Type.ARTICLE);
 
177
    additional.setValue(Field.AUTHOR, "O. Maron and T. Lozano-Perez");
 
178
    additional.setValue(Field.YEAR, "1998");
 
179
    additional.setValue(Field.TITLE, "A Framework for Multiple Instance Learning");
 
180
    additional.setValue(Field.JOURNAL, "Neural Information Processing Systems");
 
181
    additional.setValue(Field.VOLUME, "10");
 
182
    
 
183
    return result;
 
184
  }
 
185
 
 
186
  /**
 
187
   * Returns an enumeration describing the available options
 
188
   *
 
189
   * @return an enumeration of all the available options
 
190
   */
 
191
  public Enumeration listOptions() {
 
192
    Vector result = new Vector();
 
193
    
 
194
    result.addElement(new Option(
 
195
          "\tTurn on debugging output.",
 
196
          "D", 0, "-D"));
 
197
    
 
198
    result.addElement(new Option(
 
199
          "\tWhether to 0=normalize/1=standardize/2=neither.\n"
 
200
          + "\t(default 1=standardize)",
 
201
          "N", 1, "-N <num>"));
 
202
 
 
203
    return result.elements();
 
204
  }
 
205
 
 
206
  /**
 
207
   * Parses a given list of options. 
 
208
   *
 
209
   * @param options the list of options as an array of strings
 
210
   * @throws Exception if an option is not supported
 
211
   */
 
212
  public void setOptions(String[] options) throws Exception {
 
213
    setDebug(Utils.getFlag('D', options));
 
214
 
 
215
    String nString = Utils.getOption('N', options);
 
216
    if (nString.length() != 0) {
 
217
      setFilterType(new SelectedTag(Integer.parseInt(nString), TAGS_FILTER));
 
218
    } else {
 
219
      setFilterType(new SelectedTag(FILTER_STANDARDIZE, TAGS_FILTER));
 
220
    }     
 
221
  }
 
222
 
 
223
  /**
 
224
   * Gets the current settings of the classifier.
 
225
   *
 
226
   * @return an array of strings suitable for passing to setOptions
 
227
   */
 
228
  public String[] getOptions() {
 
229
    Vector        result;
 
230
    
 
231
    result = new Vector();
 
232
 
 
233
    if (getDebug())
 
234
      result.add("-D");
 
235
    
 
236
    result.add("-N");
 
237
    result.add("" + m_filterType);
 
238
 
 
239
    return (String[]) result.toArray(new String[result.size()]);
 
240
  }
 
241
 
 
242
  /**
 
243
   * Returns the tip text for this property
 
244
   *
 
245
   * @return tip text for this property suitable for
 
246
   * displaying in the explorer/experimenter gui
 
247
   */
 
248
  public String filterTypeTipText() {
 
249
    return "The filter type for transforming the training data.";
 
250
  }
 
251
 
 
252
  /**
 
253
   * Gets how the training data will be transformed. Will be one of
 
254
   * FILTER_NORMALIZE, FILTER_STANDARDIZE, FILTER_NONE.
 
255
   *
 
256
   * @return the filtering mode
 
257
   */
 
258
  public SelectedTag getFilterType() {
 
259
    return new SelectedTag(m_filterType, TAGS_FILTER);
 
260
  }
 
261
 
 
262
  /**
 
263
   * Sets how the training data will be transformed. Should be one of
 
264
   * FILTER_NORMALIZE, FILTER_STANDARDIZE, FILTER_NONE.
 
265
   *
 
266
   * @param newType the new filtering mode
 
267
   */
 
268
  public void setFilterType(SelectedTag newType) {
 
269
 
 
270
    if (newType.getTags() == TAGS_FILTER) {
 
271
      m_filterType = newType.getSelectedTag().getID();
 
272
    }
 
273
  }
 
274
 
 
275
 
 
276
  private class OptEng 
 
277
    extends Optimization{
 
278
    
 
279
    /** 
 
280
     * Evaluate objective function
 
281
     * @param x the current values of variables
 
282
     * @return the value of the objective function 
 
283
     */
 
284
    protected double objectiveFunction(double[] x){
 
285
      double nll = 0; // -LogLikelihood
 
286
      for(int i=0; i<m_Classes.length; i++){ // ith bag
 
287
        int nI = m_Data[i][0].length; // numInstances in ith bag
 
288
        double bag = 0;  // NLL of each bag
 
289
 
 
290
        for(int j=0; j<nI; j++){
 
291
          double ins=0.0; 
 
292
          for(int k=0; k<m_Data[i].length; k++) {
 
293
            ins += (m_Data[i][k][j]-x[k*2])*(m_Data[i][k][j]-x[k*2])/
 
294
              (x[k*2+1]*x[k*2+1]);
 
295
          }
 
296
          ins = Math.exp(-ins); 
 
297
 
 
298
          if(m_Classes[i] == 1)
 
299
            bag += ins/(double)nI;
 
300
          else
 
301
            bag += (1.0-ins)/(double)nI;   
 
302
        }               
 
303
        if(bag<=m_Zero) bag=m_Zero; 
 
304
        nll -= Math.log(bag);
 
305
      }         
 
306
 
 
307
      return nll;
 
308
    }
 
309
 
 
310
    /** 
 
311
     * Evaluate Jacobian vector
 
312
     * @param x the current values of variables
 
313
     * @return the gradient vector 
 
314
     */
 
315
    protected double[] evaluateGradient(double[] x){
 
316
      double[] grad = new double[x.length];
 
317
      for(int i=0; i<m_Classes.length; i++){ // ith bag
 
318
        int nI = m_Data[i][0].length; // numInstances in ith bag 
 
319
 
 
320
        double denom=0.0;
 
321
        double[] numrt = new double[x.length];
 
322
 
 
323
        for(int j=0; j<nI; j++){
 
324
          double exp=0.0;
 
325
          for(int k=0; k<m_Data[i].length; k++)
 
326
            exp += (m_Data[i][k][j]-x[k*2])*(m_Data[i][k][j]-x[k*2])/
 
327
              (x[k*2+1]*x[k*2+1]);                      
 
328
          exp = Math.exp(-exp);
 
329
          if(m_Classes[i]==1)
 
330
            denom += exp;
 
331
          else
 
332
            denom += (1.0-exp);            
 
333
 
 
334
          // Instance-wise update
 
335
          for(int p=0; p<m_Data[i].length; p++){  // pth variable
 
336
            numrt[2*p] += exp*2.0*(x[2*p]-m_Data[i][p][j])/
 
337
              (x[2*p+1]*x[2*p+1]);
 
338
            numrt[2*p+1] += 
 
339
              exp*(x[2*p]-m_Data[i][p][j])*(x[2*p]-m_Data[i][p][j])/
 
340
              (x[2*p+1]*x[2*p+1]*x[2*p+1]);
 
341
          }                     
 
342
        }
 
343
 
 
344
        if(denom <= m_Zero){
 
345
          denom = m_Zero;
 
346
        }
 
347
 
 
348
        // Bag-wise update 
 
349
        for(int q=0; q<m_Data[i].length; q++){
 
350
          if(m_Classes[i]==1){
 
351
            grad[2*q] += numrt[2*q]/denom;
 
352
            grad[2*q+1] -= numrt[2*q+1]/denom;
 
353
          }else{
 
354
            grad[2*q] -= numrt[2*q]/denom;
 
355
            grad[2*q+1] += numrt[2*q+1]/denom;
 
356
          }
 
357
        }
 
358
      }
 
359
 
 
360
      return grad;
 
361
    }
 
362
  }
 
363
 
 
364
  /**
 
365
   * Returns default capabilities of the classifier.
 
366
   *
 
367
   * @return      the capabilities of this classifier
 
368
   */
 
369
  public Capabilities getCapabilities() {
 
370
    Capabilities result = super.getCapabilities();
 
371
 
 
372
    // attributes
 
373
    result.enable(Capability.NOMINAL_ATTRIBUTES);
 
374
    result.enable(Capability.RELATIONAL_ATTRIBUTES);
 
375
    result.enable(Capability.MISSING_VALUES);
 
376
 
 
377
    // class
 
378
    result.enable(Capability.BINARY_CLASS);
 
379
    result.enable(Capability.MISSING_CLASS_VALUES);
 
380
    
 
381
    // other
 
382
    result.enable(Capability.ONLY_MULTIINSTANCE);
 
383
    
 
384
    return result;
 
385
  }
 
386
 
 
387
  /**
 
388
   * Returns the capabilities of this multi-instance classifier for the
 
389
   * relational data.
 
390
   *
 
391
   * @return            the capabilities of this object
 
392
   * @see               Capabilities
 
393
   */
 
394
  public Capabilities getMultiInstanceCapabilities() {
 
395
    Capabilities result = super.getCapabilities();
 
396
    
 
397
    // attributes
 
398
    result.enable(Capability.NOMINAL_ATTRIBUTES);
 
399
    result.enable(Capability.NUMERIC_ATTRIBUTES);
 
400
    result.enable(Capability.DATE_ATTRIBUTES);
 
401
    result.enable(Capability.MISSING_VALUES);
 
402
 
 
403
    // class
 
404
    result.disableAllClasses();
 
405
    result.enable(Capability.NO_CLASS);
 
406
    
 
407
    return result;
 
408
  }
 
409
 
 
410
  /**
 
411
   * Builds the classifier
 
412
   *
 
413
   * @param train the training data to be used for generating the
 
414
   * boosted classifier.
 
415
   * @throws Exception if the classifier could not be built successfully
 
416
   */
 
417
  public void buildClassifier(Instances train) throws Exception {
 
418
    // can classifier handle the data?
 
419
    getCapabilities().testWithFail(train);
 
420
 
 
421
    // remove instances with missing class
 
422
    train = new Instances(train);
 
423
    train.deleteWithMissingClass();
 
424
    
 
425
    m_ClassIndex = train.classIndex();
 
426
    m_NumClasses = train.numClasses();
 
427
 
 
428
    int nR = train.attribute(1).relation().numAttributes();
 
429
    int nC = train.numInstances();
 
430
    int [] bagSize=new int [nC];
 
431
    Instances datasets= new Instances(train.attribute(1).relation(),0);
 
432
 
 
433
    m_Data  = new double [nC][nR][];              // Data values
 
434
    m_Classes  = new int [nC];                    // Class values
 
435
    m_Attributes = datasets.stringFreeStructure();              
 
436
    double sY1=0, sY0=0;                          // Number of classes
 
437
 
 
438
    if (m_Debug) {
 
439
      System.out.println("Extracting data...");
 
440
    }
 
441
    FastVector maxSzIdx=new FastVector();
 
442
    int maxSz=0;
 
443
 
 
444
    for(int h=0; h<nC; h++){
 
445
      Instance current = train.instance(h);
 
446
      m_Classes[h] = (int)current.classValue();  // Class value starts from 0
 
447
      Instances currInsts = current.relationalValue(1);
 
448
      int nI = currInsts.numInstances();
 
449
      bagSize[h]=nI;
 
450
 
 
451
      for (int i=0; i<nI;i++){
 
452
        Instance inst=currInsts.instance(i);
 
453
        datasets.add(inst);
 
454
      }
 
455
 
 
456
      if(m_Classes[h]==1){
 
457
        if(nI>maxSz){
 
458
          maxSz=nI;
 
459
          maxSzIdx=new FastVector(1);
 
460
          maxSzIdx.addElement(new Integer(h));
 
461
        }
 
462
        else if(nI == maxSz)
 
463
          maxSzIdx.addElement(new Integer(h));
 
464
      }
 
465
    }
 
466
 
 
467
    /* filter the training data */
 
468
    if (m_filterType == FILTER_STANDARDIZE)  
 
469
      m_Filter = new Standardize();
 
470
    else if (m_filterType == FILTER_NORMALIZE)
 
471
      m_Filter = new Normalize();
 
472
    else 
 
473
      m_Filter = null; 
 
474
 
 
475
    if (m_Filter!=null) {
 
476
      m_Filter.setInputFormat(datasets);
 
477
      datasets = Filter.useFilter(datasets, m_Filter);  
 
478
    }
 
479
 
 
480
    m_Missing.setInputFormat(datasets);
 
481
    datasets = Filter.useFilter(datasets, m_Missing);
 
482
 
 
483
    int instIndex=0;
 
484
    int start=0;        
 
485
    for(int h=0; h<nC; h++)  {  
 
486
      for (int i = 0; i < datasets.numAttributes(); i++) {
 
487
        // initialize m_data[][][]
 
488
        m_Data[h][i] = new double[bagSize[h]];
 
489
        instIndex=start;
 
490
        for (int k=0; k<bagSize[h]; k++){
 
491
          m_Data[h][i][k]=datasets.instance(instIndex).value(i);
 
492
          instIndex ++;
 
493
        }
 
494
      }
 
495
      start=instIndex;
 
496
 
 
497
      // Class count    
 
498
      if (m_Classes[h] == 1)
 
499
        sY1++;          
 
500
      else
 
501
        sY0++;
 
502
    }
 
503
 
 
504
    if (m_Debug) {
 
505
      System.out.println("\nIteration History..." );
 
506
    }
 
507
 
 
508
    double[] x = new double[nR*2], tmp = new double[x.length];
 
509
    double[][] b = new double[2][x.length]; 
 
510
 
 
511
    OptEng opt;
 
512
    double nll, bestnll = Double.MAX_VALUE;
 
513
    for (int t=0; t<x.length; t++){
 
514
      b[0][t] = Double.NaN;
 
515
      b[1][t] = Double.NaN; 
 
516
    }
 
517
 
 
518
    // Largest positive exemplar
 
519
    for(int s=0; s<maxSzIdx.size(); s++){
 
520
      int exIdx = ((Integer)maxSzIdx.elementAt(s)).intValue();
 
521
      for(int p=0; p<m_Data[exIdx][0].length; p++){
 
522
        for (int q=0; q < nR;q++){
 
523
          x[2*q] = m_Data[exIdx][q][p];  // pick one instance
 
524
          x[2*q+1] = 1.0;
 
525
        }               
 
526
 
 
527
        opt = new OptEng();     
 
528
        tmp = opt.findArgmin(x, b);
 
529
        while(tmp==null){
 
530
          tmp = opt.getVarbValues();
 
531
          if (m_Debug)
 
532
            System.out.println("200 iterations finished, not enough!");
 
533
          tmp = opt.findArgmin(tmp, b);
 
534
        }
 
535
        nll = opt.getMinFunction();
 
536
 
 
537
        if(nll < bestnll){
 
538
          bestnll = nll;
 
539
          m_Par = tmp;
 
540
          if (m_Debug)
 
541
            System.out.println("!!!!!!!!!!!!!!!!Smaller NLL found: "+nll);
 
542
        }
 
543
        if (m_Debug)
 
544
          System.out.println(exIdx+":  -------------<Converged>--------------");
 
545
      }
 
546
    }
 
547
    }           
 
548
 
 
549
  /**
 
550
   * Computes the distribution for a given exemplar
 
551
   *
 
552
   * @param exmp the exemplar for which distribution is computed
 
553
   * @return the distribution
 
554
   * @throws Exception if the distribution can't be computed successfully
 
555
   */
 
556
  public double[] distributionForInstance(Instance exmp) 
 
557
    throws Exception {
 
558
 
 
559
    // Extract the data
 
560
    Instances ins = exmp.relationalValue(1);
 
561
    if(m_Filter!=null)
 
562
      ins = Filter.useFilter(ins, m_Filter);
 
563
 
 
564
    ins = Filter.useFilter(ins, m_Missing);
 
565
 
 
566
    int nI = ins.numInstances(), nA = ins.numAttributes();
 
567
    double[][] dat = new double [nI][nA];
 
568
    for(int j=0; j<nI; j++){
 
569
      for(int k=0; k<nA; k++){ 
 
570
        dat[j][k] = ins.instance(j).value(k);
 
571
      }
 
572
    }
 
573
 
 
574
    // Compute the probability of the bag
 
575
    double [] distribution = new double[2];
 
576
    distribution[1]=0.0;  // Prob. for class 1
 
577
 
 
578
    for(int i=0; i<nI; i++){
 
579
      double exp = 0.0;
 
580
      for(int r=0; r<nA; r++)
 
581
        exp += (m_Par[r*2]-dat[i][r])*(m_Par[r*2]-dat[i][r])/
 
582
          ((m_Par[r*2+1])*(m_Par[r*2+1]));
 
583
      exp = Math.exp(-exp);
 
584
 
 
585
      // Prob. updated for one instance
 
586
      distribution[1] += exp/(double)nI;
 
587
      distribution[0] += (1.0-exp)/(double)nI;
 
588
    }
 
589
 
 
590
    return distribution;
 
591
  }
 
592
 
 
593
  /**
 
594
   * Gets a string describing the classifier.
 
595
   *
 
596
   * @return a string describing the classifer built.
 
597
   */
 
598
  public String toString() {
 
599
 
 
600
    String result = "Modified Logistic Regression";
 
601
    if (m_Par == null) {
 
602
      return result + ": No model built yet.";
 
603
    }
 
604
 
 
605
    result += "\nCoefficients...\n"
 
606
      + "Variable      Coeff.\n";
 
607
    for (int j = 0, idx=0; j < m_Par.length/2; j++, idx++) {
 
608
 
 
609
      result += m_Attributes.attribute(idx).name();
 
610
      result += " "+Utils.doubleToString(m_Par[j*2], 12, 4); 
 
611
      result += " "+Utils.doubleToString(m_Par[j*2+1], 12, 4)+"\n";
 
612
    }
 
613
 
 
614
    return result;
 
615
  }
 
616
 
 
617
  /**
 
618
   * Main method for testing this class.
 
619
   *
 
620
   * @param argv should contain the command line arguments to the
 
621
   * scheme (see Evaluation)
 
622
   */
 
623
  public static void main(String[] argv) {
 
624
    runClassifier(new MDD(), argv);
 
625
  }
 
626
}