ROOT  6.06/09
Reference Guide
MethodFisher.cxx
Go to the documentation of this file.
1 // @(#)root/tmva $Id$
2 // Author: Andreas Hoecker, Xavier Prudent, Joerg Stelzer, Helge Voss, Kai Voss
3 
4 /**********************************************************************************
5  * Project: TMVA - a Root-integrated toolkit for multivariate Data analysis *
6  * Package: TMVA *
7  * Class : MethodFisher *
8  * Web : http://tmva.sourceforge.net *
9  * *
10  * Description: *
11  * Implementation (see header for description) *
12  * *
13  * Original author of this Fisher-Discriminant implementation: *
14  * Andre Gaidot, CEA-France; *
15  * (Translation from FORTRAN) *
16  * *
17  * Authors (alphabetical): *
18  * Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland *
19  * Xavier Prudent <prudent@lapp.in2p3.fr> - LAPP, France *
20  * Helge Voss <Helge.Voss@cern.ch> - MPI-K Heidelberg, Germany *
21  * Kai Voss <Kai.Voss@cern.ch> - U. of Victoria, Canada *
22  * *
23  * Copyright (c) 2005: *
24  * CERN, Switzerland *
25  * U. of Victoria, Canada *
26  * MPI-K Heidelberg, Germany *
27  * LAPP, Annecy, France *
28  * *
29  * Redistribution and use in source and binary forms, with or without *
30  * modification, are permitted according to the terms listed in LICENSE *
31  * (http://tmva.sourceforge.net/LICENSE) *
32  **********************************************************************************/
33 
34 ////////////////////////////////////////////////////////////////////////////////
35 
36 /* Begin_Html
37  Fisher and Mahalanobis Discriminants (Linear Discriminant Analysis)
38 
39  <p>
40  In the method of Fisher discriminants event selection is performed
41  in a transformed variable space with zero linear correlations, by
42  distinguishing the mean values of the signal and background
43  distributions.<br></p>
44 
45  <p>
46  The linear discriminant analysis determines an axis in the (correlated)
47  hyperspace of the input variables
48  such that, when projecting the output classes (signal and background)
49  upon this axis, they are pushed as far as possible away from each other,
50  while events of a same class are confined in a close vicinity.
51  The linearity property of this method is reflected in the metric with
52  which "far apart" and "close vicinity" are determined: the covariance
53  matrix of the discriminant variable space.
54  </p>
55 
56  <p>
57  The classification of the events in signal and background classes
58  relies on the following characteristics (only): overall sample means,
59  <i><my:o>x</my:o><sub>i</sub></i>, for each input variable, <i>i</i>,
60  class-specific sample means, <i><my:o>x</my:o><sub>S(B),i</sub></i>,
61  and total covariance matrix <i>T<sub>ij</sub></i>. The covariance matrix
62  can be decomposed into the sum of a <i>within-</i> (<i>W<sub>ij</sub></i>)
63  and a <i>between-class</i> (<i>B<sub>ij</sub></i>) class matrix. They describe
64  the dispersion of events relative to the means of their own class (within-class
65  matrix), and relative to the overall sample means (between-class matrix).
66  The Fisher coefficients, <i>F<sub>i</sub></i>, are then given by <br>
67  <center>
68  <img vspace=6 src="gif/tmva_fisherC.gif" align="bottom" >
69  </center>
70  where in TMVA is set <i>N<sub>S</sub>=N<sub>B</sub></i>, so that the factor
71  in front of the sum simplifies to &frac12;.
72  The Fisher discriminant then reads<br>
73  <center>
74  <img vspace=6 src="gif/tmva_fisherD.gif" align="bottom" >
75  </center>
76  The offset <i>F</i><sub>0</sub> centers the sample mean of <i>x</i><sub>Fi</sub>
77  at zero. Instead of using the within-class matrix, the Mahalanobis variant
78  determines the Fisher coefficients as follows:<br>
79  <center>
80  <img vspace=6 src="gif/tmva_mahaC.gif" align="bottom" >
81  </center>
82  with resulting <i>x</i><sub>Ma</sub> that are very similar to the
83  <i>x</i><sub>Fi</sub>. <br></p>
84 
85  TMVA provides two outputs for the ranking of the input variables:<br><p></p>
86  <ul>
87  <li> <u>Fisher test:</u> the Fisher analysis aims at simultaneously maximising
88  the between-class separation, while minimising the within-class dispersion.
89  A useful measure of the discrimination power of a variable is hence given
90  by the diagonal quantity: <i>B<sub>ii</sub>/W<sub>ii</sub></i>.
91  </li>
92 
93  <li> <u>Discrimination power:</u> the value of the Fisher coefficient is a
94  measure of the discriminating power of a variable. The discrimination power
95  of set of input variables can therefore be measured by the scalar
96  <center>
97  <img vspace=6 src="gif/tmva_discpower.gif" align="bottom" >
98  </center>
99  </li>
100  </ul>
101  The corresponding numbers are printed on standard output.
102  End_Html */
103 //_______________________________________________________________________
104 
105 #include <iomanip>
106 #include <cassert>
107 
108 #include "TMath.h"
109 #include "Riostream.h"
110 
112 #include "TMVA/MethodFisher.h"
113 #include "TMVA/Tools.h"
114 #include "TMatrix.h"
115 #include "TMVA/Ranking.h"
116 #include "TMVA/Types.h"
117 #include "TMVA/ClassifierFactory.h"
118 
119 REGISTER_METHOD(Fisher)
120 
121 ClassImp(TMVA::MethodFisher);
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 /// standard constructor for the "Fisher"
125 
126 TMVA::MethodFisher::MethodFisher( const TString& jobName,
127  const TString& methodTitle,
128  DataSetInfo& dsi,
129  const TString& theOption,
130  TDirectory* theTargetDir ) :
131  MethodBase( jobName, Types::kFisher, methodTitle, dsi, theOption, theTargetDir ),
132  fMeanMatx ( 0 ),
133  fTheMethod ( "Fisher" ),
134  fFisherMethod ( kFisher ),
135  fBetw ( 0 ),
136  fWith ( 0 ),
137  fCov ( 0 ),
138  fSumOfWeightsS( 0 ),
139  fSumOfWeightsB( 0 ),
140  fDiscrimPow ( 0 ),
141  fFisherCoeff ( 0 ),
142  fF0 ( 0 )
143 {
144 }
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// constructor from weight file
148 
150  const TString& theWeightFile,
151  TDirectory* theTargetDir ) :
152  MethodBase( Types::kFisher, dsi, theWeightFile, theTargetDir ),
153  fMeanMatx ( 0 ),
154  fTheMethod ( "Fisher" ),
155  fFisherMethod ( kFisher ),
156  fBetw ( 0 ),
157  fWith ( 0 ),
158  fCov ( 0 ),
159  fSumOfWeightsS( 0 ),
160  fSumOfWeightsB( 0 ),
161  fDiscrimPow ( 0 ),
162  fFisherCoeff ( 0 ),
163  fF0 ( 0 )
164 {
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// default initialization called by all constructors
169 
171 {
172  // allocate Fisher coefficients
173  fFisherCoeff = new std::vector<Double_t>( GetNvar() );
174 
175  // the minimum requirement to declare an event signal-like
176  SetSignalReferenceCut( 0.0 );
177 
178  // this is the preparation for training
179  InitMatrices();
180 }
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 ///
184 /// MethodFisher options:
185 /// format and syntax of option string: "type"
186 /// where type is "Fisher" or "Mahalanobis"
187 ///
188 
190 {
191  DeclareOptionRef( fTheMethod = "Fisher", "Method", "Discrimination method" );
192  AddPreDefVal(TString("Fisher"));
193  AddPreDefVal(TString("Mahalanobis"));
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// process user options
198 
200 {
201  if (fTheMethod == "Fisher" ) fFisherMethod = kFisher;
202  else fFisherMethod = kMahalanobis;
203 
204  // this is the preparation for training
205  InitMatrices();
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// destructor
210 
212 {
213  if (fBetw ) { delete fBetw; fBetw = 0; }
214  if (fWith ) { delete fWith; fWith = 0; }
215  if (fCov ) { delete fCov; fCov = 0; }
216  if (fDiscrimPow ) { delete fDiscrimPow; fDiscrimPow = 0; }
217  if (fFisherCoeff) { delete fFisherCoeff; fFisherCoeff = 0; }
218 }
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 /// Fisher can only handle classification with 2 classes
222 
224 {
225  if (type == Types::kClassification && numberClasses == 2) return kTRUE;
226  return kFALSE;
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 /// computation of Fisher coefficients by series of matrix operations
231 
233 {
234  // get mean value of each variables for signal, backgd and signal+backgd
235  GetMean();
236 
237  // get the matrix of covariance 'within class'
238  GetCov_WithinClass();
239 
240  // get the matrix of covariance 'between class'
241  GetCov_BetweenClass();
242 
243  // get the matrix of covariance 'between class'
244  GetCov_Full();
245 
246  //--------------------------------------------------------------
247 
248  // get the Fisher coefficients
249  GetFisherCoeff();
250 
251  // get the discriminating power of each variables
252  GetDiscrimPower();
253 
254  // nice output
255  PrintCoefficients();
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 /// returns the Fisher value (no fixed range)
260 
262 {
263  const Event * ev = GetEvent();
264  Double_t result = fF0;
265  for (UInt_t ivar=0; ivar<GetNvar(); ivar++)
266  result += (*fFisherCoeff)[ivar]*ev->GetValue(ivar);
267 
268  // cannot determine error
269  NoErrorCalc(err, errUpper);
270 
271  return result;
272 
273 }
274 
275 ////////////////////////////////////////////////////////////////////////////////
276 /// initializaton method; creates global matrices and vectors
277 
279 {
280  // average value of each variables for S, B, S+B
281  fMeanMatx = new TMatrixD( GetNvar(), 3 );
282 
283  // the covariance 'within class' and 'between class' matrices
284  fBetw = new TMatrixD( GetNvar(), GetNvar() );
285  fWith = new TMatrixD( GetNvar(), GetNvar() );
286  fCov = new TMatrixD( GetNvar(), GetNvar() );
287 
288  // discriminating power
289  fDiscrimPow = new std::vector<Double_t>( GetNvar() );
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 /// compute mean values of variables in each sample, and the overall means
294 
296 {
297  // initialize internal sum-of-weights variables
298  fSumOfWeightsS = 0;
299  fSumOfWeightsB = 0;
300 
301  const UInt_t nvar = DataInfo().GetNVariables();
302 
303  // init vectors
304  Double_t* sumS = new Double_t[nvar];
305  Double_t* sumB = new Double_t[nvar];
306  for (UInt_t ivar=0; ivar<nvar; ivar++) { sumS[ivar] = sumB[ivar] = 0; }
307 
308  // compute sample means
309  for (Int_t ievt=0; ievt<Data()->GetNEvents(); ievt++) {
310 
311  // read the Training Event into "event"
312  const Event * ev = GetEvent(ievt);
313 
314  // sum of weights
315  Double_t weight = ev->GetWeight();
316  if (DataInfo().IsSignal(ev)) fSumOfWeightsS += weight;
317  else fSumOfWeightsB += weight;
318 
319  Double_t* sum = DataInfo().IsSignal(ev) ? sumS : sumB;
320 
321  for (UInt_t ivar=0; ivar<nvar; ivar++) sum[ivar] += ev->GetValue( ivar )*weight;
322  }
323 
324  for (UInt_t ivar=0; ivar<nvar; ivar++) {
325  (*fMeanMatx)( ivar, 2 ) = sumS[ivar];
326  (*fMeanMatx)( ivar, 0 ) = sumS[ivar]/fSumOfWeightsS;
327 
328  (*fMeanMatx)( ivar, 2 ) += sumB[ivar];
329  (*fMeanMatx)( ivar, 1 ) = sumB[ivar]/fSumOfWeightsB;
330 
331  // signal + background
332  (*fMeanMatx)( ivar, 2 ) /= (fSumOfWeightsS + fSumOfWeightsB);
333  }
334 
335  // fMeanMatx->Print();
336  delete [] sumS;
337  delete [] sumB;
338 }
339 
340 ////////////////////////////////////////////////////////////////////////////////
341 /// the matrix of covariance 'within class' reflects the dispersion of the
342 /// events relative to the center of gravity of their own class
343 
345 {
346  // assert required
347  assert( fSumOfWeightsS > 0 && fSumOfWeightsB > 0 );
348 
349  // product matrices (x-<x>)(y-<y>) where x;y are variables
350 
351  // init
352  const Int_t nvar = GetNvar();
353  const Int_t nvar2 = nvar*nvar;
354  Double_t *sumSig = new Double_t[nvar2];
355  Double_t *sumBgd = new Double_t[nvar2];
356  Double_t *xval = new Double_t[nvar];
357  memset(sumSig,0,nvar2*sizeof(Double_t));
358  memset(sumBgd,0,nvar2*sizeof(Double_t));
359 
360  // 'within class' covariance
361  for (Int_t ievt=0; ievt<Data()->GetNEvents(); ievt++) {
362 
363  // read the Training Event into "event"
364  const Event* ev = GetEvent(ievt);
365 
366  Double_t weight = ev->GetWeight(); // may ignore events with negative weights
367 
368  for (Int_t x=0; x<nvar; x++) xval[x] = ev->GetValue( x );
369  Int_t k=0;
370  for (Int_t x=0; x<nvar; x++) {
371  for (Int_t y=0; y<nvar; y++) {
372  if (DataInfo().IsSignal(ev)) {
373  Double_t v = ( (xval[x] - (*fMeanMatx)(x, 0))*(xval[y] - (*fMeanMatx)(y, 0)) )*weight;
374  sumSig[k] += v;
375  }else{
376  Double_t v = ( (xval[x] - (*fMeanMatx)(x, 1))*(xval[y] - (*fMeanMatx)(y, 1)) )*weight;
377  sumBgd[k] += v;
378  }
379  k++;
380  }
381  }
382  }
383  Int_t k=0;
384  for (Int_t x=0; x<nvar; x++) {
385  for (Int_t y=0; y<nvar; y++) {
386  //(*fWith)(x, y) = (sumSig[k] + sumBgd[k])/(fSumOfWeightsS + fSumOfWeightsB);
387  // HHV: I am still convinced that THIS is how it should be (below) However, while
388  // the old version corresponded so nicely with LD, the FIXED version does not, unless
389  // we agree to change LD. For LD, it is not "defined" to my knowledge how the weights
390  // are weighted, while it is clear how the "Within" matrix for Fisher should be calcuated
391  // (i.e. as seen below). In order to agree with the Fisher classifier, one would have to
392  // weigh signal and background such that they correspond to the same number of effective
393  // (weithed) events.
394  // THAT is NOT done currently, but just "event weights" are used.
395  (*fWith)(x, y) = sumSig[k]/fSumOfWeightsS + sumBgd[k]/fSumOfWeightsB;
396  k++;
397  }
398  }
399 
400  delete [] sumSig;
401  delete [] sumBgd;
402  delete [] xval;
403 }
404 
405 ////////////////////////////////////////////////////////////////////////////////
406 /// the matrix of covariance 'between class' reflects the dispersion of the
407 /// events of a class relative to the global center of gravity of all the class
408 /// hence the separation between classes
409 
411 {
412  // assert required
413  assert( fSumOfWeightsS > 0 && fSumOfWeightsB > 0);
414 
415  Double_t prodSig, prodBgd;
416 
417  for (UInt_t x=0; x<GetNvar(); x++) {
418  for (UInt_t y=0; y<GetNvar(); y++) {
419 
420  prodSig = ( ((*fMeanMatx)(x, 0) - (*fMeanMatx)(x, 2))*
421  ((*fMeanMatx)(y, 0) - (*fMeanMatx)(y, 2)) );
422  prodBgd = ( ((*fMeanMatx)(x, 1) - (*fMeanMatx)(x, 2))*
423  ((*fMeanMatx)(y, 1) - (*fMeanMatx)(y, 2)) );
424 
425  (*fBetw)(x, y) = (fSumOfWeightsS*prodSig + fSumOfWeightsB*prodBgd) / (fSumOfWeightsS + fSumOfWeightsB);
426  }
427  }
428 }
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 /// compute full covariance matrix from sum of within and between matrices
432 
434 {
435  for (UInt_t x=0; x<GetNvar(); x++)
436  for (UInt_t y=0; y<GetNvar(); y++)
437  (*fCov)(x, y) = (*fWith)(x, y) + (*fBetw)(x, y);
438 }
439 
440 ////////////////////////////////////////////////////////////////////////////////
441 /// Fisher = Sum { [coeff]*[variables] }
442 ///
443 /// let Xs be the array of the mean values of variables for signal evts
444 /// let Xb be the array of the mean values of variables for backgd evts
445 /// let InvWith be the inverse matrix of the 'within class' correlation matrix
446 ///
447 /// then the array of Fisher coefficients is
448 /// [coeff] =sqrt(fNsig*fNbgd)/fNevt*transpose{Xs-Xb}*InvWith
449 
451 {
452  // assert required
453  assert( fSumOfWeightsS > 0 && fSumOfWeightsB > 0);
454 
455  // invert covariance matrix
456  TMatrixD* theMat = 0;
457  switch (GetFisherMethod()) {
458  case kFisher:
459  theMat = fWith;
460  break;
461  case kMahalanobis:
462  theMat = fCov;
463  break;
464  default:
465  Log() << kFATAL << "<GetFisherCoeff> undefined method" << GetFisherMethod() << Endl;
466  }
467 
468  TMatrixD invCov( *theMat );
469 
470  if ( TMath::Abs(invCov.Determinant()) < 10E-24 ) {
471  Log() << kWARNING << "<GetFisherCoeff> matrix is almost singular with deterninant="
472  << TMath::Abs(invCov.Determinant())
473  << " did you use the variables that are linear combinations or highly correlated?"
474  << Endl;
475  }
476  if ( TMath::Abs(invCov.Determinant()) < 10E-120 ) {
477  theMat->Print();
478  Log() << kFATAL << "<GetFisherCoeff> matrix is singular with determinant="
479  << TMath::Abs(invCov.Determinant())
480  << " did you use the variables that are linear combinations? \n"
481  << " do you any clue as to what went wrong in above printout of the covariance matrix? "
482  << Endl;
483  }
484 
485  invCov.Invert();
486 
487  // apply rescaling factor
488  Double_t xfact = TMath::Sqrt( fSumOfWeightsS*fSumOfWeightsB ) / (fSumOfWeightsS + fSumOfWeightsB);
489 
490  // compute difference of mean values
491  std::vector<Double_t> diffMeans( GetNvar() );
492  UInt_t ivar, jvar;
493  for (ivar=0; ivar<GetNvar(); ivar++) {
494  (*fFisherCoeff)[ivar] = 0;
495 
496  for (jvar=0; jvar<GetNvar(); jvar++) {
497  Double_t d = (*fMeanMatx)(jvar, 0) - (*fMeanMatx)(jvar, 1);
498  (*fFisherCoeff)[ivar] += invCov(ivar, jvar)*d;
499  }
500  // rescale
501  (*fFisherCoeff)[ivar] *= xfact;
502  }
503 
504 
505  // offset correction
506  fF0 = 0.0;
507  for (ivar=0; ivar<GetNvar(); ivar++){
508  fF0 += (*fFisherCoeff)[ivar]*((*fMeanMatx)(ivar, 0) + (*fMeanMatx)(ivar, 1));
509  }
510  fF0 /= -2.0;
511 }
512 
513 ////////////////////////////////////////////////////////////////////////////////
514 /// computation of discrimination power indicator for each variable
515 /// small values of "fWith" indicates little compactness of sig & of backgd
516 /// big values of "fBetw" indicates large separation between sig & backgd
517 ///
518 /// we want signal & backgd classes as compact and separated as possible
519 /// the discriminating power is then defined as the ration "fBetw/fWith"
520 
522 {
523  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
524  if ((*fCov)(ivar, ivar) != 0)
525  (*fDiscrimPow)[ivar] = (*fBetw)(ivar, ivar)/(*fCov)(ivar, ivar);
526  else
527  (*fDiscrimPow)[ivar] = 0;
528  }
529 }
530 
531 ////////////////////////////////////////////////////////////////////////////////
532 /// computes ranking of input variables
533 
535 {
536  // create the ranking object
537  fRanking = new Ranking( GetName(), "Discr. power" );
538 
539  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
540  fRanking->AddRank( Rank( GetInputLabel(ivar), (*fDiscrimPow)[ivar] ) );
541  }
542 
543  return fRanking;
544 }
545 
546 ////////////////////////////////////////////////////////////////////////////////
547 /// display Fisher coefficients and discriminating power for each variable
548 /// check maximum length of variable name
549 
551 {
552  Log() << kINFO << "Results for Fisher coefficients:" << Endl;
553 
554  if (GetTransformationHandler().GetTransformationList().GetSize() != 0) {
555  Log() << kINFO << "NOTE: The coefficients must be applied to TRANFORMED variables" << Endl;
556  Log() << kINFO << " List of the transformation: " << Endl;
557  TListIter trIt(&GetTransformationHandler().GetTransformationList());
558  while (VariableTransformBase *trf = (VariableTransformBase*) trIt()) {
559  Log() << kINFO << " -- " << trf->GetName() << Endl;
560  }
561  }
562  std::vector<TString> vars;
563  std::vector<Double_t> coeffs;
564  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
565  vars .push_back( GetInputLabel(ivar) );
566  coeffs.push_back( (*fFisherCoeff)[ivar] );
567  }
568  vars .push_back( "(offset)" );
569  coeffs.push_back( fF0 );
570  TMVA::gTools().FormattedOutput( coeffs, vars, "Variable" , "Coefficient", Log() );
571 
572  // for (int i=0; i<coeffs.size(); i++)
573  // std::cout << "fisher coeff["<<i<<"]="<<coeffs[i]<<std::endl;
574 
575  if (IsNormalised()) {
576  Log() << kINFO << "NOTE: You have chosen to use the \"Normalise\" booking option. Hence, the" << Endl;
577  Log() << kINFO << " coefficients must be applied to NORMALISED (') variables as follows:" << Endl;
578  Int_t maxL = 0;
579  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) if (GetInputLabel(ivar).Length() > maxL) maxL = GetInputLabel(ivar).Length();
580 
581  // Print normalisation expression (see Tools.cxx): "2*(x - xmin)/(xmax - xmin) - 1.0"
582  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
583  Log() << kINFO
584  << std::setw(maxL+9) << TString("[") + GetInputLabel(ivar) + "]' = 2*("
585  << std::setw(maxL+2) << TString("[") + GetInputLabel(ivar) + "]"
586  << std::setw(3) << (GetXmin(ivar) > 0 ? " - " : " + ")
587  << std::setw(6) << TMath::Abs(GetXmin(ivar)) << std::setw(3) << ")/"
588  << std::setw(6) << (GetXmax(ivar) - GetXmin(ivar) )
589  << std::setw(3) << " - 1"
590  << Endl;
591  }
592  Log() << kINFO << "The TMVA Reader will properly account for this normalisation, but if the" << Endl;
593  Log() << kINFO << "Fisher classifier is applied outside the Reader, the transformation must be" << Endl;
594  Log() << kINFO << "implemented -- or the \"Normalise\" option is removed and Fisher retrained." << Endl;
595  Log() << kINFO << Endl;
596  }
597 }
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// read Fisher coefficients from weight file
601 
603 {
604  istr >> fF0;
605  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) istr >> (*fFisherCoeff)[ivar];
606 }
607 
608 ////////////////////////////////////////////////////////////////////////////////
609 /// create XML description of Fisher classifier
610 
611 void TMVA::MethodFisher::AddWeightsXMLTo( void* parent ) const
612 {
613  void* wght = gTools().AddChild(parent, "Weights");
614  gTools().AddAttr( wght, "NCoeff", GetNvar()+1 );
615  void* coeffxml = gTools().AddChild(wght, "Coefficient");
616  gTools().AddAttr( coeffxml, "Index", 0 );
617  gTools().AddAttr( coeffxml, "Value", fF0 );
618  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
619  coeffxml = gTools().AddChild( wght, "Coefficient" );
620  gTools().AddAttr( coeffxml, "Index", ivar+1 );
621  gTools().AddAttr( coeffxml, "Value", (*fFisherCoeff)[ivar] );
622  }
623 }
624 
625 ////////////////////////////////////////////////////////////////////////////////
626 /// read Fisher coefficients from xml weight file
627 
629 {
630  UInt_t ncoeff, coeffidx;
631  gTools().ReadAttr( wghtnode, "NCoeff", ncoeff );
632  fFisherCoeff->resize(ncoeff-1);
633 
634  void* ch = gTools().GetChild(wghtnode);
635  Double_t coeff;
636  while (ch) {
637  gTools().ReadAttr( ch, "Index", coeffidx );
638  gTools().ReadAttr( ch, "Value", coeff );
639  if (coeffidx==0) fF0 = coeff;
640  else (*fFisherCoeff)[coeffidx-1] = coeff;
641  ch = gTools().GetNextChild(ch);
642  }
643 }
644 
645 ////////////////////////////////////////////////////////////////////////////////
646 /// write Fisher-specific classifier response
647 
648 void TMVA::MethodFisher::MakeClassSpecific( std::ostream& fout, const TString& className ) const
649 {
650  Int_t dp = fout.precision();
651  fout << " double fFisher0;" << std::endl;
652  fout << " std::vector<double> fFisherCoefficients;" << std::endl;
653  fout << "};" << std::endl;
654  fout << "" << std::endl;
655  fout << "inline void " << className << "::Initialize() " << std::endl;
656  fout << "{" << std::endl;
657  fout << " fFisher0 = " << std::setprecision(12) << fF0 << ";" << std::endl;
658  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
659  fout << " fFisherCoefficients.push_back( " << std::setprecision(12) << (*fFisherCoeff)[ivar] << " );" << std::endl;
660  }
661  fout << std::endl;
662  fout << " // sanity check" << std::endl;
663  fout << " if (fFisherCoefficients.size() != fNvars) {" << std::endl;
664  fout << " std::cout << \"Problem in class \\\"\" << fClassName << \"\\\"::Initialize: mismatch in number of input values\"" << std::endl;
665  fout << " << fFisherCoefficients.size() << \" != \" << fNvars << std::endl;" << std::endl;
666  fout << " fStatusIsClean = false;" << std::endl;
667  fout << " } " << std::endl;
668  fout << "}" << std::endl;
669  fout << std::endl;
670  fout << "inline double " << className << "::GetMvaValue__( const std::vector<double>& inputValues ) const" << std::endl;
671  fout << "{" << std::endl;
672  fout << " double retval = fFisher0;" << std::endl;
673  fout << " for (size_t ivar = 0; ivar < fNvars; ivar++) {" << std::endl;
674  fout << " retval += fFisherCoefficients[ivar]*inputValues[ivar];" << std::endl;
675  fout << " }" << std::endl;
676  fout << std::endl;
677  fout << " return retval;" << std::endl;
678  fout << "}" << std::endl;
679  fout << std::endl;
680  fout << "// Clean up" << std::endl;
681  fout << "inline void " << className << "::Clear() " << std::endl;
682  fout << "{" << std::endl;
683  fout << " // clear coefficients" << std::endl;
684  fout << " fFisherCoefficients.clear(); " << std::endl;
685  fout << "}" << std::endl;
686  fout << std::setprecision(dp);
687 }
688 
689 ////////////////////////////////////////////////////////////////////////////////
690 /// get help message text
691 ///
692 /// typical length of text line:
693 /// "|--------------------------------------------------------------|"
694 
696 {
697  Log() << Endl;
698  Log() << gTools().Color("bold") << "--- Short description:" << gTools().Color("reset") << Endl;
699  Log() << Endl;
700  Log() << "Fisher discriminants select events by distinguishing the mean " << Endl;
701  Log() << "values of the signal and background distributions in a trans- " << Endl;
702  Log() << "formed variable space where linear correlations are removed." << Endl;
703  Log() << Endl;
704  Log() << " (More precisely: the \"linear discriminator\" determines" << Endl;
705  Log() << " an axis in the (correlated) hyperspace of the input " << Endl;
706  Log() << " variables such that, when projecting the output classes " << Endl;
707  Log() << " (signal and background) upon this axis, they are pushed " << Endl;
708  Log() << " as far as possible away from each other, while events" << Endl;
709  Log() << " of a same class are confined in a close vicinity. The " << Endl;
710  Log() << " linearity property of this classifier is reflected in the " << Endl;
711  Log() << " metric with which \"far apart\" and \"close vicinity\" are " << Endl;
712  Log() << " determined: the covariance matrix of the discriminating" << Endl;
713  Log() << " variable space.)" << Endl;
714  Log() << Endl;
715  Log() << gTools().Color("bold") << "--- Performance optimisation:" << gTools().Color("reset") << Endl;
716  Log() << Endl;
717  Log() << "Optimal performance for Fisher discriminants is obtained for " << Endl;
718  Log() << "linearly correlated Gaussian-distributed variables. Any deviation" << Endl;
719  Log() << "from this ideal reduces the achievable separation power. In " << Endl;
720  Log() << "particular, no discrimination at all is achieved for a variable" << Endl;
721  Log() << "that has the same sample mean for signal and background, even if " << Endl;
722  Log() << "the shapes of the distributions are very different. Thus, Fisher " << Endl;
723  Log() << "discriminants often benefit from suitable transformations of the " << Endl;
724  Log() << "input variables. For example, if a variable x in [-1,1] has a " << Endl;
725  Log() << "a parabolic signal distributions, and a uniform background" << Endl;
726  Log() << "distributions, their mean value is zero in both cases, leading " << Endl;
727  Log() << "to no separation. The simple transformation x -> |x| renders this " << Endl;
728  Log() << "variable powerful for the use in a Fisher discriminant." << Endl;
729  Log() << Endl;
730  Log() << gTools().Color("bold") << "--- Performance tuning via configuration options:" << gTools().Color("reset") << Endl;
731  Log() << Endl;
732  Log() << "<None>" << Endl;
733 }
void GetCov_BetweenClass(void)
the matrix of covariance 'between class' reflects the dispersion of the events of a class relative to...
const Ranking * CreateRanking()
computes ranking of input variables
void MakeClassSpecific(std::ostream &, const TString &) const
write Fisher-specific classifier response
MsgLogger & Endl(MsgLogger &ml)
Definition: MsgLogger.h:162
void ReadWeightsFromStream(std::istream &i)
read Fisher coefficients from weight file
virtual ~MethodFisher(void)
destructor
void AddWeightsXMLTo(void *parent) const
create XML description of Fisher classifier
void GetCov_Full(void)
compute full covariance matrix from sum of within and between matrices
void GetDiscrimPower(void)
computation of discrimination power indicator for each variable small values of "fWith" indicates lit...
virtual Bool_t HasAnalysisType(Types::EAnalysisType type, UInt_t numberClasses, UInt_t numberTargets)
Fisher can only handle classification with 2 classes.
#define assert(cond)
Definition: unittest.h:542
MethodFisher(const TString &jobName, const TString &methodTitle, DataSetInfo &dsi, const TString &theOption="Fisher", TDirectory *theTargetDir=0)
standard constructor for the "Fisher"
EAnalysisType
Definition: Types.h:124
Basic string class.
Definition: TString.h:137
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
Double_t GetWeight() const
return the event weight - depending on whether the flag IgnoreNegWeightsInTraining is or not...
Definition: Event.cxx:376
void AddAttr(void *node, const char *, const T &value, Int_t precision=16)
Definition: Tools.h:308
void * AddChild(void *parent, const char *childname, const char *content=0, bool isRootNode=false)
add child node
Definition: Tools.cxx:1134
Short_t Abs(Short_t d)
Definition: TMathBase.h:110
Iterator of linked list.
Definition: TList.h:187
Float_t GetValue(UInt_t ivar) const
return value of i'th variable
Definition: Event.cxx:231
Tools & gTools()
Definition: Tools.cxx:79
Double_t x[n]
Definition: legend1.C:17
void * GetChild(void *parent, const char *childname=0)
get child node
Definition: Tools.cxx:1158
std::vector< std::vector< double > > Data
TMatrixT< Element > & Invert(Double_t *det=0)
Invert the matrix and calculate its determinant.
Definition: TMatrixT.cxx:1387
TMatrixT< Double_t > TMatrixD
Definition: TMatrixDfwd.h:24
void Print(Option_t *name="") const
Print the matrix as a table of elements.
Double_t GetMvaValue(Double_t *err=0, Double_t *errUpper=0)
returns the Fisher value (no fixed range)
void Train(void)
computation of Fisher coefficients by series of matrix operations
void ReadWeightsFromXML(void *wghtnode)
read Fisher coefficients from xml weight file
void ProcessOptions()
process user options
SVector< double, 2 > v
Definition: Dict.h:5
unsigned int UInt_t
Definition: RtypesCore.h:42
ClassImp(TMVA::MethodFisher)
Double_t E()
Definition: TMath.h:54
void InitMatrices(void)
initializaton method; creates global matrices and vectors
void ReadAttr(void *node, const char *, T &value)
Definition: Tools.h:295
void GetHelpMessage() const
get help message text
void DeclareOptions()
MethodFisher options: format and syntax of option string: "type" where type is "Fisher" or "Mahalanob...
double Double_t
Definition: RtypesCore.h:55
void GetMean(void)
compute mean values of variables in each sample, and the overall means
void GetCov_WithinClass(void)
the matrix of covariance 'within class' reflects the dispersion of the events relative to the center ...
Describe directory structure in memory.
Definition: TDirectory.h:41
int type
Definition: TGX11.cxx:120
void * GetNextChild(void *prevchild, const char *childname=0)
XML helpers.
Definition: Tools.cxx:1170
Double_t y[n]
Definition: legend1.C:17
void FormattedOutput(const std::vector< Double_t > &, const std::vector< TString > &, const TString titleVars, const TString titleValues, MsgLogger &logger, TString format="%+1.3f")
formatted output of simple table
Definition: Tools.cxx:896
const TString & Color(const TString &)
human readable color strings
Definition: Tools.cxx:837
#define REGISTER_METHOD(CLASS)
for example
Abstract ClassifierFactory template that handles arbitrary types.
virtual Double_t Determinant() const
Return the matrix determinant.
Definition: TMatrixT.cxx:1352
void PrintCoefficients(void)
display Fisher coefficients and discriminating power for each variable check maximum length of variab...
double result[121]
Double_t Sqrt(Double_t x)
Definition: TMath.h:464
void GetFisherCoeff(void)
Fisher = Sum { [coeff]*[variables] }.
const Bool_t kTRUE
Definition: Rtypes.h:91
Definition: math.cpp:60
void Init(void)
default initialization called by all constructors