Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
MethodBase.cxx
Go to the documentation of this file.
1// @(#)root/tmva $Id$
2// Author: Andreas Hoecker, Peter Speckmayer, Joerg Stelzer, Helge Voss, Kai Voss, Eckhard von Toerne, Jan Therhaag
3
4/**********************************************************************************
5 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis *
6 * Package: TMVA *
7 * Class : MethodBase *
8 * *
9 * *
10 * Description: *
11 * Implementation (see header for description) *
12 * *
13 * Authors (alphabetical): *
14 * Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland *
15 * Joerg Stelzer <Joerg.Stelzer@cern.ch> - CERN, Switzerland *
16 * Peter Speckmayer <Peter.Speckmayer@cern.ch> - CERN, Switzerland *
17 * Helge Voss <Helge.Voss@cern.ch> - MPI-K Heidelberg, Germany *
18 * Kai Voss <Kai.Voss@cern.ch> - U. of Victoria, Canada *
19 * Jan Therhaag <Jan.Therhaag@cern.ch> - U of Bonn, Germany *
20 * Eckhard v. Toerne <evt@uni-bonn.de> - U of Bonn, Germany *
21 * *
22 * Copyright (c) 2005-2011: *
23 * CERN, Switzerland *
24 * U. of Victoria, Canada *
25 * MPI-K Heidelberg, Germany *
26 * U. of Bonn, Germany *
27 * *
28 * Redistribution and use in source and binary forms, with or without *
29 * modification, are permitted according to the terms listed in LICENSE *
30 * (see tmva/doc/LICENSE) *
31 * *
32 **********************************************************************************/
33
34/*! \class TMVA::MethodBase
35\ingroup TMVA
36
37 Virtual base Class for all MVA method
38
39 MethodBase hosts several specific evaluation methods.
40
41 The kind of MVA that provides optimal performance in an analysis strongly
42 depends on the particular application. The evaluation factory provides a
43 number of numerical benchmark results to directly assess the performance
44 of the MVA training on the independent test sample. These are:
45
46 - The _signal efficiency_ at three representative background efficiencies
47 (which is 1 &minus; rejection).
48 - The _significance_ of an MVA estimator, defined by the difference
49 between the MVA mean values for signal and background, divided by the
50 quadratic sum of their root mean squares.
51 - The _separation_ of an MVA _x_, defined by the integral
52 \f[
53 \frac{1}{2} \int \frac{(S(x) - B(x))^2}{(S(x) + B(x))} dx
54 \f]
55 where
56 \f$ S(x) \f$ and \f$ B(x) \f$ are the signal and background distributions,
57 respectively. The separation is zero for identical signal and background MVA
58 shapes, and it is one for disjunctive shapes.
59 - The average, \f$ \int x \mu (S(x)) dx \f$, of the signal \f$ \mu_{transform} \f$.
60 The \f$ \mu_{transform} \f$ of an MVA denotes the transformation that yields
61 a uniform background distribution. In this way, the signal distributions
62 \f$ S(x) \f$ can be directly compared among the various MVAs. The stronger
63 \f$ S(x) \f$ peaks towards one, the better is the discrimination of the MVA.
64 The \f$ \mu_{transform} \f$ is
65 [documented here](http://tel.ccsd.cnrs.fr/documents/archives0/00/00/29/91/index_fr.html).
66
67 The MVA standard output also prints the linear correlation coefficients between
68 signal and background, which can be useful to eliminate variables that exhibit too
69 strong correlations.
70*/
71
72#include "TMVA/MethodBase.h"
73
74#include "TMVA/Config.h"
75#include "TMVA/Configurable.h"
76#include "TMVA/DataSetInfo.h"
77#include "TMVA/DataSet.h"
78#include "TMVA/Factory.h"
79#include "TMVA/IMethod.h"
80#include "TMVA/MsgLogger.h"
81#include "TMVA/PDF.h"
82#include "TMVA/Ranking.h"
83#include "TMVA/DataLoader.h"
84#include "TMVA/Tools.h"
85#include "TMVA/Results.h"
89#include "TMVA/RootFinder.h"
90#include "TMVA/Timer.h"
91#include "TMVA/TSpline1.h"
92#include "TMVA/Types.h"
96#include "TMVA/VariableInfo.h"
100#include "TMVA/Version.h"
101
102#include "TROOT.h"
103#include "TSystem.h"
104#include "TObjString.h"
105#include "TQObject.h"
106#include "TSpline.h"
107#include "TMatrix.h"
108#include "TMath.h"
109#include "TH1F.h"
110#include "TH2F.h"
111#include "TFile.h"
112#include "TGraph.h"
113#include "TXMLEngine.h"
114
115#include <iomanip>
116#include <iostream>
117#include <fstream>
118#include <sstream>
119#include <cstdlib>
120#include <algorithm>
121#include <limits>
122
123
124
125using std::endl;
126using std::atof;
127
128//const Int_t MethodBase_MaxIterations_ = 200;
130
131//const Int_t NBIN_HIST_PLOT = 100;
132const Int_t NBIN_HIST_HIGH = 10000;
133
134#ifdef _WIN32
135/* Disable warning C4355: 'this' : used in base member initializer list */
136#pragma warning ( disable : 4355 )
137#endif
138
139////////////////////////////////////////////////////////////////////////////////
140/// standard constructor
141
144 const TString& methodTitle,
146 const TString& theOption) :
147 IMethod(),
149 fTmpEvent ( 0 ),
150 fRanking ( 0 ),
151 fInputVars ( 0 ),
152 fAnalysisType ( Types::kNoAnalysisType ),
153 fRegressionReturnVal ( 0 ),
154 fMulticlassReturnVal ( 0 ),
155 fDataSetInfo ( dsi ),
156 fSignalReferenceCut ( 0.5 ),
157 fSignalReferenceCutOrientation( 1. ),
158 fVariableTransformType ( Types::kSignal ),
159 fJobName ( jobName ),
160 fMethodName ( methodTitle ),
161 fMethodType ( methodType ),
162 fTestvar ( "" ),
163 fTMVATrainingVersion ( TMVA_VERSION_CODE ),
164 fROOTTrainingVersion ( ROOT_VERSION_CODE ),
165 fConstructedFromWeightFile ( kFALSE ),
166 fBaseDir ( 0 ),
167 fMethodBaseDir ( 0 ),
168 fFile ( 0 ),
169 fSilentFile (kFALSE),
170 fModelPersistence (kTRUE),
171 fWeightFile ( "" ),
172 fEffS ( 0 ),
173 fDefaultPDF ( 0 ),
174 fMVAPdfS ( 0 ),
175 fMVAPdfB ( 0 ),
176 fSplS ( 0 ),
177 fSplB ( 0 ),
178 fSpleffBvsS ( 0 ),
179 fSplTrainS ( 0 ),
180 fSplTrainB ( 0 ),
181 fSplTrainEffBvsS ( 0 ),
182 fVarTransformString ( "None" ),
183 fTransformationPointer ( 0 ),
184 fTransformation ( dsi, methodTitle ),
185 fVerbose ( kFALSE ),
186 fVerbosityLevelString ( "Default" ),
187 fHelp ( kFALSE ),
188 fHasMVAPdfs ( kFALSE ),
189 fIgnoreNegWeightsInTraining( kFALSE ),
190 fSignalClass ( 0 ),
191 fBackgroundClass ( 0 ),
192 fSplRefS ( 0 ),
193 fSplRefB ( 0 ),
194 fSplTrainRefS ( 0 ),
195 fSplTrainRefB ( 0 ),
196 fSetupCompleted (kFALSE)
197{
198 SetTestvarName();
199 fLogger->SetSource(GetName());
200
201// // default extension for weight files
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// constructor used for Testing + Application of the MVA,
206/// only (no training), using given WeightFiles
207
210 const TString& weightFile ) :
211 IMethod(),
212 Configurable(""),
213 fTmpEvent ( 0 ),
214 fRanking ( 0 ),
215 fInputVars ( 0 ),
216 fAnalysisType ( Types::kNoAnalysisType ),
217 fRegressionReturnVal ( 0 ),
218 fMulticlassReturnVal ( 0 ),
219 fDataSetInfo ( dsi ),
220 fSignalReferenceCut ( 0.5 ),
221 fVariableTransformType ( Types::kSignal ),
222 fJobName ( "" ),
223 fMethodName ( "MethodBase" ),
224 fMethodType ( methodType ),
225 fTestvar ( "" ),
226 fTMVATrainingVersion ( 0 ),
227 fROOTTrainingVersion ( 0 ),
228 fConstructedFromWeightFile ( kTRUE ),
229 fBaseDir ( 0 ),
230 fMethodBaseDir ( 0 ),
231 fFile ( 0 ),
232 fSilentFile (kFALSE),
233 fModelPersistence (kTRUE),
234 fWeightFile ( weightFile ),
235 fEffS ( 0 ),
236 fDefaultPDF ( 0 ),
237 fMVAPdfS ( 0 ),
238 fMVAPdfB ( 0 ),
239 fSplS ( 0 ),
240 fSplB ( 0 ),
241 fSpleffBvsS ( 0 ),
242 fSplTrainS ( 0 ),
243 fSplTrainB ( 0 ),
244 fSplTrainEffBvsS ( 0 ),
245 fVarTransformString ( "None" ),
246 fTransformationPointer ( 0 ),
247 fTransformation ( dsi, "" ),
248 fVerbose ( kFALSE ),
249 fVerbosityLevelString ( "Default" ),
250 fHelp ( kFALSE ),
251 fHasMVAPdfs ( kFALSE ),
252 fIgnoreNegWeightsInTraining( kFALSE ),
253 fSignalClass ( 0 ),
254 fBackgroundClass ( 0 ),
255 fSplRefS ( 0 ),
256 fSplRefB ( 0 ),
257 fSplTrainRefS ( 0 ),
258 fSplTrainRefB ( 0 ),
259 fSetupCompleted (kFALSE)
260{
262// // constructor used for Testing + Application of the MVA,
263// // only (no training), using given WeightFiles
264}
265
266////////////////////////////////////////////////////////////////////////////////
267/// destructor
268
270{
271 // destructor
272 if (!fSetupCompleted) Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Calling destructor of method which got never setup" << Endl;
273
274 // destructor
275 if (fInputVars != 0) { fInputVars->clear(); delete fInputVars; }
276 if (fRanking != 0) delete fRanking;
277
278 // PDFs
279 if (fDefaultPDF!= 0) { delete fDefaultPDF; fDefaultPDF = 0; }
280 if (fMVAPdfS != 0) { delete fMVAPdfS; fMVAPdfS = 0; }
281 if (fMVAPdfB != 0) { delete fMVAPdfB; fMVAPdfB = 0; }
282
283 // Splines
284 if (fSplS) { delete fSplS; fSplS = 0; }
285 if (fSplB) { delete fSplB; fSplB = 0; }
286 if (fSpleffBvsS) { delete fSpleffBvsS; fSpleffBvsS = 0; }
287 if (fSplRefS) { delete fSplRefS; fSplRefS = 0; }
288 if (fSplRefB) { delete fSplRefB; fSplRefB = 0; }
289 if (fSplTrainRefS) { delete fSplTrainRefS; fSplTrainRefS = 0; }
290 if (fSplTrainRefB) { delete fSplTrainRefB; fSplTrainRefB = 0; }
291 if (fSplTrainEffBvsS) { delete fSplTrainEffBvsS; fSplTrainEffBvsS = 0; }
292
293 for (size_t i = 0; i < fEventCollections.size(); i++ ) {
294 if (fEventCollections.at(i)) {
295 for (std::vector<Event*>::const_iterator it = fEventCollections.at(i)->begin();
296 it != fEventCollections.at(i)->end(); ++it) {
297 delete (*it);
298 }
299 delete fEventCollections.at(i);
300 fEventCollections.at(i) = nullptr;
301 }
302 }
303
304 if (fRegressionReturnVal) delete fRegressionReturnVal;
305 if (fMulticlassReturnVal) delete fMulticlassReturnVal;
306}
307
308////////////////////////////////////////////////////////////////////////////////
309/// setup of methods
310
312{
313 // setup of methods
314
315 if (fSetupCompleted) Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Calling SetupMethod for the second time" << Endl;
316 InitBase();
317 DeclareBaseOptions();
318 Init();
319 DeclareOptions();
320 fSetupCompleted = kTRUE;
321}
322
323////////////////////////////////////////////////////////////////////////////////
324/// process all options
325/// the "CheckForUnusedOptions" is done in an independent call, since it may be overridden by derived class
326/// (sometimes, eg, fitters are used which can only be implemented during training phase)
327
329{
330 ProcessBaseOptions();
331 ProcessOptions();
332}
333
334////////////////////////////////////////////////////////////////////////////////
335/// check may be overridden by derived class
336/// (sometimes, eg, fitters are used which can only be implemented during training phase)
337
339{
340 CheckForUnusedOptions();
341}
342
343////////////////////////////////////////////////////////////////////////////////
344/// default initialization called by all constructors
345
347{
348 SetConfigDescription( "Configuration options for classifier architecture and tuning" );
349
350 fNbins = gConfig().fVariablePlotting.fNbinsXOfROCCurve;
351 fNbinsMVAoutput = gConfig().fVariablePlotting.fNbinsMVAoutput;
352 fNbinsH = NBIN_HIST_HIGH;
353
354 fSplTrainS = 0;
355 fSplTrainB = 0;
356 fSplTrainEffBvsS = 0;
357 fMeanS = -1;
358 fMeanB = -1;
359 fRmsS = -1;
360 fRmsB = -1;
361 fXmin = DBL_MAX;
362 fXmax = -DBL_MAX;
363 fTxtWeightsOnly = kTRUE;
364 fSplRefS = 0;
365 fSplRefB = 0;
366
367 fTrainTime = -1.;
368 fTestTime = -1.;
369
370 fRanking = 0;
371
372 // temporary until the move to DataSet is complete
373 fInputVars = new std::vector<TString>;
374 for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
375 fInputVars->push_back(DataInfo().GetVariableInfo(ivar).GetLabel());
376 }
377 fRegressionReturnVal = 0;
378 fMulticlassReturnVal = 0;
379
380 fEventCollections.resize( 2 );
381 fEventCollections.at(0) = 0;
382 fEventCollections.at(1) = 0;
383
384 // retrieve signal and background class index
385 if (DataInfo().GetClassInfo("Signal") != 0) {
386 fSignalClass = DataInfo().GetClassInfo("Signal")->GetNumber();
387 }
388 if (DataInfo().GetClassInfo("Background") != 0) {
389 fBackgroundClass = DataInfo().GetClassInfo("Background")->GetNumber();
390 }
391
392 SetConfigDescription( "Configuration options for MVA method" );
393 SetConfigName( TString("Method") + GetMethodTypeName() );
394}
395
396////////////////////////////////////////////////////////////////////////////////
397/// define the options (their key words) that can be set in the option string
398/// here the options valid for ALL MVA methods are declared.
399///
400/// know options:
401///
402/// - VariableTransform=None,Decorrelated,PCA to use transformed variables
403/// instead of the original ones
404/// - VariableTransformType=Signal,Background which decorrelation matrix to use
405/// in the method. Only the Likelihood
406/// Method can make proper use of independent
407/// transformations of signal and background
408/// - fNbinsMVAPdf = 50 Number of bins used to create a PDF of MVA
409/// - fNsmoothMVAPdf = 2 Number of times a histogram is smoothed before creating the PDF
410/// - fHasMVAPdfs create PDFs for the MVA outputs
411/// - V for Verbose output (!V) for non verbos
412/// - H for Help message
413
415{
416 DeclareOptionRef( fVerbose, "V", "Verbose output (short form of \"VerbosityLevel\" below - overrides the latter one)" );
417
418 DeclareOptionRef( fVerbosityLevelString="Default", "VerbosityLevel", "Verbosity level" );
419 AddPreDefVal( TString("Default") ); // uses default defined in MsgLogger header
420 AddPreDefVal( TString("Debug") );
421 AddPreDefVal( TString("Verbose") );
422 AddPreDefVal( TString("Info") );
423 AddPreDefVal( TString("Warning") );
424 AddPreDefVal( TString("Error") );
425 AddPreDefVal( TString("Fatal") );
426
427 // If True (default): write all training results (weights) as text files only;
428 // if False: write also in ROOT format (not available for all methods - will abort if not
429 fTxtWeightsOnly = kTRUE; // OBSOLETE !!!
430 fNormalise = kFALSE; // OBSOLETE !!!
431
432 DeclareOptionRef( fVarTransformString, "VarTransform", "List of variable transformations performed before training, e.g., \"D_Background,P_Signal,G,N_AllClasses\" for: \"Decorrelation, PCA-transformation, Gaussianisation, Normalisation, each for the given class of events ('AllClasses' denotes all events of all classes, if no class indication is given, 'All' is assumed)\"" );
433
434 DeclareOptionRef( fHelp, "H", "Print method-specific help message" );
435
436 DeclareOptionRef( fHasMVAPdfs, "CreateMVAPdfs", "Create PDFs for classifier outputs (signal and background)" );
437
438 DeclareOptionRef( fIgnoreNegWeightsInTraining, "IgnoreNegWeightsInTraining",
439 "Events with negative weights are ignored in the training (but are included for testing and performance evaluation)" );
440}
441
442////////////////////////////////////////////////////////////////////////////////
443/// the option string is decoded, for available options see "DeclareOptions"
444
446{
447 if (HasMVAPdfs()) {
448 // setting the default bin num... maybe should be static ? ==> Please no static (JS)
449 // You can't use the logger in the constructor!!! Log() << kINFO << "Create PDFs" << Endl;
450 // reading every PDF's definition and passing the option string to the next one to be read and marked
451 fDefaultPDF = new PDF( TString(GetName())+"_PDF", GetOptions(), "MVAPdf" );
452 fDefaultPDF->DeclareOptions();
453 fDefaultPDF->ParseOptions();
454 fDefaultPDF->ProcessOptions();
455 fMVAPdfB = new PDF( TString(GetName())+"_PDFBkg", fDefaultPDF->GetOptions(), "MVAPdfBkg", fDefaultPDF );
456 fMVAPdfB->DeclareOptions();
457 fMVAPdfB->ParseOptions();
458 fMVAPdfB->ProcessOptions();
459 fMVAPdfS = new PDF( TString(GetName())+"_PDFSig", fMVAPdfB->GetOptions(), "MVAPdfSig", fDefaultPDF );
460 fMVAPdfS->DeclareOptions();
461 fMVAPdfS->ParseOptions();
462 fMVAPdfS->ProcessOptions();
463
464 // the final marked option string is written back to the original methodbase
465 SetOptions( fMVAPdfS->GetOptions() );
466 }
467
468 TMVA::CreateVariableTransforms( fVarTransformString,
469 DataInfo(),
470 GetTransformationHandler(),
471 Log() );
472
473 if (!HasMVAPdfs()) {
474 if (fDefaultPDF!= 0) { delete fDefaultPDF; fDefaultPDF = 0; }
475 if (fMVAPdfS != 0) { delete fMVAPdfS; fMVAPdfS = 0; }
476 if (fMVAPdfB != 0) { delete fMVAPdfB; fMVAPdfB = 0; }
477 }
478
479 if (fVerbose) { // overwrites other settings
480 fVerbosityLevelString = TString("Verbose");
481 Log().SetMinType( kVERBOSE );
482 }
483 else if (fVerbosityLevelString == "Debug" ) Log().SetMinType( kDEBUG );
484 else if (fVerbosityLevelString == "Verbose" ) Log().SetMinType( kVERBOSE );
485 else if (fVerbosityLevelString == "Info" ) Log().SetMinType( kINFO );
486 else if (fVerbosityLevelString == "Warning" ) Log().SetMinType( kWARNING );
487 else if (fVerbosityLevelString == "Error" ) Log().SetMinType( kERROR );
488 else if (fVerbosityLevelString == "Fatal" ) Log().SetMinType( kFATAL );
489 else if (fVerbosityLevelString != "Default" ) {
490 Log() << kFATAL << "<ProcessOptions> Verbosity level type '"
491 << fVerbosityLevelString << "' unknown." << Endl;
492 }
493 Event::SetIgnoreNegWeightsInTraining(fIgnoreNegWeightsInTraining);
494}
495
496////////////////////////////////////////////////////////////////////////////////
497/// options that are used ONLY for the READER to ensure backward compatibility
498/// they are hence without any effect (the reader is only reading the training
499/// options that HAD been used at the training of the .xml weight file at hand
500
502{
503 DeclareOptionRef( fNormalise=kFALSE, "Normalise", "Normalise input variables" ); // don't change the default !!!
504 DeclareOptionRef( fUseDecorr=kFALSE, "D", "Use-decorrelated-variables flag" );
505 DeclareOptionRef( fVariableTransformTypeString="Signal", "VarTransformType",
506 "Use signal or background events to derive for variable transformation (the transformation is applied on both types of, course)" );
507 AddPreDefVal( TString("Signal") );
508 AddPreDefVal( TString("Background") );
509 DeclareOptionRef( fTxtWeightsOnly=kTRUE, "TxtWeightFilesOnly", "If True: write all training results (weights) as text files (False: some are written in ROOT format)" );
510 // Why on earth ?? was this here? Was the verbosity level option meant to 'disappear? Not a good idea i think..
511 // DeclareOptionRef( fVerbosityLevelString="Default", "VerboseLevel", "Verbosity level" );
512 // AddPreDefVal( TString("Default") ); // uses default defined in MsgLogger header
513 // AddPreDefVal( TString("Debug") );
514 // AddPreDefVal( TString("Verbose") );
515 // AddPreDefVal( TString("Info") );
516 // AddPreDefVal( TString("Warning") );
517 // AddPreDefVal( TString("Error") );
518 // AddPreDefVal( TString("Fatal") );
519 DeclareOptionRef( fNbinsMVAPdf = 60, "NbinsMVAPdf", "Number of bins used for the PDFs of classifier outputs" );
520 DeclareOptionRef( fNsmoothMVAPdf = 2, "NsmoothMVAPdf", "Number of smoothing iterations for classifier PDFs" );
521}
522
523
524////////////////////////////////////////////////////////////////////////////////
525/// call the Optimizer with the set of parameters and ranges that
526/// are meant to be tuned.
527
528std::map<TString,Double_t> TMVA::MethodBase::OptimizeTuningParameters(TString /* fomType */ , TString /* fitType */)
529{
530 // this is just a dummy... needs to be implemented for each method
531 // individually (as long as we don't have it automatized via the
532 // configuration string
533
534 Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Parameter optimization is not yet implemented for method "
535 << GetName() << Endl;
536 Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Currently we need to set hardcoded which parameter is tuned in which ranges"<<Endl;
537
538 return std::map<TString,Double_t>();
539}
540
541////////////////////////////////////////////////////////////////////////////////
542/// set the tuning parameters according to the argument
543/// This is just a dummy .. have a look at the MethodBDT how you could
544/// perhaps implement the same thing for the other Classifiers..
545
546void TMVA::MethodBase::SetTuneParameters(std::map<TString,Double_t> /* tuneParameters */)
547{
548}
549
550////////////////////////////////////////////////////////////////////////////////
551
553{
554 Data()->SetCurrentType(Types::kTraining);
555 Event::SetIsTraining(kTRUE); // used to set negative event weights to zero if chosen to do so
556
557 // train the MVA method
558 if (Help()) PrintHelpMessage();
559
560 // all histograms should be created in the method's subdirectory
561 if(!IsSilentFile()) BaseDir()->cd();
562
563 // once calculate all the transformation (e.g. the sequence of Decorr:Gauss:Decorr)
564 // needed for this classifier
565 GetTransformationHandler().CalcTransformations(Data()->GetEventCollection());
566
567 // call training of derived MVA
568 Log() << kDEBUG //<<Form("\tDataset[%s] : ",DataInfo().GetName())
569 << "Begin training" << Endl;
570 Long64_t nEvents = Data()->GetNEvents();
571 Timer traintimer( nEvents, GetName(), kTRUE );
572 Train();
573 Log() << kDEBUG //<<Form("Dataset[%s] : ",DataInfo().GetName()
574 << "\tEnd of training " << Endl;
575 SetTrainTime(traintimer.ElapsedSeconds());
576 Log() << kINFO //<<Form("Dataset[%s] : ",DataInfo().GetName())
577 << "Elapsed time for training with " << nEvents << " events: "
578 << traintimer.GetElapsedTime() << " " << Endl;
579
580 Log() << kDEBUG //<<Form("Dataset[%s] : ",DataInfo().GetName())
581 << "\tCreate MVA output for ";
582
583 // create PDFs for the signal and background MVA distributions (if required)
584 if (DoMulticlass()) {
585 Log() <<Form("[%s] : ",DataInfo().GetName())<< "Multiclass classification on training sample" << Endl;
586 AddMulticlassOutput(Types::kTraining);
587 }
588 else if (!DoRegression()) {
589
590 Log() <<Form("[%s] : ",DataInfo().GetName())<< "classification on training sample" << Endl;
591 AddClassifierOutput(Types::kTraining);
592 if (HasMVAPdfs()) {
593 CreateMVAPdfs();
594 AddClassifierOutputProb(Types::kTraining);
595 }
596
597 } else {
598
599 Log() <<Form("Dataset[%s] : ",DataInfo().GetName())<< "regression on training sample" << Endl;
600 AddRegressionOutput( Types::kTraining );
601
602 if (HasMVAPdfs() ) {
603 Log() <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Create PDFs" << Endl;
604 CreateMVAPdfs();
605 }
606 }
607
608 // write the current MVA state into stream
609 // produced are one text file and one ROOT file
610 if (fModelPersistence ) WriteStateToFile();
611
612 // produce standalone make class (presently only supported for classification)
613 if ((!DoRegression()) && (fModelPersistence)) MakeClass();
614
615 // write additional monitoring histograms to main target file (not the weight file)
616 // again, make sure the histograms go into the method's subdirectory
617 if(!IsSilentFile())
618 {
619 BaseDir()->cd();
620 WriteMonitoringHistosToFile();
621 }
622}
623
624////////////////////////////////////////////////////////////////////////////////
625
627{
628 if (!DoRegression()) Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Trying to use GetRegressionDeviation() with a classification job" << Endl;
629 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Create results for " << (type==Types::kTraining?"training":"testing") << Endl;
630 ResultsRegression* regRes = (ResultsRegression*)Data()->GetResults(GetMethodName(), Types::kTesting, Types::kRegression);
631 bool truncate = false;
632 TH1F* h1 = regRes->QuadraticDeviation( tgtNum , truncate, 1.);
633 stddev = sqrt(h1->GetMean());
634 truncate = true;
635 Double_t yq[1], xq[]={0.9};
636 h1->GetQuantiles(1,yq,xq);
637 TH1F* h2 = regRes->QuadraticDeviation( tgtNum , truncate, yq[0]);
638 stddev90Percent = sqrt(h2->GetMean());
639 delete h1;
640 delete h2;
641}
642
643////////////////////////////////////////////////////////////////////////////////
644/// Get al regression values in one call
646{
647 Long64_t nEvents = Data()->GetNEvents();
648 // use timer
649 Timer timer( nEvents, GetName(), kTRUE );
650
651 // Drawing the progress bar every event was causing a huge slowdown in the evaluation time
652 // So we set some parameters to draw the progress bar a total of totalProgressDraws, i.e. only draw every 1 in 100
653
654 Int_t totalProgressDraws = 100; // total number of times to update the progress bar
655 Int_t drawProgressEvery = 1; // draw every nth event such that we have a total of totalProgressDraws
657
658 size_t ntargets = Data()->GetEvent(0)->GetNTargets();
659 std::vector<float> output(nEvents*ntargets);
660 auto itr = output.begin();
661 for (Int_t ievt=0; ievt<nEvents; ievt++) {
662
663 Data()->SetCurrentEvent(ievt);
664 std::vector< Float_t > vals = GetRegressionValues();
665 if (vals.size() != ntargets)
666 Log() << kFATAL << "Output regression vector with size " << vals.size() << " is not consistent with target size of "
667 << ntargets << std::endl;
668
669 std::copy(vals.begin(), vals.end(), itr);
670 itr += vals.size();
671
672 // Only draw the progress bar once in a while, doing this every event causes the evaluation to be ridiculously slow
673 if(ievt % drawProgressEvery == 0 || ievt==nEvents-1) timer.DrawProgressBar( ievt );
674 }
675
676 return output;
677}
678
679////////////////////////////////////////////////////////////////////////////////
680/// prepare tree branch with the method's discriminating variable
681
683{
684 Data()->SetCurrentType(type);
685
686 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Create results for " << (type==Types::kTraining?"training":"testing") << Endl;
687
688 ResultsRegression* regRes = (ResultsRegression*)Data()->GetResults(GetMethodName(), type, Types::kRegression);
689
690 Long64_t nEvents = Data()->GetNEvents();
691
692 // use timer
693 Timer timer( nEvents, GetName(), kTRUE );
694
695 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName()) << "Evaluation of " << GetMethodName() << " on "
696 << (type==Types::kTraining?"training":"testing") << " sample" << Endl;
697
698 regRes->Resize( nEvents );
699
700 std::vector<float> output = GetAllRegressionValues();
701 // assume we have all number of targets for all events
702 Data()->SetCurrentEvent(0);
703 size_t nTargets = GetEvent()->GetNTargets();
704 auto regValuesBegin = output.begin();
706
707 if (output.size() != nTargets * size_t(nEvents))
708 Log() << kFATAL << "Output regression vector with size " << output.size() << " is not consistent with target size of "
709 << nTargets << " and number of events " << nEvents << std::endl;
710
711
712 for (Int_t ievt=0; ievt<nEvents; ievt++) {
713
714 std::vector< Float_t > vals(regValuesBegin, regValuesEnd);
715 regRes->SetValue( vals, ievt );
716
719 }
720
721 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())
722 << "Elapsed time for evaluation of " << nEvents << " events: "
723 << timer.GetElapsedTime() << " " << Endl;
724
725 // store time used for testing
727 SetTestTime(timer.ElapsedSeconds());
728
729 TString histNamePrefix(GetTestvarName());
730 histNamePrefix += (type==Types::kTraining?"train":"test");
731 regRes->CreateDeviationHistograms( histNamePrefix );
732}
733////////////////////////////////////////////////////////////////////////////////
734/// Get all multi-class values
736{
737 // use timer for progress bar
738
739 Long64_t nEvents = Data()->GetNEvents();
740 Timer timer( nEvents, GetName(), kTRUE );
741
742 Int_t modulo = Int_t(nEvents/100) + 1;
743 // call first time to get number of classes
744 Data()->SetCurrentEvent(0);
745 std::vector< Float_t > vals = GetMulticlassValues();
746 std::vector<float> output(nEvents * vals.size());
747 auto itr = output.begin();
748 std::copy(vals.begin(), vals.end(), itr);
749 for (Int_t ievt=1; ievt<nEvents; ievt++) {
750 itr += vals.size();
751 Data()->SetCurrentEvent(ievt);
752 vals = GetMulticlassValues();
753
754 std::copy(vals.begin(), vals.end(), itr);
755
756 if (ievt%modulo == 0) timer.DrawProgressBar( ievt );
757 }
758 return output;
759}
760////////////////////////////////////////////////////////////////////////////////
761/// prepare tree branch with the method's discriminating variable
762
764{
765 Data()->SetCurrentType(type);
766
767 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Create results for " << (type==Types::kTraining?"training":"testing") << Endl;
768
769 ResultsMulticlass* resMulticlass = dynamic_cast<ResultsMulticlass*>(Data()->GetResults(GetMethodName(), type, Types::kMulticlass));
770 if (!resMulticlass) Log() << kFATAL<<Form("Dataset[%s] : ",DataInfo().GetName())<< "unable to create pointer in AddMulticlassOutput, exiting."<<Endl;
771
772 Long64_t nEvents = Data()->GetNEvents();
773
774 // use timer
775 Timer timer( nEvents, GetName(), kTRUE );
776
777 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Multiclass evaluation of " << GetMethodName() << " on "
778 << (type==Types::kTraining?"training":"testing") << " sample" << Endl;
779
780 resMulticlass->Resize( nEvents );
781 std::vector<Float_t> output = GetAllMulticlassValues();
782 size_t nClasses = output.size()/nEvents;
783 for (Int_t ievt=0; ievt<nEvents; ievt++) {
784 std::vector< Float_t > vals(output.begin()+ievt*nClasses, output.begin()+(ievt+1)*nClasses);
785 resMulticlass->SetValue( vals, ievt );
786 }
787
788
789 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())
790 << "Elapsed time for evaluation of " << nEvents << " events: "
791 << timer.GetElapsedTime() << " " << Endl;
792
793 // store time used for testing
795 SetTestTime(timer.ElapsedSeconds());
796
797 TString histNamePrefix(GetTestvarName());
798 histNamePrefix += (type==Types::kTraining?"_Train":"_Test");
799
800 resMulticlass->CreateMulticlassHistos( histNamePrefix, fNbinsMVAoutput, fNbinsH );
801 resMulticlass->CreateMulticlassPerformanceHistos(histNamePrefix);
802}
803
804////////////////////////////////////////////////////////////////////////////////
805
807 if (err) *err=-1;
808 if (errUpper) *errUpper=-1;
809}
810
811////////////////////////////////////////////////////////////////////////////////
812
814 fTmpEvent = ev;
815 Double_t val = GetMvaValue(err, errUpper);
816 fTmpEvent = 0;
817 return val;
818}
819
820////////////////////////////////////////////////////////////////////////////////
821/// uses a pre-set cut on the MVA output (SetSignalReferenceCut and SetSignalReferenceCutOrientation)
822/// for a quick determination if an event would be selected as signal or background
823
825 return GetMvaValue()*GetSignalReferenceCutOrientation() > GetSignalReferenceCut()*GetSignalReferenceCutOrientation() ? kTRUE : kFALSE;
826}
827////////////////////////////////////////////////////////////////////////////////
828/// uses a pre-set cut on the MVA output (SetSignalReferenceCut and SetSignalReferenceCutOrientation)
829/// for a quick determination if an event with this mva output value would be selected as signal or background
830
832 return mvaVal*GetSignalReferenceCutOrientation() > GetSignalReferenceCut()*GetSignalReferenceCutOrientation() ? kTRUE : kFALSE;
833}
834
835////////////////////////////////////////////////////////////////////////////////
836/// prepare tree branch with the method's discriminating variable
837
839{
840 Data()->SetCurrentType(type);
841
843 (ResultsClassification*)Data()->GetResults(GetMethodName(), type, Types::kClassification );
844
845 Long64_t nEvents = Data()->GetNEvents();
846 clRes->Resize( nEvents );
847
848 // use timer
849 Timer timer( nEvents, GetName(), kTRUE );
850
851 Log() << kHEADER << Form("[%s] : ",DataInfo().GetName())
852 << "Evaluation of " << GetMethodName() << " on "
853 << (Data()->GetCurrentType() == Types::kTraining ? "training" : "testing")
854 << " sample (" << nEvents << " events)" << Endl;
855
856 std::vector<Double_t> mvaValues = GetMvaValues(0, nEvents, true);
857
858 Log() << kINFO
859 << "Elapsed time for evaluation of " << nEvents << " events: "
860 << timer.GetElapsedTime() << " " << Endl;
861
862 // store time used for testing
864 SetTestTime(timer.ElapsedSeconds());
865
866 // load mva values and type to results object
867 for (Int_t ievt = 0; ievt < nEvents; ievt++) {
868 // note we do not need the trasformed event to get the signal/background information
869 // by calling Data()->GetEvent instead of this->GetEvent we access the untransformed one
870 auto ev = Data()->GetEvent(ievt);
871 clRes->SetValue(mvaValues[ievt], ievt, DataInfo().IsSignal(ev));
872 }
873}
874
875////////////////////////////////////////////////////////////////////////////////
876/// get all the MVA values for the events of the current Data type
878{
879
880 Long64_t nEvents = Data()->GetNEvents();
881 if (firstEvt > lastEvt || lastEvt > nEvents) lastEvt = nEvents;
882 if (firstEvt < 0) firstEvt = 0;
883 std::vector<Double_t> values(lastEvt-firstEvt);
884 // log in case of looping on all the events
885 nEvents = values.size();
886
887 // use timer
888 Timer timer( nEvents, GetName(), kTRUE );
889
890 if (logProgress)
891 Log() << kHEADER << Form("[%s] : ",DataInfo().GetName())
892 << "Evaluation of " << GetMethodName() << " on "
893 << (Data()->GetCurrentType() == Types::kTraining ? "training" : "testing")
894 << " sample (" << nEvents << " events)" << Endl;
895
896 for (Int_t ievt=firstEvt; ievt<lastEvt; ievt++) {
897 Data()->SetCurrentEvent(ievt);
898 values[ievt] = GetMvaValue();
899
900 // print progress
901 if (logProgress) {
902 Int_t modulo = Int_t(nEvents/100);
903 if (modulo <= 0 ) modulo = 1;
904 if (ievt%modulo == 0) timer.DrawProgressBar( ievt );
905 }
906 }
907 if (logProgress) {
908 Log() << kINFO //<<Form("Dataset[%s] : ",DataInfo().GetName())
909 << "Elapsed time for evaluation of " << nEvents << " events: "
910 << timer.GetElapsedTime() << " " << Endl;
911 }
912
913 return values;
914}
915
916////////////////////////////////////////////////////////////////////////////////
917/// get all the MVA values for the events of the given Data type
918// (this is used by Method Category and it does not need to be re-implemented by derived classes )
920{
921 fTmpData = data;
922 auto result = GetMvaValues(firstEvt, lastEvt, logProgress);
923 fTmpData = nullptr;
924 return result;
925}
926
927////////////////////////////////////////////////////////////////////////////////
928/// prepare tree branch with the method's discriminating variable
929
931{
932 Data()->SetCurrentType(type);
933
935 (ResultsClassification*)Data()->GetResults(TString("prob_")+GetMethodName(), type, Types::kClassification );
936
937 Long64_t nEvents = Data()->GetNEvents();
938
939 // use timer
940 Timer timer( nEvents, GetName(), kTRUE );
941
942 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName()) << "Evaluation of " << GetMethodName() << " on "
943 << (type==Types::kTraining?"training":"testing") << " sample" << Endl;
944
945 mvaProb->Resize( nEvents );
946 Int_t modulo = Int_t(nEvents/100);
947 if (modulo <= 0 ) modulo = 1;
948 for (Int_t ievt=0; ievt<nEvents; ievt++) {
949
950 Data()->SetCurrentEvent(ievt);
951 Float_t proba = ((Float_t)GetProba( GetMvaValue(), 0.5 ));
952 if (proba < 0) break;
953 mvaProb->SetValue( proba, ievt, DataInfo().IsSignal( Data()->GetEvent()) );
954
955 // print progress
956 if (ievt%modulo == 0) timer.DrawProgressBar( ievt );
957 }
958
959 Log() << kDEBUG <<Form("Dataset[%s] : ",DataInfo().GetName())
960 << "Elapsed time for evaluation of " << nEvents << " events: "
961 << timer.GetElapsedTime() << " " << Endl;
962}
963
964////////////////////////////////////////////////////////////////////////////////
965/// calculate <sum-of-deviation-squared> of regression output versus "true" value from test sample
966///
967/// - bias = average deviation
968/// - dev = average absolute deviation
969/// - rms = rms of deviation
970
975 Double_t& corr,
977{
978 Types::ETreeType savedType = Data()->GetCurrentType();
979 Data()->SetCurrentType(type);
980
981 bias = 0; biasT = 0; dev = 0; devT = 0; rms = 0; rmsT = 0;
982 Double_t sumw = 0;
983 Double_t m1 = 0, m2 = 0, s1 = 0, s2 = 0, s12 = 0; // for correlation
984 const Int_t nevt = GetNEvents();
985 Float_t* rV = new Float_t[nevt];
986 Float_t* tV = new Float_t[nevt];
987 Float_t* wV = new Float_t[nevt];
988 Float_t xmin = 1e30, xmax = -1e30;
989 Log() << kINFO << "Calculate regression for all events" << Endl;
990 Timer timer( nevt, GetName(), kTRUE );
991 Long64_t modulo = Long64_t(nevt / 100) + 1;
992 auto output = GetAllRegressionValues();
993 int ntargets = Data()->GetEvent(0)->GetNTargets();
994 for (Long64_t ievt=0; ievt<nevt; ievt++) {
995 const Event* ev = Data()->GetEvent(ievt); // NOTE: need untransformed event here !
996 Float_t t = ev->GetTarget(0);
997 Float_t w = ev->GetWeight();
998 Float_t r = output[ievt*ntargets];
999 Float_t d = (r-t);
1000
1001 // find min/max
1004
1005 // store for truncated RMS computation
1006 rV[ievt] = r;
1007 tV[ievt] = t;
1008 wV[ievt] = w;
1009
1010 // compute deviation-squared
1011 sumw += w;
1012 bias += w * d;
1013 dev += w * TMath::Abs(d);
1014 rms += w * d * d;
1015
1016 // compute correlation between target and regression estimate
1017 m1 += t*w; s1 += t*t*w;
1018 m2 += r*w; s2 += r*r*w;
1019 s12 += t*r;
1020 // print progress
1021 if (ievt % modulo == 0)
1022 timer.DrawProgressBar(ievt);
1023 }
1024 timer.DrawProgressBar(nevt - 1);
1025 Log() << kINFO << "Elapsed time for evaluation of " << nevt << " events: "
1026 << timer.GetElapsedTime() << " " << Endl;
1027
1028 // standard quantities
1029 bias /= sumw;
1030 dev /= sumw;
1031 rms /= sumw;
1033
1034 // correlation
1035 m1 /= sumw;
1036 m2 /= sumw;
1037 corr = s12/sumw - m1*m2;
1038 corr /= TMath::Sqrt( (s1/sumw - m1*m1) * (s2/sumw - m2*m2) );
1039
1040 // create histogram required for computation of mutual information
1041 TH2F* hist = new TH2F( "hist", "hist", 150, xmin, xmax, 100, xmin, xmax );
1042 TH2F* histT = new TH2F( "histT", "histT", 150, xmin, xmax, 100, xmin, xmax );
1043
1044 // compute truncated RMS and fill histogram
1045 Double_t devMax = bias + 2*rms;
1046 Double_t devMin = bias - 2*rms;
1047 sumw = 0;
1048 for (Long64_t ievt=0; ievt<nevt; ievt++) {
1049 Float_t d = (rV[ievt] - tV[ievt]);
1050 hist->Fill( rV[ievt], tV[ievt], wV[ievt] );
1051 if (d >= devMin && d <= devMax) {
1052 sumw += wV[ievt];
1053 biasT += wV[ievt] * d;
1054 devT += wV[ievt] * TMath::Abs(d);
1055 rmsT += wV[ievt] * d * d;
1056 histT->Fill( rV[ievt], tV[ievt], wV[ievt] );
1057 }
1058 }
1059 biasT /= sumw;
1060 devT /= sumw;
1061 rmsT /= sumw;
1063 mInf = gTools().GetMutualInformation( *hist );
1065
1066 delete hist;
1067 delete histT;
1068
1069 delete [] rV;
1070 delete [] tV;
1071 delete [] wV;
1072
1073 Data()->SetCurrentType(savedType);
1074}
1075
1076
1077////////////////////////////////////////////////////////////////////////////////
1078/// test multiclass classification
1079
1081{
1082 ResultsMulticlass* resMulticlass = dynamic_cast<ResultsMulticlass*>(Data()->GetResults(GetMethodName(), Types::kTesting, Types::kMulticlass));
1083 if (!resMulticlass) Log() << kFATAL<<Form("Dataset[%s] : ",DataInfo().GetName())<< "unable to create pointer in TestMulticlass, exiting."<<Endl;
1084
1085 // GA evaluation of best cut for sig eff * sig pur. Slow, disabled for now.
1086 // Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Determine optimal multiclass cuts for test
1087 // data..." << Endl; for (UInt_t icls = 0; icls<DataInfo().GetNClasses(); ++icls) {
1088 // resMulticlass->GetBestMultiClassCuts(icls);
1089 // }
1090
1091 // Create histograms for use in TMVA GUI
1092 TString histNamePrefix(GetTestvarName());
1095
1096 resMulticlass->CreateMulticlassHistos(histNamePrefixTest, fNbinsMVAoutput, fNbinsH);
1097 resMulticlass->CreateMulticlassPerformanceHistos(histNamePrefixTest);
1098
1099 resMulticlass->CreateMulticlassHistos(histNamePrefixTrain, fNbinsMVAoutput, fNbinsH);
1100 resMulticlass->CreateMulticlassPerformanceHistos(histNamePrefixTrain);
1101}
1102
1103
1104////////////////////////////////////////////////////////////////////////////////
1105/// initialization
1106
1108{
1109 Data()->SetCurrentType(Types::kTesting);
1110
1112 ( Data()->GetResults(GetMethodName(),Types::kTesting, Types::kClassification) );
1113
1114 // sanity checks: tree must exist, and theVar must be in tree
1115 if (0==mvaRes && !(GetMethodTypeName().Contains("Cuts"))) {
1116 Log()<<Form("Dataset[%s] : ",DataInfo().GetName()) << "mvaRes " << mvaRes << " GetMethodTypeName " << GetMethodTypeName()
1117 << " contains " << !(GetMethodTypeName().Contains("Cuts")) << Endl;
1118 Log() << kFATAL<<Form("Dataset[%s] : ",DataInfo().GetName()) << "<TestInit> Test variable " << GetTestvarName()
1119 << " not found in tree" << Endl;
1120 }
1121
1122 // basic statistics operations are made in base class
1123 gTools().ComputeStat( GetEventCollection(Types::kTesting), mvaRes->GetValueVector(),
1124 fMeanS, fMeanB, fRmsS, fRmsB, fXmin, fXmax, fSignalClass );
1125
1126 // choose reasonable histogram ranges, by removing outliers
1127 Double_t nrms = 10;
1128 fXmin = TMath::Max( TMath::Min( fMeanS - nrms*fRmsS, fMeanB - nrms*fRmsB ), fXmin );
1129 fXmax = TMath::Min( TMath::Max( fMeanS + nrms*fRmsS, fMeanB + nrms*fRmsB ), fXmax );
1130
1131 // determine cut orientation
1132 fCutOrientation = (fMeanS > fMeanB) ? kPositive : kNegative;
1133
1134 // fill 2 types of histograms for the various analyses
1135 // this one is for actual plotting
1136
1137 Double_t sxmax = fXmax+0.00001;
1138
1139 // classifier response distributions for training sample
1140 // MVA plots used for graphics representation (signal)
1142 if(IsSilentFile()) {
1143 TestvarName = TString::Format("[%s]%s",DataInfo().GetName(),GetTestvarName().Data());
1144 } else {
1145 TestvarName=GetTestvarName();
1146 }
1147 TH1* mva_s = new TH1D( TestvarName + "_S",TestvarName + "_S", fNbinsMVAoutput, fXmin, sxmax );
1148 TH1* mva_b = new TH1D( TestvarName + "_B",TestvarName + "_B", fNbinsMVAoutput, fXmin, sxmax );
1149 mvaRes->Store(mva_s, "MVA_S");
1150 mvaRes->Store(mva_b, "MVA_B");
1151 mva_s->Sumw2();
1152 mva_b->Sumw2();
1153
1154 TH1* proba_s = 0;
1155 TH1* proba_b = 0;
1156 TH1* rarity_s = 0;
1157 TH1* rarity_b = 0;
1158 if (HasMVAPdfs()) {
1159 // P(MVA) plots used for graphics representation
1160 proba_s = new TH1D( TestvarName + "_Proba_S", TestvarName + "_Proba_S", fNbinsMVAoutput, 0.0, 1.0 );
1161 proba_b = new TH1D( TestvarName + "_Proba_B", TestvarName + "_Proba_B", fNbinsMVAoutput, 0.0, 1.0 );
1162 mvaRes->Store(proba_s, "Prob_S");
1163 mvaRes->Store(proba_b, "Prob_B");
1164 proba_s->Sumw2();
1165 proba_b->Sumw2();
1166
1167 // R(MVA) plots used for graphics representation
1168 rarity_s = new TH1D( TestvarName + "_Rarity_S", TestvarName + "_Rarity_S", fNbinsMVAoutput, 0.0, 1.0 );
1169 rarity_b = new TH1D( TestvarName + "_Rarity_B", TestvarName + "_Rarity_B", fNbinsMVAoutput, 0.0, 1.0 );
1170 mvaRes->Store(rarity_s, "Rar_S");
1171 mvaRes->Store(rarity_b, "Rar_B");
1172 rarity_s->Sumw2();
1173 rarity_b->Sumw2();
1174 }
1175
1176 // MVA plots used for efficiency calculations (large number of bins)
1177 TH1* mva_eff_s = new TH1D( TestvarName + "_S_high", TestvarName + "_S_high", fNbinsH, fXmin, sxmax );
1178 TH1* mva_eff_b = new TH1D( TestvarName + "_B_high", TestvarName + "_B_high", fNbinsH, fXmin, sxmax );
1179 mvaRes->Store(mva_eff_s, "MVA_HIGHBIN_S");
1180 mvaRes->Store(mva_eff_b, "MVA_HIGHBIN_B");
1181 mva_eff_s->Sumw2();
1182 mva_eff_b->Sumw2();
1183
1184 // fill the histograms
1185
1187 (Data()->GetResults( TString("prob_")+GetMethodName(), Types::kTesting, Types::kMaxAnalysisType ) );
1188
1189 Log() << kHEADER <<Form("[%s] : ",DataInfo().GetName())<< "Loop over test events and fill histograms with classifier response..." << Endl << Endl;
1190 if (mvaProb) Log() << kINFO << "Also filling probability and rarity histograms (on request)..." << Endl;
1191 //std::vector<Bool_t>* mvaResTypes = mvaRes->GetValueVectorTypes();
1192
1193 //LM: this is needed to avoid crashes in ROOCCURVE
1194 if ( mvaRes->GetSize() != GetNEvents() ) {
1195 Log() << kFATAL << TString::Format("Inconsistent result size %lld with number of events %u ", mvaRes->GetSize() , GetNEvents() ) << Endl;
1196 assert(mvaRes->GetSize() == GetNEvents());
1197 }
1198
1199 for (Long64_t ievt=0; ievt<GetNEvents(); ievt++) {
1200
1201 const Event* ev = GetEvent(ievt);
1202 Float_t v = (*mvaRes)[ievt][0];
1203 Float_t w = ev->GetWeight();
1204
1205 if (DataInfo().IsSignal(ev)) {
1206 //mvaResTypes->push_back(kTRUE);
1207 mva_s ->Fill( v, w );
1208 if (mvaProb) {
1209 proba_s->Fill( (*mvaProb)[ievt][0], w );
1210 rarity_s->Fill( GetRarity( v ), w );
1211 }
1212
1213 mva_eff_s ->Fill( v, w );
1214 }
1215 else {
1216 //mvaResTypes->push_back(kFALSE);
1217 mva_b ->Fill( v, w );
1218 if (mvaProb) {
1219 proba_b->Fill( (*mvaProb)[ievt][0], w );
1220 rarity_b->Fill( GetRarity( v ), w );
1221 }
1222 mva_eff_b ->Fill( v, w );
1223 }
1224 }
1225
1226 // uncomment those (and several others if you want unnormalized output
1227 gTools().NormHist( mva_s );
1228 gTools().NormHist( mva_b );
1229 gTools().NormHist( proba_s );
1230 gTools().NormHist( proba_b );
1235
1236 // create PDFs from histograms, using default splines, and no additional smoothing
1237 if (fSplS) { delete fSplS; fSplS = 0; }
1238 if (fSplB) { delete fSplB; fSplB = 0; }
1239 fSplS = new PDF( TString(GetName()) + " PDF Sig", mva_s, PDF::kSpline2 );
1240 fSplB = new PDF( TString(GetName()) + " PDF Bkg", mva_b, PDF::kSpline2 );
1241}
1242
1243////////////////////////////////////////////////////////////////////////////////
1244/// general method used in writing the header of the weight files where
1245/// the used variables, variable transformation type etc. is specified
1246
1247void TMVA::MethodBase::WriteStateToStream( std::ostream& tf ) const
1248{
1249 TString prefix = "";
1251
1252 tf << prefix << "#GEN -*-*-*-*-*-*-*-*-*-*-*- general info -*-*-*-*-*-*-*-*-*-*-*-" << std::endl << prefix << std::endl;
1253 tf << prefix << "Method : " << GetMethodTypeName() << "::" << GetMethodName() << std::endl;
1254 tf.setf(std::ios::left);
1255 tf << prefix << "TMVA Release : " << std::setw(10) << GetTrainingTMVAVersionString() << " ["
1256 << GetTrainingTMVAVersionCode() << "]" << std::endl;
1257 tf << prefix << "ROOT Release : " << std::setw(10) << GetTrainingROOTVersionString() << " ["
1258 << GetTrainingROOTVersionCode() << "]" << std::endl;
1259 tf << prefix << "Creator : " << userInfo->fUser << std::endl;
1260 tf << prefix << "Date : "; TDatime *d = new TDatime; tf << d->AsString() << std::endl; delete d;
1261 tf << prefix << "Host : " << gSystem->GetBuildNode() << std::endl;
1262 tf << prefix << "Dir : " << gSystem->WorkingDirectory() << std::endl;
1263 tf << prefix << "Training events: " << Data()->GetNTrainingEvents() << std::endl;
1264
1265 TString analysisType(((const_cast<TMVA::MethodBase*>(this)->GetAnalysisType()==Types::kRegression) ? "Regression" : "Classification"));
1266
1267 tf << prefix << "Analysis type : " << "[" << ((GetAnalysisType()==Types::kRegression) ? "Regression" : "Classification") << "]" << std::endl;
1268 tf << prefix << std::endl;
1269
1270 delete userInfo;
1271
1272 // First write all options
1273 tf << prefix << std::endl << prefix << "#OPT -*-*-*-*-*-*-*-*-*-*-*-*- options -*-*-*-*-*-*-*-*-*-*-*-*-" << std::endl << prefix << std::endl;
1274 WriteOptionsToStream( tf, prefix );
1275 tf << prefix << std::endl;
1276
1277 // Second write variable info
1278 tf << prefix << std::endl << prefix << "#VAR -*-*-*-*-*-*-*-*-*-*-*-* variables *-*-*-*-*-*-*-*-*-*-*-*-" << std::endl << prefix << std::endl;
1279 WriteVarsToStream( tf, prefix );
1280 tf << prefix << std::endl;
1281}
1282
1283////////////////////////////////////////////////////////////////////////////////
1284/// xml writing
1285
1286void TMVA::MethodBase::AddInfoItem( void* gi, const TString& name, const TString& value) const
1287{
1288 void* it = gTools().AddChild(gi,"Info");
1289 gTools().AddAttr(it,"name", name);
1290 gTools().AddAttr(it,"value", value);
1291}
1292
1293////////////////////////////////////////////////////////////////////////////////
1294
1296 if (analysisType == Types::kRegression) {
1297 AddRegressionOutput( type );
1298 } else if (analysisType == Types::kMulticlass) {
1299 AddMulticlassOutput( type );
1300 } else {
1301 AddClassifierOutput( type );
1302 if (HasMVAPdfs())
1303 AddClassifierOutputProb( type );
1304 }
1305}
1306
1307////////////////////////////////////////////////////////////////////////////////
1308/// general method used in writing the header of the weight files where
1309/// the used variables, variable transformation type etc. is specified
1310
1311void TMVA::MethodBase::WriteStateToXML( void* parent ) const
1312{
1313 if (!parent) return;
1314
1316
1317 void* gi = gTools().AddChild(parent, "GeneralInfo");
1318 AddInfoItem( gi, "TMVA Release", GetTrainingTMVAVersionString() + " [" + gTools().StringFromInt(GetTrainingTMVAVersionCode()) + "]" );
1319 AddInfoItem( gi, "ROOT Release", GetTrainingROOTVersionString() + " [" + gTools().StringFromInt(GetTrainingROOTVersionCode()) + "]");
1320 AddInfoItem( gi, "Creator", userInfo->fUser);
1321 TDatime dt; AddInfoItem( gi, "Date", dt.AsString());
1322 AddInfoItem( gi, "Host", gSystem->GetBuildNode() );
1323 AddInfoItem( gi, "Dir", gSystem->WorkingDirectory());
1324 AddInfoItem( gi, "Training events", gTools().StringFromInt(Data()->GetNTrainingEvents()));
1325 AddInfoItem( gi, "TrainingTime", gTools().StringFromDouble(const_cast<TMVA::MethodBase*>(this)->GetTrainTime()));
1326
1327 Types::EAnalysisType aType = const_cast<TMVA::MethodBase*>(this)->GetAnalysisType();
1328 TString analysisType((aType==Types::kRegression) ? "Regression" :
1329 (aType==Types::kMulticlass ? "Multiclass" : "Classification"));
1330 AddInfoItem( gi, "AnalysisType", analysisType );
1331 delete userInfo;
1332
1333 // write options
1334 AddOptionsXMLTo( parent );
1335
1336 // write variable info
1337 AddVarsXMLTo( parent );
1338
1339 // write spectator info
1340 if (fModelPersistence)
1341 AddSpectatorsXMLTo( parent );
1342
1343 // write class info if in multiclass mode
1344 AddClassesXMLTo(parent);
1345
1346 // write target info if in regression mode
1347 if (DoRegression()) AddTargetsXMLTo(parent);
1348
1349 // write transformations
1350 GetTransformationHandler(false).AddXMLTo( parent );
1351
1352 // write MVA variable distributions
1353 void* pdfs = gTools().AddChild(parent, "MVAPdfs");
1354 if (fMVAPdfS) fMVAPdfS->AddXMLTo(pdfs);
1355 if (fMVAPdfB) fMVAPdfB->AddXMLTo(pdfs);
1356
1357 // write weights
1358 AddWeightsXMLTo( parent );
1359}
1360
1361////////////////////////////////////////////////////////////////////////////////
1362/// write reference MVA distributions (and other information)
1363/// to a ROOT type weight file
1364
1366{
1367 TDirectory::TContext dirCtx{nullptr}; // Don't register histograms to current directory
1368 fMVAPdfS = (TMVA::PDF*)rf.Get( "MVA_PDF_Signal" );
1369 fMVAPdfB = (TMVA::PDF*)rf.Get( "MVA_PDF_Background" );
1370
1371 ReadWeightsFromStream( rf );
1372
1373 SetTestvarName();
1374}
1375
1376////////////////////////////////////////////////////////////////////////////////
1377/// write options and weights to file
1378/// note that each one text file for the main configuration information
1379/// and one ROOT file for ROOT objects are created
1380
1382{
1383 // ---- create the text file
1384 TString tfname( GetWeightFileName() );
1385
1386 // writing xml file
1387 TString xmlfname( tfname ); xmlfname.ReplaceAll( ".txt", ".xml" );
1388 Log() << kINFO //<<Form("Dataset[%s] : ",DataInfo().GetName())
1389 << "Creating xml weight file: "
1390 << gTools().Color("lightblue") << xmlfname << gTools().Color("reset") << Endl;
1391 void* doc = gTools().xmlengine().NewDoc();
1392 void* rootnode = gTools().AddChild(0,"MethodSetup", "", true);
1393 gTools().xmlengine().DocSetRootElement(doc,rootnode);
1394 gTools().AddAttr(rootnode,"Method", GetMethodTypeName() + "::" + GetMethodName());
1395 WriteStateToXML(rootnode);
1398}
1399
1400////////////////////////////////////////////////////////////////////////////////
1401/// Function to write options and weights to file
1402
1404{
1405 // get the filename
1406
1407 TString tfname(GetWeightFileName());
1408
1409 Log() << kINFO //<<Form("Dataset[%s] : ",DataInfo().GetName())
1410 << "Reading weight file: "
1411 << gTools().Color("lightblue") << tfname << gTools().Color("reset") << Endl;
1412
1413 if (tfname.EndsWith(".xml") ) {
1414 void* doc = gTools().xmlengine().ParseFile(tfname,gTools().xmlenginebuffersize()); // the default buffer size in TXMLEngine::ParseFile is 100k. Starting with ROOT 5.29 one can set the buffer size, see: http://savannah.cern.ch/bugs/?78864. This might be necessary for large XML files
1415 if (!doc) {
1416 Log() << kFATAL << "Error parsing XML file " << tfname << Endl;
1417 }
1418 void* rootnode = gTools().xmlengine().DocGetRootElement(doc); // node "MethodSetup"
1419 ReadStateFromXML(rootnode);
1421 }
1422 else {
1423 std::filebuf fb;
1424 fb.open(tfname.Data(),std::ios::in);
1425 if (!fb.is_open()) { // file not found --> Error
1426 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<ReadStateFromFile> "
1427 << "Unable to open input weight file: " << tfname << Endl;
1428 }
1429 std::istream fin(&fb);
1430 ReadStateFromStream(fin);
1431 fb.close();
1432 }
1433 if (!fTxtWeightsOnly) {
1434 // ---- read the ROOT file
1435 TString rfname( tfname ); rfname.ReplaceAll( ".txt", ".root" );
1436 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Reading root weight file: "
1437 << gTools().Color("lightblue") << rfname << gTools().Color("reset") << Endl;
1438 TFile* rfile = TFile::Open( rfname, "READ" );
1439 ReadStateFromStream( *rfile );
1440 rfile->Close();
1441 }
1442}
1443////////////////////////////////////////////////////////////////////////////////
1444/// for reading from memory
1445
1447 void* doc = gTools().xmlengine().ParseString(xmlstr);
1448 void* rootnode = gTools().xmlengine().DocGetRootElement(doc); // node "MethodSetup"
1449 ReadStateFromXML(rootnode);
1451
1452 return;
1453}
1454
1455////////////////////////////////////////////////////////////////////////////////
1456
1458{
1459
1461 gTools().ReadAttr( methodNode, "Method", fullMethodName );
1462
1463 fMethodName = fullMethodName(fullMethodName.Index("::")+2,fullMethodName.Length());
1464
1465 // update logger
1466 Log().SetSource( GetName() );
1467 Log() << kDEBUG//<<Form("Dataset[%s] : ",DataInfo().GetName())
1468 << "Read method \"" << GetMethodName() << "\" of type \"" << GetMethodTypeName() << "\"" << Endl;
1469
1470 // after the method name is read, the testvar can be set
1471 SetTestvarName();
1472
1473 TString nodeName("");
1474 void* ch = gTools().GetChild(methodNode);
1475 while (ch!=0) {
1476 nodeName = TString( gTools().GetName(ch) );
1477
1478 if (nodeName=="GeneralInfo") {
1479 // read analysis type
1480
1481 TString name(""),val("");
1482 void* antypeNode = gTools().GetChild(ch);
1483 while (antypeNode) {
1484 gTools().ReadAttr( antypeNode, "name", name );
1485
1486 if (name == "TrainingTime")
1487 gTools().ReadAttr( antypeNode, "value", fTrainTime );
1488
1489 if (name == "AnalysisType") {
1490 gTools().ReadAttr( antypeNode, "value", val );
1491 val.ToLower();
1492 if (val == "regression" ) SetAnalysisType( Types::kRegression );
1493 else if (val == "classification" ) SetAnalysisType( Types::kClassification );
1494 else if (val == "multiclass" ) SetAnalysisType( Types::kMulticlass );
1495 else Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Analysis type " << val << " is not known." << Endl;
1496 }
1497
1498 if (name == "TMVA Release" || name == "TMVA") {
1499 TString s;
1500 gTools().ReadAttr( antypeNode, "value", s);
1501 fTMVATrainingVersion = TString(s(s.Index("[")+1,s.Index("]")-s.Index("[")-1)).Atoi();
1502 Log() << kDEBUG <<Form("[%s] : ",DataInfo().GetName()) << "MVA method was trained with TMVA Version: " << GetTrainingTMVAVersionString() << Endl;
1503 }
1504
1505 if (name == "ROOT Release" || name == "ROOT") {
1506 TString s;
1507 gTools().ReadAttr( antypeNode, "value", s);
1508 fROOTTrainingVersion = TString(s(s.Index("[")+1,s.Index("]")-s.Index("[")-1)).Atoi();
1509 Log() << kDEBUG //<<Form("Dataset[%s] : ",DataInfo().GetName())
1510 << "MVA method was trained with ROOT Version: " << GetTrainingROOTVersionString() << Endl;
1511 }
1513 }
1514 }
1515 else if (nodeName=="Options") {
1516 ReadOptionsFromXML(ch);
1517 ParseOptions();
1518
1519 }
1520 else if (nodeName=="Variables") {
1521 ReadVariablesFromXML(ch);
1522 }
1523 else if (nodeName=="Spectators") {
1524 ReadSpectatorsFromXML(ch);
1525 }
1526 else if (nodeName=="Classes") {
1527 if (DataInfo().GetNClasses()==0) ReadClassesFromXML(ch);
1528 }
1529 else if (nodeName=="Targets") {
1530 if (DataInfo().GetNTargets()==0 && DoRegression()) ReadTargetsFromXML(ch);
1531 }
1532 else if (nodeName=="Transformations") {
1533 GetTransformationHandler().ReadFromXML(ch);
1534 }
1535 else if (nodeName=="MVAPdfs") {
1537 if (fMVAPdfS) { delete fMVAPdfS; fMVAPdfS=0; }
1538 if (fMVAPdfB) { delete fMVAPdfB; fMVAPdfB=0; }
1539 void* pdfnode = gTools().GetChild(ch);
1540 if (pdfnode) {
1541 gTools().ReadAttr(pdfnode, "Name", pdfname);
1542 fMVAPdfS = new PDF(pdfname);
1543 fMVAPdfS->ReadXML(pdfnode);
1545 gTools().ReadAttr(pdfnode, "Name", pdfname);
1546 fMVAPdfB = new PDF(pdfname);
1547 fMVAPdfB->ReadXML(pdfnode);
1548 }
1549 }
1550 else if (nodeName=="Weights") {
1551 ReadWeightsFromXML(ch);
1552 }
1553 else {
1554 Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Unparsed XML node: '" << nodeName << "'" << Endl;
1555 }
1556 ch = gTools().GetNextChild(ch);
1557
1558 }
1559
1560 // update transformation handler
1561 if (GetTransformationHandler().GetCallerName() == "") GetTransformationHandler().SetCallerName( GetName() );
1562}
1563
1564////////////////////////////////////////////////////////////////////////////////
1565/// read the header from the weight files of the different MVA methods
1566
1568{
1569 char buf[512];
1570
1571 // when reading from stream, we assume the files are produced with TMVA<=397
1572 SetAnalysisType(Types::kClassification);
1573
1574
1575 // first read the method name
1576 GetLine(fin,buf);
1577 while (!TString(buf).BeginsWith("Method")) GetLine(fin,buf);
1578 TString namestr(buf);
1579
1580 TString methodType = namestr(0,namestr.Index("::"));
1581 methodType = methodType(methodType.Last(' '),methodType.Length());
1583
1584 TString methodName = namestr(namestr.Index("::")+2,namestr.Length());
1585 methodName = methodName.Strip(TString::kLeading);
1586 if (methodName == "") methodName = methodType;
1587 fMethodName = methodName;
1588
1589 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Read method \"" << GetMethodName() << "\" of type \"" << GetMethodTypeName() << "\"" << Endl;
1590
1591 // update logger
1592 Log().SetSource( GetName() );
1593
1594 // now the question is whether to read the variables first or the options (well, of course the order
1595 // of writing them needs to agree)
1596 //
1597 // the option "Decorrelation" is needed to decide if the variables we
1598 // read are decorrelated or not
1599 //
1600 // the variables are needed by some methods (TMLP) to build the NN
1601 // which is done in ProcessOptions so for the time being we first Read and Parse the options then
1602 // we read the variables, and then we process the options
1603
1604 // now read all options
1605 GetLine(fin,buf);
1606 while (!TString(buf).BeginsWith("#OPT")) GetLine(fin,buf);
1607 ReadOptionsFromStream(fin);
1608 ParseOptions();
1609
1610 // Now read variable info
1611 fin.getline(buf,512);
1612 while (!TString(buf).BeginsWith("#VAR")) fin.getline(buf,512);
1613 ReadVarsFromStream(fin);
1614
1615 // now we process the options (of the derived class)
1616 ProcessOptions();
1617
1618 if (IsNormalised()) {
1620 GetTransformationHandler().AddTransformation( new VariableNormalizeTransform(DataInfo()), -1 );
1621 norm->BuildTransformationFromVarInfo( DataInfo().GetVariableInfos() );
1622 }
1624 if ( fVarTransformString == "None") {
1625 if (fUseDecorr)
1626 varTrafo = GetTransformationHandler().AddTransformation( new VariableDecorrTransform(DataInfo()), -1 );
1627 } else if ( fVarTransformString == "Decorrelate" ) {
1628 varTrafo = GetTransformationHandler().AddTransformation( new VariableDecorrTransform(DataInfo()), -1 );
1629 } else if ( fVarTransformString == "PCA" ) {
1630 varTrafo = GetTransformationHandler().AddTransformation( new VariablePCATransform(DataInfo()), -1 );
1631 } else if ( fVarTransformString == "Uniform" ) {
1632 varTrafo = GetTransformationHandler().AddTransformation( new VariableGaussTransform(DataInfo(),"Uniform"), -1 );
1633 } else if ( fVarTransformString == "Gauss" ) {
1634 varTrafo = GetTransformationHandler().AddTransformation( new VariableGaussTransform(DataInfo()), -1 );
1635 } else if ( fVarTransformString == "GaussDecorr" ) {
1636 varTrafo = GetTransformationHandler().AddTransformation( new VariableGaussTransform(DataInfo()), -1 );
1637 varTrafo2 = GetTransformationHandler().AddTransformation( new VariableDecorrTransform(DataInfo()), -1 );
1638 } else {
1639 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<ProcessOptions> Variable transform '"
1640 << fVarTransformString << "' unknown." << Endl;
1641 }
1642 // Now read decorrelation matrix if available
1643 if (GetTransformationHandler().GetTransformationList().GetSize() > 0) {
1644 fin.getline(buf,512);
1645 while (!TString(buf).BeginsWith("#MAT")) fin.getline(buf,512);
1646 if (varTrafo) {
1647 TString trafo(fVariableTransformTypeString); trafo.ToLower();
1648 varTrafo->ReadTransformationFromStream(fin, trafo );
1649 }
1650 if (varTrafo2) {
1651 TString trafo(fVariableTransformTypeString); trafo.ToLower();
1652 varTrafo2->ReadTransformationFromStream(fin, trafo );
1653 }
1654 }
1655
1656
1657 if (HasMVAPdfs()) {
1658 // Now read the MVA PDFs
1659 fin.getline(buf,512);
1660 while (!TString(buf).BeginsWith("#MVAPDFS")) fin.getline(buf,512);
1661 if (fMVAPdfS != 0) { delete fMVAPdfS; fMVAPdfS = 0; }
1662 if (fMVAPdfB != 0) { delete fMVAPdfB; fMVAPdfB = 0; }
1663 fMVAPdfS = new PDF(TString(GetName()) + " MVA PDF Sig");
1664 fMVAPdfB = new PDF(TString(GetName()) + " MVA PDF Bkg");
1665 fMVAPdfS->SetReadingVersion( GetTrainingTMVAVersionCode() );
1666 fMVAPdfB->SetReadingVersion( GetTrainingTMVAVersionCode() );
1667
1668 fin >> *fMVAPdfS;
1669 fin >> *fMVAPdfB;
1670 }
1671
1672 // Now read weights
1673 fin.getline(buf,512);
1674 while (!TString(buf).BeginsWith("#WGT")) fin.getline(buf,512);
1675 fin.getline(buf,512);
1676 ReadWeightsFromStream( fin );
1677
1678 // update transformation handler
1679 if (GetTransformationHandler().GetCallerName() == "") GetTransformationHandler().SetCallerName( GetName() );
1680
1681}
1682
1683////////////////////////////////////////////////////////////////////////////////
1684/// write the list of variables (name, min, max) for a given data
1685/// transformation method to the stream
1686
1687void TMVA::MethodBase::WriteVarsToStream( std::ostream& o, const TString& prefix ) const
1688{
1689 o << prefix << "NVar " << DataInfo().GetNVariables() << std::endl;
1690 std::vector<VariableInfo>::const_iterator varIt = DataInfo().GetVariableInfos().begin();
1691 for (; varIt!=DataInfo().GetVariableInfos().end(); ++varIt) { o << prefix; varIt->WriteToStream(o); }
1692 o << prefix << "NSpec " << DataInfo().GetNSpectators() << std::endl;
1693 varIt = DataInfo().GetSpectatorInfos().begin();
1694 for (; varIt!=DataInfo().GetSpectatorInfos().end(); ++varIt) { o << prefix; varIt->WriteToStream(o); }
1695}
1696
1697////////////////////////////////////////////////////////////////////////////////
1698/// Read the variables (name, min, max) for a given data
1699/// transformation method from the stream. In the stream we only
1700/// expect the limits which will be set
1701
1703{
1704 TString dummy;
1706 istr >> dummy >> readNVar;
1707
1708 if (readNVar!=DataInfo().GetNVariables()) {
1709 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "You declared "<< DataInfo().GetNVariables() << " variables in the Reader"
1710 << " while there are " << readNVar << " variables declared in the file"
1711 << Endl;
1712 }
1713
1714 // we want to make sure all variables are read in the order they are defined
1716 std::vector<VariableInfo>::iterator varIt = DataInfo().GetVariableInfos().begin();
1717 int varIdx = 0;
1718 for (; varIt!=DataInfo().GetVariableInfos().end(); ++varIt, ++varIdx) {
1719 varInfo.ReadFromStream(istr);
1720 if (varIt->GetExpression() == varInfo.GetExpression()) {
1721 varInfo.SetExternalLink((*varIt).GetExternalLink());
1722 (*varIt) = varInfo;
1723 }
1724 else {
1725 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "ERROR in <ReadVarsFromStream>" << Endl;
1726 Log() << kINFO << "The definition (or the order) of the variables found in the input file is" << Endl;
1727 Log() << kINFO << "is not the same as the one declared in the Reader (which is necessary for" << Endl;
1728 Log() << kINFO << "the correct working of the method):" << Endl;
1729 Log() << kINFO << " var #" << varIdx <<" declared in Reader: " << varIt->GetExpression() << Endl;
1730 Log() << kINFO << " var #" << varIdx <<" declared in file : " << varInfo.GetExpression() << Endl;
1731 Log() << kFATAL << "The expression declared to the Reader needs to be checked (name or order are wrong)" << Endl;
1732 }
1733 }
1734}
1735
1736////////////////////////////////////////////////////////////////////////////////
1737/// write variable info to XML
1738
1739void TMVA::MethodBase::AddVarsXMLTo( void* parent ) const
1740{
1741 void* vars = gTools().AddChild(parent, "Variables");
1742 gTools().AddAttr( vars, "NVar", gTools().StringFromInt(DataInfo().GetNVariables()) );
1743
1744 for (UInt_t idx=0; idx<DataInfo().GetVariableInfos().size(); idx++) {
1745 VariableInfo& vi = DataInfo().GetVariableInfos()[idx];
1746 void* var = gTools().AddChild( vars, "Variable" );
1747 gTools().AddAttr( var, "VarIndex", idx );
1748 vi.AddToXML( var );
1749 }
1750}
1751
1752////////////////////////////////////////////////////////////////////////////////
1753/// write spectator info to XML
1754
1756{
1757 void* specs = gTools().AddChild(parent, "Spectators");
1758
1759 UInt_t writeIdx=0;
1760 for (UInt_t idx=0; idx<DataInfo().GetSpectatorInfos().size(); idx++) {
1761
1762 VariableInfo& vi = DataInfo().GetSpectatorInfos()[idx];
1763
1764 // we do not want to write spectators that are category-cuts,
1765 // except if the method is the category method and the spectators belong to it
1766 if (vi.GetVarType()=='C') continue;
1767
1768 void* spec = gTools().AddChild( specs, "Spectator" );
1769 gTools().AddAttr( spec, "SpecIndex", writeIdx++ );
1770 vi.AddToXML( spec );
1771 }
1772 gTools().AddAttr( specs, "NSpec", gTools().StringFromInt(writeIdx) );
1773}
1774
1775////////////////////////////////////////////////////////////////////////////////
1776/// write class info to XML
1777
1778void TMVA::MethodBase::AddClassesXMLTo( void* parent ) const
1779{
1780 UInt_t nClasses=DataInfo().GetNClasses();
1781
1782 void* classes = gTools().AddChild(parent, "Classes");
1783 gTools().AddAttr( classes, "NClass", nClasses );
1784
1785 for (UInt_t iCls=0; iCls<nClasses; ++iCls) {
1786 ClassInfo *classInfo=DataInfo().GetClassInfo (iCls);
1787 TString className =classInfo->GetName();
1788 UInt_t classNumber=classInfo->GetNumber();
1789
1790 void* classNode=gTools().AddChild(classes, "Class");
1791 gTools().AddAttr( classNode, "Name", className );
1792 gTools().AddAttr( classNode, "Index", classNumber );
1793 }
1794}
1795////////////////////////////////////////////////////////////////////////////////
1796/// write target info to XML
1797
1798void TMVA::MethodBase::AddTargetsXMLTo( void* parent ) const
1799{
1800 void* targets = gTools().AddChild(parent, "Targets");
1801 gTools().AddAttr( targets, "NTrgt", gTools().StringFromInt(DataInfo().GetNTargets()) );
1802
1803 for (UInt_t idx=0; idx<DataInfo().GetTargetInfos().size(); idx++) {
1804 VariableInfo& vi = DataInfo().GetTargetInfos()[idx];
1805 void* tar = gTools().AddChild( targets, "Target" );
1806 gTools().AddAttr( tar, "TargetIndex", idx );
1807 vi.AddToXML( tar );
1808 }
1809}
1810
1811////////////////////////////////////////////////////////////////////////////////
1812/// read variable info from XML
1813
1815{
1817 gTools().ReadAttr( varnode, "NVar", readNVar);
1818
1819 if (readNVar!=DataInfo().GetNVariables()) {
1820 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "You declared "<< DataInfo().GetNVariables() << " variables in the Reader"
1821 << " while there are " << readNVar << " variables declared in the file"
1822 << Endl;
1823 }
1824
1825 // we want to make sure all variables are read in the order they are defined
1827 int varIdx = 0;
1828 void* ch = gTools().GetChild(varnode);
1829 while (ch) {
1830 gTools().ReadAttr( ch, "VarIndex", varIdx);
1831 existingVarInfo = DataInfo().GetVariableInfos()[varIdx];
1832 readVarInfo.ReadFromXML(ch);
1833
1834 if (existingVarInfo.GetExpression() == readVarInfo.GetExpression()) {
1835 readVarInfo.SetExternalLink(existingVarInfo.GetExternalLink());
1837 }
1838 else {
1839 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "ERROR in <ReadVariablesFromXML>" << Endl;
1840 Log() << kINFO << "The definition (or the order) of the variables found in the input file is" << Endl;
1841 Log() << kINFO << "not the same as the one declared in the Reader (which is necessary for the" << Endl;
1842 Log() << kINFO << "correct working of the method):" << Endl;
1843 Log() << kINFO << " var #" << varIdx <<" declared in Reader: " << existingVarInfo.GetExpression() << Endl;
1844 Log() << kINFO << " var #" << varIdx <<" declared in file : " << readVarInfo.GetExpression() << Endl;
1845 Log() << kFATAL << "The expression declared to the Reader needs to be checked (name or order are wrong)" << Endl;
1846 }
1847 ch = gTools().GetNextChild(ch);
1848 }
1849}
1850
1851////////////////////////////////////////////////////////////////////////////////
1852/// read spectator info from XML
1853
1855{
1857 gTools().ReadAttr( specnode, "NSpec", readNSpec);
1858
1859 if (readNSpec!=DataInfo().GetNSpectators(kFALSE)) {
1860 Log() << kFATAL<<Form("Dataset[%s] : ",DataInfo().GetName()) << "You declared "<< DataInfo().GetNSpectators(kFALSE) << " spectators in the Reader"
1861 << " while there are " << readNSpec << " spectators declared in the file"
1862 << Endl;
1863 }
1864
1865 // we want to make sure all variables are read in the order they are defined
1867 int specIdx = 0;
1868 void* ch = gTools().GetChild(specnode);
1869 while (ch) {
1870 gTools().ReadAttr( ch, "SpecIndex", specIdx);
1871 existingSpecInfo = DataInfo().GetSpectatorInfos()[specIdx];
1872 readSpecInfo.ReadFromXML(ch);
1873
1874 if (existingSpecInfo.GetExpression() == readSpecInfo.GetExpression()) {
1875 readSpecInfo.SetExternalLink(existingSpecInfo.GetExternalLink());
1877 }
1878 else {
1879 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "ERROR in <ReadSpectatorsFromXML>" << Endl;
1880 Log() << kINFO << "The definition (or the order) of the spectators found in the input file is" << Endl;
1881 Log() << kINFO << "not the same as the one declared in the Reader (which is necessary for the" << Endl;
1882 Log() << kINFO << "correct working of the method):" << Endl;
1883 Log() << kINFO << " spec #" << specIdx <<" declared in Reader: " << existingSpecInfo.GetExpression() << Endl;
1884 Log() << kINFO << " spec #" << specIdx <<" declared in file : " << readSpecInfo.GetExpression() << Endl;
1885 Log() << kFATAL << "The expression declared to the Reader needs to be checked (name or order are wrong)" << Endl;
1886 }
1887 ch = gTools().GetNextChild(ch);
1888 }
1889}
1890
1891////////////////////////////////////////////////////////////////////////////////
1892/// read number of classes from XML
1893
1895{
1897 // coverity[tainted_data_argument]
1898 gTools().ReadAttr( clsnode, "NClass", readNCls);
1899
1900 TString className="";
1902 void* ch = gTools().GetChild(clsnode);
1903 if (!ch) {
1904 for (UInt_t icls = 0; icls<readNCls;++icls) {
1905 TString classname = TString::Format("class%i",icls);
1906 DataInfo().AddClass(classname);
1907
1908 }
1909 }
1910 else{
1911 while (ch) {
1912 gTools().ReadAttr( ch, "Index", classIndex);
1913 gTools().ReadAttr( ch, "Name", className );
1914 DataInfo().AddClass(className);
1915
1916 ch = gTools().GetNextChild(ch);
1917 }
1918 }
1919
1920 // retrieve signal and background class index
1921 if (DataInfo().GetClassInfo("Signal") != 0) {
1922 fSignalClass = DataInfo().GetClassInfo("Signal")->GetNumber();
1923 }
1924 else
1925 fSignalClass=0;
1926 if (DataInfo().GetClassInfo("Background") != 0) {
1927 fBackgroundClass = DataInfo().GetClassInfo("Background")->GetNumber();
1928 }
1929 else
1930 fBackgroundClass=1;
1931}
1932
1933////////////////////////////////////////////////////////////////////////////////
1934/// read target info from XML
1935
1937{
1939 gTools().ReadAttr( tarnode, "NTrgt", readNTar);
1940
1941 int tarIdx = 0;
1942 TString expression;
1943 void* ch = gTools().GetChild(tarnode);
1944 while (ch) {
1945 gTools().ReadAttr( ch, "TargetIndex", tarIdx);
1946 gTools().ReadAttr( ch, "Expression", expression);
1947 DataInfo().AddTarget(expression,"","",0,0);
1948
1949 ch = gTools().GetNextChild(ch);
1950 }
1951}
1952
1953////////////////////////////////////////////////////////////////////////////////
1954/// returns the ROOT directory where info/histograms etc of the
1955/// corresponding MVA method instance are stored
1956
1958{
1959 if (fBaseDir != 0) return fBaseDir;
1960 Log()<<kDEBUG<<Form("Dataset[%s] : ",DataInfo().GetName())<<" Base Directory for " << GetMethodName() << " not set yet --> check if already there.." <<Endl;
1961
1962 if (IsSilentFile()) {
1963 Log() << kFATAL << Form("Dataset[%s] : ", DataInfo().GetName())
1964 << "MethodBase::BaseDir() - No directory exists when running a Method without output file. Enable the "
1965 "output when creating the factory"
1966 << Endl;
1967 }
1968
1969 TDirectory* methodDir = MethodBaseDir();
1970 if (methodDir==0)
1971 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "MethodBase::BaseDir() - MethodBaseDir() return a NULL pointer!" << Endl;
1972
1973 TString defaultDir = GetMethodName();
1974 TDirectory *sdir = methodDir->GetDirectory(defaultDir.Data());
1975 if(!sdir)
1976 {
1977 Log()<<kDEBUG<<Form("Dataset[%s] : ",DataInfo().GetName())<<" Base Directory for " << GetMethodTypeName() << " does not exist yet--> created it" <<Endl;
1978 sdir = methodDir->mkdir(defaultDir);
1979 sdir->cd();
1980 // write weight file name into target file
1981 if (fModelPersistence) {
1983 TObjString wfileName( GetWeightFileName() );
1984 wfilePath.Write( "TrainingPath" );
1985 wfileName.Write( "WeightFileName" );
1986 }
1987 }
1988
1989 Log()<<kDEBUG<<Form("Dataset[%s] : ",DataInfo().GetName())<<" Base Directory for " << GetMethodTypeName() << " existed, return it.." <<Endl;
1990 return sdir;
1991}
1992
1993////////////////////////////////////////////////////////////////////////////////
1994/// returns the ROOT directory where all instances of the
1995/// corresponding MVA method are stored
1996
1998{
1999 if (fMethodBaseDir != 0) {
2000 return fMethodBaseDir;
2001 }
2002
2003 const char *datasetName = DataInfo().GetName();
2004
2005 Log() << kDEBUG << Form("Dataset[%s] : ", datasetName) << " Base Directory for " << GetMethodTypeName()
2006 << " not set yet --> check if already there.." << Endl;
2007
2008 TDirectory *factoryBaseDir = GetFile();
2009 if (!factoryBaseDir) return nullptr;
2010 fMethodBaseDir = factoryBaseDir->GetDirectory(datasetName);
2011 if (!fMethodBaseDir) {
2012 fMethodBaseDir = factoryBaseDir->mkdir(datasetName, TString::Format("Base directory for dataset %s", datasetName).Data());
2013 if (!fMethodBaseDir) {
2014 Log() << kFATAL << "Can not create dir " << datasetName;
2015 }
2016 }
2017 TString methodTypeDir = TString::Format("Method_%s", GetMethodTypeName().Data());
2018 fMethodBaseDir = fMethodBaseDir->GetDirectory(methodTypeDir.Data());
2019
2020 if (!fMethodBaseDir) {
2022 TString methodTypeDirHelpStr = TString::Format("Directory for all %s methods", GetMethodTypeName().Data());
2023 fMethodBaseDir = datasetDir->mkdir(methodTypeDir.Data(), methodTypeDirHelpStr);
2024 Log() << kDEBUG << Form("Dataset[%s] : ", datasetName) << " Base Directory for " << GetMethodName()
2025 << " does not exist yet--> created it" << Endl;
2026 }
2027
2028 Log() << kDEBUG << Form("Dataset[%s] : ", datasetName)
2029 << "Return from MethodBaseDir() after creating base directory " << Endl;
2030 return fMethodBaseDir;
2031}
2032
2033////////////////////////////////////////////////////////////////////////////////
2034/// set directory of weight file
2035
2037{
2038 fFileDir = fileDir;
2039 gSystem->mkdir( fFileDir, kTRUE );
2040}
2041
2042////////////////////////////////////////////////////////////////////////////////
2043/// set the weight file name (depreciated)
2044
2049
2050////////////////////////////////////////////////////////////////////////////////
2051/// retrieve weight file name
2052
2054{
2055 if (fWeightFile!="") return fWeightFile;
2056
2057 // the default consists of
2058 // directory/jobname_methodname_suffix.extension.{root/txt}
2059 TString suffix = "";
2060 TString wFileDir(GetWeightFileDir());
2061 TString wFileName = GetJobName() + "_" + GetMethodName() +
2062 suffix + "." + gConfig().GetIONames().fWeightFileExtension + ".xml";
2063 if (wFileDir.IsNull() ) return wFileName;
2064 // add weight file directory of it is not null
2065 return ( wFileDir + (wFileDir[wFileDir.Length()-1]=='/' ? "" : "/")
2066 + wFileName );
2067}
2068////////////////////////////////////////////////////////////////////////////////
2069/// writes all MVA evaluation histograms to file
2070
2072{
2073 BaseDir()->cd();
2074
2075
2076 // write MVA PDFs to file - if exist
2077 if (0 != fMVAPdfS) {
2078 fMVAPdfS->GetOriginalHist()->Write();
2079 fMVAPdfS->GetSmoothedHist()->Write();
2080 fMVAPdfS->GetPDFHist()->Write();
2081 }
2082 if (0 != fMVAPdfB) {
2083 fMVAPdfB->GetOriginalHist()->Write();
2084 fMVAPdfB->GetSmoothedHist()->Write();
2085 fMVAPdfB->GetPDFHist()->Write();
2086 }
2087
2088 // write result-histograms
2089 Results* results = Data()->GetResults( GetMethodName(), treetype, Types::kMaxAnalysisType );
2090 if (!results)
2091 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<WriteEvaluationHistosToFile> Unknown result: "
2092 << GetMethodName() << (treetype==Types::kTraining?"/kTraining":"/kTesting")
2093 << "/kMaxAnalysisType" << Endl;
2094 results->GetStorage()->Write();
2096 // skipping plotting of variables if too many (default is 200)
2097 if ((int) DataInfo().GetNVariables()< gConfig().GetVariablePlotting().fMaxNumOfAllowedVariables)
2098 GetTransformationHandler().PlotVariables (GetEventCollection( Types::kTesting ), BaseDir() );
2099 else
2100 Log() << kINFO << TString::Format("Dataset[%s] : ",DataInfo().GetName())
2101 << " variable plots are not produces ! The number of variables is " << DataInfo().GetNVariables()
2102 << " , it is larger than " << gConfig().GetVariablePlotting().fMaxNumOfAllowedVariables << Endl;
2103 }
2104}
2105
2106////////////////////////////////////////////////////////////////////////////////
2107/// write special monitoring histograms to file
2108/// dummy implementation here -----------------
2109
2113
2114////////////////////////////////////////////////////////////////////////////////
2115/// reads one line from the input stream
2116/// checks for certain keywords and interprets
2117/// the line if keywords are found
2118
2119Bool_t TMVA::MethodBase::GetLine(std::istream& fin, char* buf )
2120{
2121 fin.getline(buf,512);
2122 TString line(buf);
2123 if (line.BeginsWith("TMVA Release")) {
2124 Ssiz_t start = line.First('[')+1;
2125 Ssiz_t length = line.Index("]",start)-start;
2126 TString code = line(start,length);
2127 std::stringstream s(code.Data());
2128 s >> fTMVATrainingVersion;
2129 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "MVA method was trained with TMVA Version: " << GetTrainingTMVAVersionString() << Endl;
2130 }
2131 if (line.BeginsWith("ROOT Release")) {
2132 Ssiz_t start = line.First('[')+1;
2133 Ssiz_t length = line.Index("]",start)-start;
2134 TString code = line(start,length);
2135 std::stringstream s(code.Data());
2136 s >> fROOTTrainingVersion;
2137 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "MVA method was trained with ROOT Version: " << GetTrainingROOTVersionString() << Endl;
2138 }
2139 if (line.BeginsWith("Analysis type")) {
2140 Ssiz_t start = line.First('[')+1;
2141 Ssiz_t length = line.Index("]",start)-start;
2142 TString code = line(start,length);
2143 std::stringstream s(code.Data());
2144 std::string analysisType;
2145 s >> analysisType;
2146 if (analysisType == "regression" || analysisType == "Regression") SetAnalysisType( Types::kRegression );
2147 else if (analysisType == "classification" || analysisType == "Classification") SetAnalysisType( Types::kClassification );
2148 else if (analysisType == "multiclass" || analysisType == "Multiclass") SetAnalysisType( Types::kMulticlass );
2149 else Log() << kFATAL << "Analysis type " << analysisType << " from weight-file not known!" << std::endl;
2150
2151 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Method was trained for "
2152 << (GetAnalysisType() == Types::kRegression ? "Regression" :
2153 (GetAnalysisType() == Types::kMulticlass ? "Multiclass" : "Classification")) << Endl;
2154 }
2155
2156 return true;
2157}
2158
2159////////////////////////////////////////////////////////////////////////////////
2160/// Create PDFs of the MVA output variables
2161
2163{
2164 Data()->SetCurrentType(Types::kTraining);
2165
2166 // the PDF's are stored as results ONLY if the corresponding "results" are booked,
2167 // otherwise they will be only used 'online'
2169 ( Data()->GetResults(GetMethodName(), Types::kTraining, Types::kClassification) );
2170
2171 if (mvaRes==0 || mvaRes->GetSize()==0) {
2172 Log() << kERROR<<Form("Dataset[%s] : ",DataInfo().GetName())<< "<CreateMVAPdfs> No result of classifier testing available" << Endl;
2173 }
2174
2175 Double_t minVal = *std::min_element(mvaRes->GetValueVector()->begin(),mvaRes->GetValueVector()->end());
2176 Double_t maxVal = *std::max_element(mvaRes->GetValueVector()->begin(),mvaRes->GetValueVector()->end());
2177
2178 // create histograms that serve as basis to create the MVA Pdfs
2179 TH1* histMVAPdfS = new TH1D( GetMethodTypeName() + "_tr_S", GetMethodTypeName() + "_tr_S",
2180 fMVAPdfS->GetHistNBins( mvaRes->GetSize() ), minVal, maxVal );
2181 TH1* histMVAPdfB = new TH1D( GetMethodTypeName() + "_tr_B", GetMethodTypeName() + "_tr_B",
2182 fMVAPdfB->GetHistNBins( mvaRes->GetSize() ), minVal, maxVal );
2183
2184
2185 // compute sum of weights properly
2186 histMVAPdfS->Sumw2();
2187 histMVAPdfB->Sumw2();
2188
2189 // fill histograms
2190 for (UInt_t ievt=0; ievt<mvaRes->GetSize(); ievt++) {
2191 Double_t theVal = mvaRes->GetValueVector()->at(ievt);
2192 Double_t theWeight = Data()->GetEvent(ievt)->GetWeight();
2193
2194 if (DataInfo().IsSignal(Data()->GetEvent(ievt))) histMVAPdfS->Fill( theVal, theWeight );
2195 else histMVAPdfB->Fill( theVal, theWeight );
2196 }
2197
2200
2201 // momentary hack for ROOT problem
2202 if(!IsSilentFile())
2203 {
2204 histMVAPdfS->Write();
2205 histMVAPdfB->Write();
2206 }
2207 // create PDFs
2208 fMVAPdfS->BuildPDF ( histMVAPdfS );
2209 fMVAPdfB->BuildPDF ( histMVAPdfB );
2210 fMVAPdfS->ValidatePDF( histMVAPdfS );
2211 fMVAPdfB->ValidatePDF( histMVAPdfB );
2212
2213 if (DataInfo().GetNClasses() == 2) { // TODO: this is an ugly hack.. adapt this to new framework
2214 Log() << kINFO<<Form("Dataset[%s] : ",DataInfo().GetName())
2215 << TString::Format( "<CreateMVAPdfs> Separation from histogram (PDF): %1.3f (%1.3f)",
2216 GetSeparation( histMVAPdfS, histMVAPdfB ), GetSeparation( fMVAPdfS, fMVAPdfB ) )
2217 << Endl;
2218 }
2219
2220 delete histMVAPdfS;
2221 delete histMVAPdfB;
2222}
2223
2225 // the simple one, automatically calculates the mvaVal and uses the
2226 // SAME sig/bkg ratio as given in the training sample (typically 50/50
2227 // .. (NormMode=EqualNumEvents) but can be different)
2228 if (!fMVAPdfS || !fMVAPdfB) {
2229 Log() << kINFO<<Form("Dataset[%s] : ",DataInfo().GetName()) << "<GetProba> MVA PDFs for Signal and Background don't exist yet, we'll create them on demand" << Endl;
2230 CreateMVAPdfs();
2231 }
2232 Double_t sigFraction = DataInfo().GetTrainingSumSignalWeights() / (DataInfo().GetTrainingSumSignalWeights() + DataInfo().GetTrainingSumBackgrWeights() );
2233 Double_t mvaVal = GetMvaValue(ev);
2234
2235 return GetProba(mvaVal,sigFraction);
2236
2237}
2238////////////////////////////////////////////////////////////////////////////////
2239/// compute likelihood ratio
2240
2242{
2243 if (!fMVAPdfS || !fMVAPdfB) {
2244 Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetProba> MVA PDFs for Signal and Background don't exist" << Endl;
2245 return -1.0;
2246 }
2247 Double_t p_s = fMVAPdfS->GetVal( mvaVal );
2248 Double_t p_b = fMVAPdfB->GetVal( mvaVal );
2249
2250 Double_t denom = p_s*ap_sig + p_b*(1 - ap_sig);
2251
2252 return (denom > 0) ? (p_s*ap_sig) / denom : -1;
2253}
2254
2255////////////////////////////////////////////////////////////////////////////////
2256/// compute rarity:
2257/// \f[
2258/// R(x) = \int_{[-\infty..x]} { PDF(x') dx' }
2259/// \f]
2260/// where PDF(x) is the PDF of the classifier's signal or background distribution
2261
2263{
2264 if ((reftype == Types::kSignal && !fMVAPdfS) || (reftype == Types::kBackground && !fMVAPdfB)) {
2265 Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetRarity> Required MVA PDF for Signal or Background does not exist: "
2266 << "select option \"CreateMVAPdfs\"" << Endl;
2267 return 0.0;
2268 }
2269
2270 PDF* thePdf = ((reftype == Types::kSignal) ? fMVAPdfS : fMVAPdfB);
2271
2272 return thePdf->GetIntegral( thePdf->GetXmin(), mvaVal );
2273}
2274
2275////////////////////////////////////////////////////////////////////////////////
2276/// fill background efficiency (resp. rejection) versus signal efficiency plots
2277/// returns signal efficiency at background efficiency indicated in theString
2278
2280{
2281 Data()->SetCurrentType(type);
2282 Results* results = Data()->GetResults( GetMethodName(), type, Types::kClassification );
2283 std::vector<Float_t>* mvaRes = dynamic_cast<ResultsClassification*>(results)->GetValueVector();
2284
2285 // parse input string for required background efficiency
2287
2288 // sanity check
2290 if (!list || list->GetSize() < 2) computeArea = kTRUE; // the area is computed
2291 else if (list->GetSize() > 2) {
2292 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetEfficiency> Wrong number of arguments"
2293 << " in string: " << theString
2294 << " | required format, e.g., Efficiency:0.05, or empty string" << Endl;
2295 delete list;
2296 return -1;
2297 }
2298
2299 // sanity check
2300 if ( results->GetHist("MVA_S")->GetNbinsX() != results->GetHist("MVA_B")->GetNbinsX() ||
2301 results->GetHist("MVA_HIGHBIN_S")->GetNbinsX() != results->GetHist("MVA_HIGHBIN_B")->GetNbinsX() ) {
2302 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetEfficiency> Binning mismatch between signal and background histos" << Endl;
2303 delete list;
2304 return -1.0;
2305 }
2306
2307 // create histograms
2308
2309 // first, get efficiency histograms for signal and background
2310 TH1 * effhist = results->GetHist("MVA_HIGHBIN_S");
2311 Double_t xmin = effhist->GetXaxis()->GetXmin();
2312 Double_t xmax = effhist->GetXaxis()->GetXmax();
2313
2315
2316 // first round ? --> create histograms
2317 if (results->DoesExist("MVA_EFF_S")==0) {
2318
2319 // for efficiency plot
2320 TH1* eff_s = new TH1D( GetTestvarName() + "_effS", GetTestvarName() + " (signal)", fNbinsH, xmin, xmax );
2321 TH1* eff_b = new TH1D( GetTestvarName() + "_effB", GetTestvarName() + " (background)", fNbinsH, xmin, xmax );
2322 results->Store(eff_s, "MVA_EFF_S");
2323 results->Store(eff_b, "MVA_EFF_B");
2324
2325 // sign if cut
2326 Int_t sign = (fCutOrientation == kPositive) ? +1 : -1;
2327
2328 // this method is unbinned
2329 nevtS = 0;
2330 for (UInt_t ievt=0; ievt<Data()->GetNEvents(); ievt++) {
2331
2332 // read the tree
2333 Bool_t isSignal = DataInfo().IsSignal(GetEvent(ievt));
2334 Float_t theWeight = GetEvent(ievt)->GetWeight();
2335 Float_t theVal = (*mvaRes)[ievt];
2336
2337 // select histogram depending on if sig or bgd
2339
2340 // count signal and background events in tree
2341 if (isSignal) nevtS+=theWeight;
2342
2343 TAxis* axis = theHist->GetXaxis();
2344 Int_t maxbin = Int_t((theVal - axis->GetXmin())/(axis->GetXmax() - axis->GetXmin())*fNbinsH) + 1;
2345 if (sign > 0 && maxbin > fNbinsH) continue; // can happen... event doesn't count
2346 if (sign < 0 && maxbin < 1 ) continue; // can happen... event doesn't count
2347 if (sign > 0 && maxbin < 1 ) maxbin = 1;
2348 if (sign < 0 && maxbin > fNbinsH) maxbin = fNbinsH;
2349
2350 if (sign > 0)
2351 for (Int_t ibin=1; ibin<=maxbin; ibin++) theHist->AddBinContent( ibin , theWeight);
2352 else if (sign < 0)
2353 for (Int_t ibin=maxbin+1; ibin<=fNbinsH; ibin++) theHist->AddBinContent( ibin , theWeight );
2354 else
2355 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetEfficiency> Mismatch in sign" << Endl;
2356 }
2357
2358 // renormalise maximum to <=1
2359 // eff_s->Scale( 1.0/TMath::Max(1.,eff_s->GetMaximum()) );
2360 // eff_b->Scale( 1.0/TMath::Max(1.,eff_b->GetMaximum()) );
2361
2362 eff_s->Scale( 1.0/TMath::Max(std::numeric_limits<double>::epsilon(),eff_s->GetMaximum()) );
2363 eff_b->Scale( 1.0/TMath::Max(std::numeric_limits<double>::epsilon(),eff_b->GetMaximum()) );
2364
2365 // background efficiency versus signal efficiency
2366 TH1* eff_BvsS = new TH1D( GetTestvarName() + "_effBvsS", GetTestvarName() + "", fNbins, 0, 1 );
2367 results->Store(eff_BvsS, "MVA_EFF_BvsS");
2368 eff_BvsS->SetXTitle( "Signal eff" );
2369 eff_BvsS->SetYTitle( "Backgr eff" );
2370
2371 // background rejection (=1-eff.) versus signal efficiency
2372 TH1* rej_BvsS = new TH1D( GetTestvarName() + "_rejBvsS", GetTestvarName() + "", fNbins, 0, 1 );
2373 results->Store(rej_BvsS);
2374 rej_BvsS->SetXTitle( "Signal eff" );
2375 rej_BvsS->SetYTitle( "Backgr rejection (1-eff)" );
2376
2377 // inverse background eff (1/eff.) versus signal efficiency
2378 TH1* inveff_BvsS = new TH1D( GetTestvarName() + "_invBeffvsSeff",
2379 GetTestvarName(), fNbins, 0, 1 );
2380 results->Store(inveff_BvsS);
2381 inveff_BvsS->SetXTitle( "Signal eff" );
2382 inveff_BvsS->SetYTitle( "Inverse backgr. eff (1/eff)" );
2383
2384 // use root finder
2385 // spline background efficiency plot
2386 // note that there is a bin shift when going from a TH1D object to a TGraph :-(
2388 fSplRefS = new TSpline1( "spline2_signal", new TGraph( eff_s ) );
2389 fSplRefB = new TSpline1( "spline2_background", new TGraph( eff_b ) );
2390
2391 // verify spline sanity
2392 gTools().CheckSplines( eff_s, fSplRefS );
2393 gTools().CheckSplines( eff_b, fSplRefB );
2394 }
2395
2396 // make the background-vs-signal efficiency plot
2397
2398 // create root finder
2399 RootFinder rootFinder( this, fXmin, fXmax );
2400
2401 Double_t effB = 0;
2402 fEffS = eff_s; // to be set for the root finder
2403 for (Int_t bini=1; bini<=fNbins; bini++) {
2404
2405 // find cut value corresponding to a given signal efficiency
2406 Double_t effS = eff_BvsS->GetBinCenter( bini );
2407 Double_t cut = rootFinder.Root( effS );
2408
2409 // retrieve background efficiency for given cut
2410 if (Use_Splines_for_Eff_) effB = fSplRefB->Eval( cut );
2411 else effB = eff_b->GetBinContent( eff_b->FindBin( cut ) );
2412
2413 // and fill histograms
2414 eff_BvsS->SetBinContent( bini, effB );
2415 rej_BvsS->SetBinContent( bini, 1.0-effB );
2416 if (effB>std::numeric_limits<double>::epsilon())
2417 inveff_BvsS->SetBinContent( bini, 1.0/effB );
2418 }
2419
2420 // create splines for histogram
2421 fSpleffBvsS = new TSpline1( "effBvsS", new TGraph( eff_BvsS ) );
2422
2423 // search for overlap point where, when cutting on it,
2424 // one would obtain: eff_S = rej_B = 1 - eff_B
2425 Double_t effS = 0., rejB, effS_ = 0., rejB_ = 0.;
2426 Int_t nbins_ = 5000;
2427 for (Int_t bini=1; bini<=nbins_; bini++) {
2428
2429 // get corresponding signal and background efficiencies
2430 effS = (bini - 0.5)/Float_t(nbins_);
2431 rejB = 1.0 - fSpleffBvsS->Eval( effS );
2432
2433 // find signal efficiency that corresponds to required background efficiency
2434 if ((effS - rejB)*(effS_ - rejB_) < 0) break;
2435 effS_ = effS;
2436 rejB_ = rejB;
2437 }
2438
2439 // find cut that corresponds to signal efficiency and update signal-like criterion
2440 Double_t cut = rootFinder.Root( 0.5*(effS + effS_) );
2441 SetSignalReferenceCut( cut );
2442 fEffS = 0;
2443 }
2444
2445 // must exist...
2446 if (0 == fSpleffBvsS) {
2447 delete list;
2448 return 0.0;
2449 }
2450
2451 // now find signal efficiency that corresponds to required background efficiency
2452 Double_t effS = 0, effB = 0, effS_ = 0, effB_ = 0;
2453 Int_t nbins_ = 1000;
2454
2455 if (computeArea) {
2456
2457 // compute area of rej-vs-eff plot
2458 Double_t integral = 0;
2459 for (Int_t bini=1; bini<=nbins_; bini++) {
2460
2461 // get corresponding signal and background efficiencies
2462 effS = (bini - 0.5)/Float_t(nbins_);
2463 effB = fSpleffBvsS->Eval( effS );
2464 integral += (1.0 - effB);
2465 }
2466 integral /= nbins_;
2467
2468 delete list;
2469 return integral;
2470 }
2471 else {
2472
2473 // that will be the value of the efficiency retured (does not affect
2474 // the efficiency-vs-bkg plot which is done anyway.
2475 Float_t effBref = atof( ((TObjString*)list->At(1))->GetString() );
2476
2477 // find precise efficiency value
2478 for (Int_t bini=1; bini<=nbins_; bini++) {
2479
2480 // get corresponding signal and background efficiencies
2481 effS = (bini - 0.5)/Float_t(nbins_);
2482 effB = fSpleffBvsS->Eval( effS );
2483
2484 // find signal efficiency that corresponds to required background efficiency
2485 if ((effB - effBref)*(effB_ - effBref) <= 0) break;
2486 effS_ = effS;
2487 effB_ = effB;
2488 }
2489
2490 // take mean between bin above and bin below
2491 effS = 0.5*(effS + effS_);
2492
2493 effSerr = 0;
2494 if (nevtS > 0) effSerr = TMath::Sqrt( effS*(1.0 - effS)/nevtS );
2495
2496 delete list;
2497 return effS;
2498 }
2499
2500 return -1;
2501}
2502
2503////////////////////////////////////////////////////////////////////////////////
2504
2506{
2507 Data()->SetCurrentType(Types::kTraining);
2508
2509 Results* results = Data()->GetResults(GetMethodName(), Types::kTesting, Types::kNoAnalysisType);
2510
2511 // fill background efficiency (resp. rejection) versus signal efficiency plots
2512 // returns signal efficiency at background efficiency indicated in theString
2513
2514 // parse input string for required background efficiency
2516 // sanity check
2517
2518 if (list->GetSize() != 2) {
2519 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetTrainingEfficiency> Wrong number of arguments"
2520 << " in string: " << theString
2521 << " | required format, e.g., Efficiency:0.05" << Endl;
2522 delete list;
2523 return -1;
2524 }
2525 // that will be the value of the efficiency retured (does not affect
2526 // the efficiency-vs-bkg plot which is done anyway.
2527 Float_t effBref = atof( ((TObjString*)list->At(1))->GetString() );
2528
2529 delete list;
2530
2531 // sanity check
2532 if (results->GetHist("MVA_S")->GetNbinsX() != results->GetHist("MVA_B")->GetNbinsX() ||
2533 results->GetHist("MVA_HIGHBIN_S")->GetNbinsX() != results->GetHist("MVA_HIGHBIN_B")->GetNbinsX() ) {
2534 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetTrainingEfficiency> Binning mismatch between signal and background histos"
2535 << Endl;
2536 return -1.0;
2537 }
2538
2539 // create histogram
2540
2541 // first, get efficiency histograms for signal and background
2542 TH1 * effhist = results->GetHist("MVA_HIGHBIN_S");
2543 Double_t xmin = effhist->GetXaxis()->GetXmin();
2544 Double_t xmax = effhist->GetXaxis()->GetXmax();
2545
2546 // first round ? --> create and fill histograms
2547 if (results->DoesExist("MVA_TRAIN_S")==0) {
2548
2549 // classifier response distributions for test sample
2550 Double_t sxmax = fXmax+0.00001;
2551
2552 // MVA plots on the training sample (check for overtraining)
2553 TH1* mva_s_tr = new TH1D( GetTestvarName() + "_Train_S",GetTestvarName() + "_Train_S", fNbinsMVAoutput, fXmin, sxmax );
2554 TH1* mva_b_tr = new TH1D( GetTestvarName() + "_Train_B",GetTestvarName() + "_Train_B", fNbinsMVAoutput, fXmin, sxmax );
2555 results->Store(mva_s_tr, "MVA_TRAIN_S");
2556 results->Store(mva_b_tr, "MVA_TRAIN_B");
2557 mva_s_tr->Sumw2();
2558 mva_b_tr->Sumw2();
2559
2560 // Training efficiency plots
2561 TH1* mva_eff_tr_s = new TH1D( GetTestvarName() + "_trainingEffS", GetTestvarName() + " (signal)",
2562 fNbinsH, xmin, xmax );
2563 TH1* mva_eff_tr_b = new TH1D( GetTestvarName() + "_trainingEffB", GetTestvarName() + " (background)",
2564 fNbinsH, xmin, xmax );
2565 results->Store(mva_eff_tr_s, "MVA_TRAINEFF_S");
2566 results->Store(mva_eff_tr_b, "MVA_TRAINEFF_B");
2567
2568 // sign if cut
2569 Int_t sign = (fCutOrientation == kPositive) ? +1 : -1;
2570
2571 std::vector<Double_t> mvaValues = GetMvaValues(0,Data()->GetNEvents());
2572 assert( (Long64_t) mvaValues.size() == Data()->GetNEvents());
2573
2574 // this method is unbinned
2575 for (Int_t ievt=0; ievt<Data()->GetNEvents(); ievt++) {
2576
2577 Data()->SetCurrentEvent(ievt);
2578 const Event* ev = GetEvent();
2579
2580 Double_t theVal = mvaValues[ievt];
2581 Double_t theWeight = ev->GetWeight();
2582
2583 TH1* theEffHist = DataInfo().IsSignal(ev) ? mva_eff_tr_s : mva_eff_tr_b;
2584 TH1* theClsHist = DataInfo().IsSignal(ev) ? mva_s_tr : mva_b_tr;
2585
2586 theClsHist->Fill( theVal, theWeight );
2587
2588 TAxis* axis = theEffHist->GetXaxis();
2589 Int_t maxbin = Int_t((theVal - axis->GetXmin())/(axis->GetXmax() - axis->GetXmin())*fNbinsH) + 1;
2590 if (sign > 0 && maxbin > fNbinsH) continue; // can happen... event doesn't count
2591 if (sign < 0 && maxbin < 1 ) continue; // can happen... event doesn't count
2592 if (sign > 0 && maxbin < 1 ) maxbin = 1;
2593 if (sign < 0 && maxbin > fNbinsH) maxbin = fNbinsH;
2594
2595 if (sign > 0) for (Int_t ibin=1; ibin<=maxbin; ibin++) theEffHist->AddBinContent( ibin , theWeight );
2596 else for (Int_t ibin=maxbin+1; ibin<=fNbinsH; ibin++) theEffHist->AddBinContent( ibin , theWeight );
2597 }
2598
2599 // normalise output distributions
2600 // uncomment those (and several others if you want unnormalized output
2603
2604 // renormalise to maximum
2605 mva_eff_tr_s->Scale( 1.0/TMath::Max(std::numeric_limits<double>::epsilon(), mva_eff_tr_s->GetMaximum()) );
2606 mva_eff_tr_b->Scale( 1.0/TMath::Max(std::numeric_limits<double>::epsilon(), mva_eff_tr_b->GetMaximum()) );
2607
2608 // Training background efficiency versus signal efficiency
2609 TH1* eff_bvss = new TH1D( GetTestvarName() + "_trainingEffBvsS", GetTestvarName() + "", fNbins, 0, 1 );
2610 // Training background rejection (=1-eff.) versus signal efficiency
2611 TH1* rej_bvss = new TH1D( GetTestvarName() + "_trainingRejBvsS", GetTestvarName() + "", fNbins, 0, 1 );
2612 results->Store(eff_bvss, "EFF_BVSS_TR");
2613 results->Store(rej_bvss, "REJ_BVSS_TR");
2614
2615 // use root finder
2616 // spline background efficiency plot
2617 // note that there is a bin shift when going from a TH1D object to a TGraph :-(
2619 if (fSplTrainRefS) delete fSplTrainRefS;
2620 if (fSplTrainRefB) delete fSplTrainRefB;
2621 fSplTrainRefS = new TSpline1( "spline2_signal", new TGraph( mva_eff_tr_s ) );
2622 fSplTrainRefB = new TSpline1( "spline2_background", new TGraph( mva_eff_tr_b ) );
2623
2624 // verify spline sanity
2625 gTools().CheckSplines( mva_eff_tr_s, fSplTrainRefS );
2626 gTools().CheckSplines( mva_eff_tr_b, fSplTrainRefB );
2627 }
2628
2629 // make the background-vs-signal efficiency plot
2630
2631 // create root finder
2632 RootFinder rootFinder(this, fXmin, fXmax );
2633
2634 Double_t effB = 0;
2635 fEffS = results->GetHist("MVA_TRAINEFF_S");
2636 for (Int_t bini=1; bini<=fNbins; bini++) {
2637
2638 // find cut value corresponding to a given signal efficiency
2639 Double_t effS = eff_bvss->GetBinCenter( bini );
2640
2641 Double_t cut = rootFinder.Root( effS );
2642
2643 // retrieve background efficiency for given cut
2644 if (Use_Splines_for_Eff_) effB = fSplTrainRefB->Eval( cut );
2645 else effB = mva_eff_tr_b->GetBinContent( mva_eff_tr_b->FindBin( cut ) );
2646
2647 // and fill histograms
2648 eff_bvss->SetBinContent( bini, effB );
2649 rej_bvss->SetBinContent( bini, 1.0-effB );
2650 }
2651 fEffS = 0;
2652
2653 // create splines for histogram
2654 fSplTrainEffBvsS = new TSpline1( "effBvsS", new TGraph( eff_bvss ) );
2655 }
2656
2657 // must exist...
2658 if (0 == fSplTrainEffBvsS) return 0.0;
2659
2660 // now find signal efficiency that corresponds to required background efficiency
2661 Double_t effS = 0., effB, effS_ = 0., effB_ = 0.;
2662 Int_t nbins_ = 1000;
2663 for (Int_t bini=1; bini<=nbins_; bini++) {
2664
2665 // get corresponding signal and background efficiencies
2666 effS = (bini - 0.5)/Float_t(nbins_);
2667 effB = fSplTrainEffBvsS->Eval( effS );
2668
2669 // find signal efficiency that corresponds to required background efficiency
2670 if ((effB - effBref)*(effB_ - effBref) <= 0) break;
2671 effS_ = effS;
2672 effB_ = effB;
2673 }
2674
2675 return 0.5*(effS + effS_); // the mean between bin above and bin below
2676}
2677
2678////////////////////////////////////////////////////////////////////////////////
2679
2680std::vector<Float_t> TMVA::MethodBase::GetMulticlassEfficiency(std::vector<std::vector<Float_t> >& purity)
2681{
2682 Data()->SetCurrentType(Types::kTesting);
2683 ResultsMulticlass* resMulticlass = dynamic_cast<ResultsMulticlass*>(Data()->GetResults(GetMethodName(), Types::kTesting, Types::kMulticlass));
2684 if (!resMulticlass) Log() << kFATAL<<Form("Dataset[%s] : ",DataInfo().GetName())<< "unable to create pointer in GetMulticlassEfficiency, exiting."<<Endl;
2685
2686 purity.push_back(resMulticlass->GetAchievablePur());
2687 return resMulticlass->GetAchievableEff();
2688}
2689
2690////////////////////////////////////////////////////////////////////////////////
2691
2692std::vector<Float_t> TMVA::MethodBase::GetMulticlassTrainingEfficiency(std::vector<std::vector<Float_t> >& purity)
2693{
2694 Data()->SetCurrentType(Types::kTraining);
2695 ResultsMulticlass* resMulticlass = dynamic_cast<ResultsMulticlass*>(Data()->GetResults(GetMethodName(), Types::kTraining, Types::kMulticlass));
2696 if (!resMulticlass) Log() << kFATAL<< "unable to create pointer in GetMulticlassTrainingEfficiency, exiting."<<Endl;
2697
2698 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Determine optimal multiclass cuts for training data..." << Endl;
2699 for (UInt_t icls = 0; icls<DataInfo().GetNClasses(); ++icls) {
2700 resMulticlass->GetBestMultiClassCuts(icls);
2701 }
2702
2703 purity.push_back(resMulticlass->GetAchievablePur());
2704 return resMulticlass->GetAchievableEff();
2705}
2706
2707////////////////////////////////////////////////////////////////////////////////
2708/// Construct a confusion matrix for a multiclass classifier. The confusion
2709/// matrix compares, in turn, each class agaist all other classes in a pair-wise
2710/// fashion. In rows with index \f$ k_r = 0 ... K \f$, \f$ k_r \f$ is
2711/// considered signal for the sake of comparison and for each column
2712/// \f$ k_c = 0 ... K \f$ the corresponding class is considered background.
2713///
2714/// Note that the diagonal elements will be returned as NaN since this will
2715/// compare a class against itself.
2716///
2717/// \see TMVA::ResultsMulticlass::GetConfusionMatrix
2718///
2719/// \param[in] effB The background efficiency for which to evaluate.
2720/// \param[in] type The data set on which to evaluate (training, testing ...).
2721///
2722/// \return A matrix containing signal efficiencies for the given background
2723/// efficiency. The diagonal elements are NaN since this measure is
2724/// meaningless (comparing a class against itself).
2725///
2726
2728{
2729 if (GetAnalysisType() != Types::kMulticlass) {
2730 Log() << kFATAL << "Cannot get confusion matrix for non-multiclass analysis." << std::endl;
2731 return TMatrixD(0, 0);
2732 }
2733
2734 Data()->SetCurrentType(type);
2736 dynamic_cast<ResultsMulticlass *>(Data()->GetResults(GetMethodName(), type, Types::kMulticlass));
2737
2738 if (resMulticlass == nullptr) {
2739 Log() << kFATAL << Form("Dataset[%s] : ", DataInfo().GetName())
2740 << "unable to create pointer in GetMulticlassEfficiency, exiting." << Endl;
2741 return TMatrixD(0, 0);
2742 }
2743
2744 return resMulticlass->GetConfusionMatrix(effB);
2745}
2746
2747////////////////////////////////////////////////////////////////////////////////
2748/// compute significance of mean difference
2749/// \f[
2750/// significance = \frac{|<S> - <B>|}{\sqrt{RMS_{S2} + RMS_{B2}}}
2751/// \f]
2752
2754{
2755 Double_t rms = sqrt( fRmsS*fRmsS + fRmsB*fRmsB );
2756
2757 return (rms > 0) ? TMath::Abs(fMeanS - fMeanB)/rms : 0;
2758}
2759
2760////////////////////////////////////////////////////////////////////////////////
2761/// compute "separation" defined as
2762/// \f[
2763/// <s2> = \frac{1}{2} \int_{-\infty}^{+\infty} { \frac{(S(x) - B(x))^2}{(S(x) + B(x))} dx }
2764/// \f]
2765
2770
2771////////////////////////////////////////////////////////////////////////////////
2772/// compute "separation" defined as
2773/// \f[
2774/// <s2> = \frac{1}{2} \int_{-\infty}^{+\infty} { \frac{(S(x) - B(x))^2}{(S(x) + B(x))} dx }
2775/// \f]
2776
2778{
2779 // note, if zero pointers given, use internal pdf
2780 // sanity check first
2781 if ((!pdfS && pdfB) || (pdfS && !pdfB))
2782 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetSeparation> Mismatch in pdfs" << Endl;
2783 if (!pdfS) pdfS = fSplS;
2784 if (!pdfB) pdfB = fSplB;
2785
2786 if (!fSplS || !fSplB) {
2787 Log()<<kDEBUG<<Form("[%s] : ",DataInfo().GetName())<< "could not calculate the separation, distributions"
2788 << " fSplS or fSplB are not yet filled" << Endl;
2789 return 0;
2790 }else{
2791 return gTools().GetSeparation( *pdfS, *pdfB );
2792 }
2793}
2794
2795////////////////////////////////////////////////////////////////////////////////
2796/// calculate the area (integral) under the ROC curve as a
2797/// overall quality measure of the classification
2798
2800{
2801 // note, if zero pointers given, use internal pdf
2802 // sanity check first
2803 if ((!histS && histB) || (histS && !histB))
2804 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetROCIntegral(TH1D*, TH1D*)> Mismatch in hists" << Endl;
2805
2806 if (histS==0 || histB==0) return 0.;
2807
2808 TMVA::PDF *pdfS = new TMVA::PDF( " PDF Sig", histS, TMVA::PDF::kSpline3 );
2809 TMVA::PDF *pdfB = new TMVA::PDF( " PDF Bkg", histB, TMVA::PDF::kSpline3 );
2810
2811
2812 Double_t xmin = TMath::Min(pdfS->GetXmin(), pdfB->GetXmin());
2813 Double_t xmax = TMath::Max(pdfS->GetXmax(), pdfB->GetXmax());
2814
2815 Double_t integral = 0;
2816 UInt_t nsteps = 1000;
2817 Double_t step = (xmax-xmin)/Double_t(nsteps);
2818 Double_t cut = xmin;
2819 for (UInt_t i=0; i<nsteps; i++) {
2820 integral += (1-pdfB->GetIntegral(cut,xmax)) * pdfS->GetVal(cut);
2821 cut+=step;
2822 }
2823 delete pdfS;
2824 delete pdfB;
2825 return integral*step;
2826}
2827
2828
2829////////////////////////////////////////////////////////////////////////////////
2830/// calculate the area (integral) under the ROC curve as a
2831/// overall quality measure of the classification
2832
2834{
2835 // note, if zero pointers given, use internal pdf
2836 // sanity check first
2837 if ((!pdfS && pdfB) || (pdfS && !pdfB))
2838 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetSeparation> Mismatch in pdfs" << Endl;
2839 if (!pdfS) pdfS = fSplS;
2840 if (!pdfB) pdfB = fSplB;
2841
2842 if (pdfS==0 || pdfB==0) return 0.;
2843
2844 Double_t xmin = TMath::Min(pdfS->GetXmin(), pdfB->GetXmin());
2845 Double_t xmax = TMath::Max(pdfS->GetXmax(), pdfB->GetXmax());
2846
2847 Double_t integral = 0;
2848 UInt_t nsteps = 1000;
2849 Double_t step = (xmax-xmin)/Double_t(nsteps);
2850 Double_t cut = xmin;
2851 for (UInt_t i=0; i<nsteps; i++) {
2852 integral += (1-pdfB->GetIntegral(cut,xmax)) * pdfS->GetVal(cut);
2853 cut+=step;
2854 }
2855 return integral*step;
2856}
2857
2858////////////////////////////////////////////////////////////////////////////////
2859/// plot significance, \f$ \frac{S}{\sqrt{S^2 + B^2}} \f$, curve for given number
2860/// of signal and background events; returns cut for maximum significance
2861/// also returned via reference is the maximum significance
2862
2866{
2867 Results* results = Data()->GetResults( GetMethodName(), Types::kTesting, Types::kMaxAnalysisType );
2868
2870 Double_t effS(0),effB(0),significance(0);
2871 TH1D *temp_histogram = new TH1D("temp", "temp", fNbinsH, fXmin, fXmax );
2872
2873 if (SignalEvents <= 0 || BackgroundEvents <= 0) {
2874 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<GetMaximumSignificance> "
2875 << "Number of signal or background events is <= 0 ==> abort"
2876 << Endl;
2877 }
2878
2879 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Using ratio SignalEvents/BackgroundEvents = "
2881
2882 TH1* eff_s = results->GetHist("MVA_EFF_S");
2883 TH1* eff_b = results->GetHist("MVA_EFF_B");
2884
2885 if ( (eff_s==0) || (eff_b==0) ) {
2886 Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Efficiency histograms empty !" << Endl;
2887 Log() << kWARNING <<Form("Dataset[%s] : ",DataInfo().GetName())<< "no maximum cut found, return 0" << Endl;
2888 return 0;
2889 }
2890
2891 for (Int_t bin=1; bin<=fNbinsH; bin++) {
2892 effS = eff_s->GetBinContent( bin );
2893 effB = eff_b->GetBinContent( bin );
2894
2895 // put significance into a histogram
2897
2898 temp_histogram->SetBinContent(bin,significance);
2899 }
2900
2901 // find maximum in histogram
2902 max_significance = temp_histogram->GetBinCenter( temp_histogram->GetMaximumBin() );
2903 max_significance_value = temp_histogram->GetBinContent( temp_histogram->GetMaximumBin() );
2904
2905 // delete
2906 delete temp_histogram;
2907
2908 Log() << kINFO <<Form("Dataset[%s] : ",DataInfo().GetName())<< "Optimal cut at : " << max_significance << Endl;
2909 Log() << kINFO<<Form("Dataset[%s] : ",DataInfo().GetName()) << "Maximum significance: " << max_significance_value << Endl;
2910
2911 return max_significance;
2912}
2913
2914////////////////////////////////////////////////////////////////////////////////
2915/// calculates rms,mean, xmin, xmax of the event variable
2916/// this can be either done for the variables as they are or for
2917/// normalised variables (in the range of 0-1) if "norm" is set to kTRUE
2918
2923{
2924 Types::ETreeType previousTreeType = Data()->GetCurrentType();
2925 Data()->SetCurrentType(treeType);
2926
2927 Long64_t entries = Data()->GetNEvents();
2928
2929 // sanity check
2930 if (entries <=0)
2931 Log() << kFATAL <<Form("Dataset[%s] : ",DataInfo().GetName())<< "<CalculateEstimator> Wrong tree type: " << treeType << Endl;
2932
2933 // index of the wanted variable
2934 UInt_t varIndex = DataInfo().FindVarIndex( theVarName );
2935
2936 // first fill signal and background in arrays before analysis
2937 xmin = +DBL_MAX;
2938 xmax = -DBL_MAX;
2939
2940 // take into account event weights
2941 meanS = 0;
2942 meanB = 0;
2943 rmsS = 0;
2944 rmsB = 0;
2945 Double_t sumwS = 0, sumwB = 0;
2946
2947 // loop over all training events
2948 for (Int_t ievt = 0; ievt < entries; ievt++) {
2949
2950 const Event* ev = GetEvent(ievt);
2951
2952 Double_t theVar = ev->GetValue(varIndex);
2953 Double_t weight = ev->GetWeight();
2954
2955 if (DataInfo().IsSignal(ev)) {
2956 sumwS += weight;
2957 meanS += weight*theVar;
2958 rmsS += weight*theVar*theVar;
2959 }
2960 else {
2961 sumwB += weight;
2962 meanB += weight*theVar;
2963 rmsB += weight*theVar*theVar;
2964 }
2965 xmin = TMath::Min( xmin, theVar );
2966 xmax = TMath::Max( xmax, theVar );
2967 }
2968
2969 meanS = meanS/sumwS;
2970 meanB = meanB/sumwB;
2973
2974 Data()->SetCurrentType(previousTreeType);
2975}
2976
2977////////////////////////////////////////////////////////////////////////////////
2978/// create reader class for method (classification only at present)
2979
2981{
2982 // the default consists of
2984 if (theClassFileName == "")
2985 classFileName = GetWeightFileDir() + "/" + GetJobName() + "_" + GetMethodName() + ".class.C";
2986 else
2988
2989 TString className = TString("Read") + GetMethodName();
2990
2992 Log() << kINFO //<<Form("Dataset[%s] : ",DataInfo().GetName())
2993 << "Creating standalone class: "
2994 << gTools().Color("lightblue") << classFileName << gTools().Color("reset") << Endl;
2995
2996 std::ofstream fout( classFileName );
2997 if (!fout.good()) { // file could not be opened --> Error
2998 Log() << kFATAL << "<MakeClass> Unable to open file: " << classFileName << Endl;
2999 }
3000
3001 // now create the class
3002 // preamble
3003 fout << "// Class: " << className << std::endl;
3004 fout << "// Automatically generated by MethodBase::MakeClass" << std::endl << "//" << std::endl;
3005
3006 // print general information and configuration state
3007 fout << std::endl;
3008 fout << "/* configuration options =====================================================" << std::endl << std::endl;
3009 WriteStateToStream( fout );
3010 fout << std::endl;
3011 fout << "============================================================================ */" << std::endl;
3012
3013 // generate the class
3014 fout << "" << std::endl;
3015 fout << "#include <array>" << std::endl;
3016 fout << "#include <vector>" << std::endl;
3017 fout << "#include <cmath>" << std::endl;
3018 fout << "#include <string>" << std::endl;
3019 fout << "#include <iostream>" << std::endl;
3020 fout << "" << std::endl;
3021 // now if the classifier needs to write some additional classes for its response implementation
3022 // this code goes here: (at least the header declarations need to come before the main class
3023 this->MakeClassSpecificHeader( fout, className );
3024
3025 fout << "#ifndef IClassifierReader__def" << std::endl;
3026 fout << "#define IClassifierReader__def" << std::endl;
3027 fout << std::endl;
3028 fout << "class IClassifierReader {" << std::endl;
3029 fout << std::endl;
3030 fout << " public:" << std::endl;
3031 fout << std::endl;
3032 fout << " // constructor" << std::endl;
3033 fout << " IClassifierReader() : fStatusIsClean( true ) {}" << std::endl;
3034 fout << " virtual ~IClassifierReader() {}" << std::endl;
3035 fout << std::endl;
3036 fout << " // return classifier response" << std::endl;
3037 if(GetAnalysisType() == Types::kMulticlass) {
3038 fout << " virtual std::vector<double> GetMulticlassValues( const std::vector<double>& inputValues ) const = 0;" << std::endl;
3039 } else {
3040 fout << " virtual double GetMvaValue( const std::vector<double>& inputValues ) const = 0;" << std::endl;
3041 }
3042 fout << std::endl;
3043 fout << " // returns classifier status" << std::endl;
3044 fout << " bool IsStatusClean() const { return fStatusIsClean; }" << std::endl;
3045 fout << std::endl;
3046 fout << " protected:" << std::endl;
3047 fout << std::endl;
3048 fout << " bool fStatusIsClean;" << std::endl;
3049 fout << "};" << std::endl;
3050 fout << std::endl;
3051 fout << "#endif" << std::endl;
3052 fout << std::endl;
3053 fout << "class " << className << " : public IClassifierReader {" << std::endl;
3054 fout << std::endl;
3055 fout << " public:" << std::endl;
3056 fout << std::endl;
3057 fout << " // constructor" << std::endl;
3058 fout << " " << className << "( std::vector<std::string>& theInputVars )" << std::endl;
3059 fout << " : IClassifierReader()," << std::endl;
3060 fout << " fClassName( \"" << className << "\" )," << std::endl;
3061 fout << " fNvars( " << GetNvar() << " )" << std::endl;
3062 fout << " {" << std::endl;
3063 fout << " // the training input variables" << std::endl;
3064 fout << " const char* inputVars[] = { ";
3065 for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
3066 fout << "\"" << GetOriginalVarName(ivar) << "\"";
3067 if (ivar<GetNvar()-1) fout << ", ";
3068 }
3069 fout << " };" << std::endl;
3070 fout << std::endl;
3071 fout << " // sanity checks" << std::endl;
3072 fout << " if (theInputVars.size() <= 0) {" << std::endl;
3073 fout << " std::cout << \"Problem in class \\\"\" << fClassName << \"\\\": empty input vector\" << std::endl;" << std::endl;
3074 fout << " fStatusIsClean = false;" << std::endl;
3075 fout << " }" << std::endl;
3076 fout << std::endl;
3077 fout << " if (theInputVars.size() != fNvars) {" << std::endl;
3078 fout << " std::cout << \"Problem in class \\\"\" << fClassName << \"\\\": mismatch in number of input values: \"" << std::endl;
3079 fout << " << theInputVars.size() << \" != \" << fNvars << std::endl;" << std::endl;
3080 fout << " fStatusIsClean = false;" << std::endl;
3081 fout << " }" << std::endl;
3082 fout << std::endl;
3083 fout << " // validate input variables" << std::endl;
3084 fout << " for (size_t ivar = 0; ivar < theInputVars.size(); ivar++) {" << std::endl;
3085 fout << " if (theInputVars[ivar] != inputVars[ivar]) {" << std::endl;
3086 fout << " std::cout << \"Problem in class \\\"\" << fClassName << \"\\\": mismatch in input variable names\" << std::endl" << std::endl;
3087 fout << " << \" for variable [\" << ivar << \"]: \" << theInputVars[ivar].c_str() << \" != \" << inputVars[ivar] << std::endl;" << std::endl;
3088 fout << " fStatusIsClean = false;" << std::endl;
3089 fout << " }" << std::endl;
3090 fout << " }" << std::endl;
3091 fout << std::endl;
3092 fout << " // initialize min and max vectors (for normalisation)" << std::endl;
3093 for (UInt_t ivar = 0; ivar < GetNvar(); ivar++) {
3094 fout << " fVmin[" << ivar << "] = " << std::setprecision(15) << GetXmin( ivar ) << ";" << std::endl;
3095 fout << " fVmax[" << ivar << "] = " << std::setprecision(15) << GetXmax( ivar ) << ";" << std::endl;
3096 }
3097 fout << std::endl;
3098 fout << " // initialize input variable types" << std::endl;
3099 for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
3100 fout << " fType[" << ivar << "] = \'" << DataInfo().GetVariableInfo(ivar).GetVarType() << "\';" << std::endl;
3101 }
3102 fout << std::endl;
3103 fout << " // initialize constants" << std::endl;
3104 fout << " Initialize();" << std::endl;
3105 fout << std::endl;
3106 if (GetTransformationHandler().GetTransformationList().GetSize() != 0) {
3107 fout << " // initialize transformation" << std::endl;
3108 fout << " InitTransform();" << std::endl;
3109 }
3110 fout << " }" << std::endl;
3111 fout << std::endl;
3112 fout << " // destructor" << std::endl;
3113 fout << " virtual ~" << className << "() {" << std::endl;
3114 fout << " Clear(); // method-specific" << std::endl;
3115 fout << " }" << std::endl;
3116 fout << std::endl;
3117 fout << " // the classifier response" << std::endl;
3118 fout << " // \"inputValues\" is a vector of input values in the same order as the" << std::endl;
3119 fout << " // variables given to the constructor" << std::endl;
3120 if(GetAnalysisType() == Types::kMulticlass) {
3121 fout << " std::vector<double> GetMulticlassValues( const std::vector<double>& inputValues ) const override;" << std::endl;
3122 } else {
3123 fout << " double GetMvaValue( const std::vector<double>& inputValues ) const override;" << std::endl;
3124 }
3125 fout << std::endl;
3126 fout << " private:" << std::endl;
3127 fout << std::endl;
3128 fout << " // method-specific destructor" << std::endl;
3129 fout << " void Clear();" << std::endl;
3130 fout << std::endl;
3131 if (GetTransformationHandler().GetTransformationList().GetSize()!=0) {
3132 fout << " // input variable transformation" << std::endl;
3133 GetTransformationHandler().MakeFunction(fout, className,1);
3134 fout << " void InitTransform();" << std::endl;
3135 fout << " void Transform( std::vector<double> & iv, int sigOrBgd ) const;" << std::endl;
3136 fout << std::endl;
3137 }
3138 fout << " // common member variables" << std::endl;
3139 fout << " const char* fClassName;" << std::endl;
3140 fout << std::endl;
3141 fout << " const size_t fNvars;" << std::endl;
3142 fout << " size_t GetNvar() const { return fNvars; }" << std::endl;
3143 fout << " char GetType( int ivar ) const { return fType[ivar]; }" << std::endl;
3144 fout << std::endl;
3145 fout << " // normalisation of input variables" << std::endl;
3146 fout << " double fVmin[" << GetNvar() << "];" << std::endl;
3147 fout << " double fVmax[" << GetNvar() << "];" << std::endl;
3148 fout << " double NormVariable( double x, double xmin, double xmax ) const {" << std::endl;
3149 fout << " // normalise to output range: [-1, 1]" << std::endl;
3150 fout << " return 2*(x - xmin)/(xmax - xmin) - 1.0;" << std::endl;
3151 fout << " }" << std::endl;
3152 fout << std::endl;
3153 fout << " // type of input variable: 'F' or 'I'" << std::endl;
3154 fout << " char fType[" << GetNvar() << "];" << std::endl;
3155 fout << std::endl;
3156 fout << " // initialize internal variables" << std::endl;
3157 fout << " void Initialize();" << std::endl;
3158 if(GetAnalysisType() == Types::kMulticlass) {
3159 fout << " std::vector<double> GetMulticlassValues__( const std::vector<double>& inputValues ) const;" << std::endl;
3160 } else {
3161 fout << " double GetMvaValue__( const std::vector<double>& inputValues ) const;" << std::endl;
3162 }
3163 fout << "" << std::endl;
3164 fout << " // private members (method specific)" << std::endl;
3165
3166 // call the classifier specific output (the classifier must close the class !)
3167 MakeClassSpecific( fout, className );
3168
3169 if(GetAnalysisType() == Types::kMulticlass) {
3170 fout << "inline std::vector<double> " << className << "::GetMulticlassValues( const std::vector<double>& inputValues ) const" << std::endl;
3171 } else {
3172 fout << "inline double " << className << "::GetMvaValue( const std::vector<double>& inputValues ) const" << std::endl;
3173 }
3174 fout << "{" << std::endl;
3175 fout << " // classifier response value" << std::endl;
3176 if(GetAnalysisType() == Types::kMulticlass) {
3177 fout << " std::vector<double> retval;" << std::endl;
3178 } else {
3179 fout << " double retval = 0;" << std::endl;
3180 }
3181 fout << std::endl;
3182 fout << " // classifier response, sanity check first" << std::endl;
3183 fout << " if (!IsStatusClean()) {" << std::endl;
3184 fout << " std::cout << \"Problem in class \\\"\" << fClassName << \"\\\": cannot return classifier response\"" << std::endl;
3185 fout << " << \" because status is dirty\" << std::endl;" << std::endl;
3186 fout << " }" << std::endl;
3187 fout << " else {" << std::endl;
3188 if (IsNormalised()) {
3189 fout << " // normalise variables" << std::endl;
3190 fout << " std::vector<double> iV;" << std::endl;
3191 fout << " iV.reserve(inputValues.size());" << std::endl;
3192 fout << " int ivar = 0;" << std::endl;
3193 fout << " for (std::vector<double>::const_iterator varIt = inputValues.begin();" << std::endl;
3194 fout << " varIt != inputValues.end(); varIt++, ivar++) {" << std::endl;
3195 fout << " iV.push_back(NormVariable( *varIt, fVmin[ivar], fVmax[ivar] ));" << std::endl;
3196 fout << " }" << std::endl;
3197 if (GetTransformationHandler().GetTransformationList().GetSize() != 0 && GetMethodType() != Types::kLikelihood &&
3198 GetMethodType() != Types::kHMatrix) {
3199 fout << " Transform( iV, -1 );" << std::endl;
3200 }
3201
3202 if(GetAnalysisType() == Types::kMulticlass) {
3203 fout << " retval = GetMulticlassValues__( iV );" << std::endl;
3204 } else {
3205 fout << " retval = GetMvaValue__( iV );" << std::endl;
3206 }
3207 } else {
3208 if (GetTransformationHandler().GetTransformationList().GetSize() != 0 && GetMethodType() != Types::kLikelihood &&
3209 GetMethodType() != Types::kHMatrix) {
3210 fout << " std::vector<double> iV(inputValues);" << std::endl;
3211 fout << " Transform( iV, -1 );" << std::endl;
3212 if(GetAnalysisType() == Types::kMulticlass) {
3213 fout << " retval = GetMulticlassValues__( iV );" << std::endl;
3214 } else {
3215 fout << " retval = GetMvaValue__( iV );" << std::endl;
3216 }
3217 } else {
3218 if(GetAnalysisType() == Types::kMulticlass) {
3219 fout << " retval = GetMulticlassValues__( inputValues );" << std::endl;
3220 } else {
3221 fout << " retval = GetMvaValue__( inputValues );" << std::endl;
3222 }
3223 }
3224 }
3225 fout << " }" << std::endl;
3226 fout << std::endl;
3227 fout << " return retval;" << std::endl;
3228 fout << "}" << std::endl;
3229
3230 // create output for transformation - if any
3231 if (GetTransformationHandler().GetTransformationList().GetSize()!=0)
3232 GetTransformationHandler().MakeFunction(fout, className,2);
3233
3234 // close the file
3235 fout.close();
3236}
3237
3238////////////////////////////////////////////////////////////////////////////////
3239/// prints out method-specific help method
3240
3242{
3243 // if options are written to reference file, also append help info
3244 std::streambuf* cout_sbuf = std::cout.rdbuf(); // save original sbuf
3245 std::ofstream* o = 0;
3246 if (gConfig().WriteOptionsReference()) {
3247 Log() << kINFO << "Print Help message for class " << GetName() << " into file: " << GetReferenceFile() << Endl;
3248 o = new std::ofstream( GetReferenceFile(), std::ios::app );
3249 if (!o->good()) { // file could not be opened --> Error
3250 Log() << kFATAL << "<PrintHelpMessage> Unable to append to output file: " << GetReferenceFile() << Endl;
3251 }
3252 std::cout.rdbuf( o->rdbuf() ); // redirect 'std::cout' to file
3253 }
3254
3255 // "|--------------------------------------------------------------|"
3256 if (!o) {
3257 Log() << kINFO << Endl;
3258 Log() << gTools().Color("bold")
3259 << "================================================================"
3260 << gTools().Color( "reset" )
3261 << Endl;
3262 Log() << gTools().Color("bold")
3263 << "H e l p f o r M V A m e t h o d [ " << GetName() << " ] :"
3264 << gTools().Color( "reset" )
3265 << Endl;
3266 }
3267 else {
3268 Log() << "Help for MVA method [ " << GetName() << " ] :" << Endl;
3269 }
3270
3271 // print method-specific help message
3272 GetHelpMessage();
3273
3274 if (!o) {
3275 Log() << Endl;
3276 Log() << "<Suppress this message by specifying \"!H\" in the booking option>" << Endl;
3277 Log() << gTools().Color("bold")
3278 << "================================================================"
3279 << gTools().Color( "reset" )
3280 << Endl;
3281 Log() << Endl;
3282 }
3283 else {
3284 // indicate END
3285 Log() << "# End of Message___" << Endl;
3286 }
3287
3288 std::cout.rdbuf( cout_sbuf ); // restore the original stream buffer
3289 if (o) o->close();
3290}
3291
3292// ----------------------- r o o t f i n d i n g ----------------------------
3293
3294////////////////////////////////////////////////////////////////////////////////
3295/// returns efficiency as function of cut
3296
3298{
3299 Double_t retval=0;
3300
3301 // retrieve the class object
3303 retval = fSplRefS->Eval( theCut );
3304 }
3305 else retval = fEffS->GetBinContent( fEffS->FindBin( theCut ) );
3306
3307 // caution: here we take some "forbidden" action to hide a problem:
3308 // in some cases, in particular for likelihood, the binned efficiency distributions
3309 // do not equal 1, at xmin, and 0 at xmax; of course, in principle we have the
3310 // unbinned information available in the trees, but the unbinned minimization is
3311 // too slow, and we don't need to do a precision measurement here. Hence, we force
3312 // this property.
3313 Double_t eps = 1.0e-5;
3314 if (theCut-fXmin < eps) retval = (GetCutOrientation() == kPositive) ? 1.0 : 0.0;
3315 else if (fXmax-theCut < eps) retval = (GetCutOrientation() == kPositive) ? 0.0 : 1.0;
3316
3317 return retval;
3318}
3319
3320////////////////////////////////////////////////////////////////////////////////
3321/// returns the event collection (i.e. the dataset) TRANSFORMED using the
3322/// classifiers specific Variable Transformation (e.g. Decorr or Decorr:Gauss:Decorr)
3323
3325{
3326 // if there's no variable transformation for this classifier, just hand back the
3327 // event collection of the data set
3328 if (GetTransformationHandler().GetTransformationList().GetEntries() <= 0) {
3329 return (Data()->GetEventCollection(type));
3330 }
3331
3332 // otherwise, transform ALL the events and hand back the vector of the pointers to the
3333 // transformed events. If the pointer is already != 0, i.e. the whole thing has been
3334 // done before, I don't need to do it again, but just "hand over" the pointer to those events.
3335 Int_t idx = Data()->TreeIndex(type); //index indicating Training,Testing,... events/datasets
3336 if (fEventCollections.at(idx) == 0) {
3337 fEventCollections.at(idx) = &(Data()->GetEventCollection(type));
3338 fEventCollections.at(idx) = GetTransformationHandler().CalcTransformations(*(fEventCollections.at(idx)),kTRUE);
3339 }
3340 return *(fEventCollections.at(idx));
3341}
3342
3343////////////////////////////////////////////////////////////////////////////////
3344/// calculates the TMVA version string from the training version code on the fly
3345
3347{
3348 UInt_t a = GetTrainingTMVAVersionCode() & 0xff0000; a>>=16;
3349 UInt_t b = GetTrainingTMVAVersionCode() & 0x00ff00; b>>=8;
3350 UInt_t c = GetTrainingTMVAVersionCode() & 0x0000ff;
3351
3352 return TString::Format("%i.%i.%i",a,b,c);
3353}
3354
3355////////////////////////////////////////////////////////////////////////////////
3356/// calculates the ROOT version string from the training version code on the fly
3357
3359{
3360 UInt_t a = GetTrainingROOTVersionCode() & 0xff0000; a>>=16;
3361 UInt_t b = GetTrainingROOTVersionCode() & 0x00ff00; b>>=8;
3362 UInt_t c = GetTrainingROOTVersionCode() & 0x0000ff;
3363
3364 return TString::Format("%i.%02i/%02i",a,b,c);
3365}
3366
3367////////////////////////////////////////////////////////////////////////////////
3368
3371 ( Data()->GetResults(GetMethodName(),Types::kTesting, Types::kClassification) );
3372
3373 if (mvaRes != NULL) {
3374 TH1D *mva_s = dynamic_cast<TH1D*> (mvaRes->GetHist("MVA_S"));
3375 TH1D *mva_b = dynamic_cast<TH1D*> (mvaRes->GetHist("MVA_B"));
3376 TH1D *mva_s_tr = dynamic_cast<TH1D*> (mvaRes->GetHist("MVA_TRAIN_S"));
3377 TH1D *mva_b_tr = dynamic_cast<TH1D*> (mvaRes->GetHist("MVA_TRAIN_B"));
3378
3379 if ( !mva_s || !mva_b || !mva_s_tr || !mva_b_tr) return -1;
3380
3381 if (SorB == 's' || SorB == 'S')
3382 return mva_s->KolmogorovTest( mva_s_tr, opt.Data() );
3383 else
3384 return mva_b->KolmogorovTest( mva_b_tr, opt.Data() );
3385 }
3386 return -1;
3387}
const Bool_t Use_Splines_for_Eff_
const Int_t NBIN_HIST_HIGH
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define s1(x)
Definition RSha256.hxx:91
#define ROOT_VERSION_CODE
Definition RVersion.hxx:24
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:52
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:148
float xmin
float xmax
TMatrixT< Double_t > TMatrixD
Definition TMatrixDfwd.h:23
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2570
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define TMVA_VERSION_CODE
Definition Version.h:47
const_iterator begin() const
const_iterator end() const
Class to manage histogram axis.
Definition TAxis.h:32
Double_t GetXmax() const
Definition TAxis.h:142
Double_t GetXmin() const
Definition TAxis.h:141
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition TDatime.h:37
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
Describe directory structure in memory.
Definition TDirectory.h:45
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3797
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
1-D histogram with a double per channel (see TH1 documentation)
Definition TH1.h:926
1-D histogram with a float per channel (see TH1 documentation)
Definition TH1.h:878
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
virtual Double_t GetMean(Int_t axis=1) const
For axis = 1,2 or 3 returns the mean value of the histogram along X,Y or Z axis.
Definition TH1.cxx:7744
virtual Int_t GetQuantiles(Int_t n, Double_t *xp, const Double_t *p=nullptr)
Compute Quantiles for this histogram.
Definition TH1.cxx:4766
2-D histogram with a float per channel (see TH1 documentation)
Definition TH2.h:345
Int_t Fill(Double_t) override
Invalid Fill method.
Definition TH2.cxx:364
A doubly linked list.
Definition TList.h:38
Class that contains all the information of a class.
Definition ClassInfo.h:49
TString fWeightFileExtension
Definition Config.h:125
VariablePlotting & GetVariablePlotting()
Definition Config.h:97
class TMVA::Config::VariablePlotting fVariablePlotting
IONames & GetIONames()
Definition Config.h:98
MsgLogger * fLogger
! message logger
Class that contains all the data information.
Definition DataSetInfo.h:62
Class that contains all the data information.
Definition DataSet.h:58
static void SetIsTraining(Bool_t)
when this static function is called, it sets the flag whether events with negative event weight shoul...
Definition Event.cxx:399
static void SetIgnoreNegWeightsInTraining(Bool_t)
when this static function is called, it sets the flag whether events with negative event weight shoul...
Definition Event.cxx:408
Interface for all concrete MVA method implementations.
Definition IMethod.h:53
Virtual base Class for all MVA method.
Definition MethodBase.h:82
TDirectory * MethodBaseDir() const
returns the ROOT directory where all instances of the corresponding MVA method are stored
virtual Double_t GetKSTrainingVsTest(Char_t SorB, TString opt="X")
MethodBase(const TString &jobName, Types::EMVA methodType, const TString &methodTitle, DataSetInfo &dsi, const TString &theOption="")
standard constructor
void PrintHelpMessage() const override
prints out method-specific help method
virtual std::vector< Float_t > GetAllMulticlassValues()
Get all multi-class values.
virtual Double_t GetSeparation(TH1 *, TH1 *) const
compute "separation" defined as
const char * GetName() const override
Definition MethodBase.h:308
void ReadClassesFromXML(void *clsnode)
read number of classes from XML
void SetWeightFileDir(TString fileDir)
set directory of weight file
void WriteStateToXML(void *parent) const
general method used in writing the header of the weight files where the used variables,...
void DeclareBaseOptions()
define the options (their key words) that can be set in the option string here the options valid for ...
virtual void TestRegression(Double_t &bias, Double_t &biasT, Double_t &dev, Double_t &devT, Double_t &rms, Double_t &rmsT, Double_t &mInf, Double_t &mInfT, Double_t &corr, Types::ETreeType type)
calculate <sum-of-deviation-squared> of regression output versus "true" value from test sample
virtual void DeclareCompatibilityOptions()
options that are used ONLY for the READER to ensure backward compatibility they are hence without any...
virtual Double_t GetSignificance() const
compute significance of mean difference
virtual Double_t GetProba(const Event *ev)
virtual TMatrixD GetMulticlassConfusionMatrix(Double_t effB, Types::ETreeType type)
Construct a confusion matrix for a multiclass classifier.
virtual void WriteEvaluationHistosToFile(Types::ETreeType treetype)
writes all MVA evaluation histograms to file
virtual void TestMulticlass()
test multiclass classification
const std::vector< TMVA::Event * > & GetEventCollection(Types::ETreeType type)
returns the event collection (i.e.
virtual std::vector< Double_t > GetDataMvaValues(DataSet *data=nullptr, Long64_t firstEvt=0, Long64_t lastEvt=-1, Bool_t logProgress=false)
get all the MVA values for the events of the given Data type
void SetupMethod()
setup of methods
TDirectory * BaseDir() const
returns the ROOT directory where info/histograms etc of the corresponding MVA method instance are sto...
virtual std::vector< Float_t > GetMulticlassEfficiency(std::vector< std::vector< Float_t > > &purity)
void AddInfoItem(void *gi, const TString &name, const TString &value) const
xml writing
virtual void AddClassifierOutputProb(Types::ETreeType type)
prepare tree branch with the method's discriminating variable
virtual Double_t GetEfficiency(const TString &, Types::ETreeType, Double_t &err)
fill background efficiency (resp.
TString GetTrainingTMVAVersionString() const
calculates the TMVA version string from the training version code on the fly
void Statistics(Types::ETreeType treeType, const TString &theVarName, Double_t &, Double_t &, Double_t &, Double_t &, Double_t &, Double_t &)
calculates rms,mean, xmin, xmax of the event variable this can be either done for the variables as th...
Bool_t GetLine(std::istream &fin, char *buf)
reads one line from the input stream checks for certain keywords and interprets the line if keywords ...
void ProcessSetup()
process all options the "CheckForUnusedOptions" is done in an independent call, since it may be overr...
virtual std::vector< Double_t > GetMvaValues(Long64_t firstEvt=0, Long64_t lastEvt=-1, Bool_t logProgress=false)
get all the MVA values for the events of the current Data type
virtual Bool_t IsSignalLike()
uses a pre-set cut on the MVA output (SetSignalReferenceCut and SetSignalReferenceCutOrientation) for...
virtual ~MethodBase()
destructor
void WriteMonitoringHistosToFile() const override
write special monitoring histograms to file dummy implementation here --------------—
virtual Double_t GetMaximumSignificance(Double_t SignalEvents, Double_t BackgroundEvents, Double_t &optimal_significance_value) const
plot significance, , curve for given number of signal and background events; returns cut for maximum ...
virtual Double_t GetTrainingEfficiency(const TString &)
void SetWeightFileName(TString)
set the weight file name (depreciated)
TString GetWeightFileName() const
retrieve weight file name
virtual void TestClassification()
initialization
void AddOutput(Types::ETreeType type, Types::EAnalysisType analysisType)
virtual void AddRegressionOutput(Types::ETreeType type)
prepare tree branch with the method's discriminating variable
void InitBase()
default initialization called by all constructors
virtual void GetRegressionDeviation(UInt_t tgtNum, Types::ETreeType type, Double_t &stddev, Double_t &stddev90Percent) const
void ReadStateFromXMLString(const char *xmlstr)
for reading from memory
void MakeClass(const TString &classFileName=TString("")) const override
create reader class for method (classification only at present)
void CreateMVAPdfs()
Create PDFs of the MVA output variables.
TString GetTrainingROOTVersionString() const
calculates the ROOT version string from the training version code on the fly
virtual Double_t GetValueForRoot(Double_t)
returns efficiency as function of cut
void ReadStateFromFile()
Function to write options and weights to file.
void WriteVarsToStream(std::ostream &tf, const TString &prefix="") const
write the list of variables (name, min, max) for a given data transformation method to the stream
void ReadVarsFromStream(std::istream &istr)
Read the variables (name, min, max) for a given data transformation method from the stream.
void ReadSpectatorsFromXML(void *specnode)
read spectator info from XML
void ReadVariablesFromXML(void *varnode)
read variable info from XML
virtual std::map< TString, Double_t > OptimizeTuningParameters(TString fomType="ROCIntegral", TString fitType="FitGA")
call the Optimizer with the set of parameters and ranges that are meant to be tuned.
virtual std::vector< Float_t > GetMulticlassTrainingEfficiency(std::vector< std::vector< Float_t > > &purity)
void WriteStateToStream(std::ostream &tf) const
general method used in writing the header of the weight files where the used variables,...
virtual Double_t GetRarity(Double_t mvaVal, Types::ESBType reftype=Types::kBackground) const
compute rarity:
virtual void SetTuneParameters(std::map< TString, Double_t > tuneParameters)
set the tuning parameters according to the argument This is just a dummy .
void ReadStateFromStream(std::istream &tf)
read the header from the weight files of the different MVA methods
void AddVarsXMLTo(void *parent) const
write variable info to XML
Double_t GetMvaValue(Double_t *errLower=nullptr, Double_t *errUpper=nullptr) override=0
void AddTargetsXMLTo(void *parent) const
write target info to XML
void ReadTargetsFromXML(void *tarnode)
read target info from XML
void ProcessBaseOptions()
the option string is decoded, for available options see "DeclareOptions"
void ReadStateFromXML(void *parent)
virtual std::vector< Float_t > GetAllRegressionValues()
Get al regression values in one call.
void NoErrorCalc(Double_t *const err, Double_t *const errUpper)
void WriteStateToFile() const
write options and weights to file note that each one text file for the main configuration information...
void AddClassesXMLTo(void *parent) const
write class info to XML
virtual void AddClassifierOutput(Types::ETreeType type)
prepare tree branch with the method's discriminating variable
void AddSpectatorsXMLTo(void *parent) const
write spectator info to XML
virtual Double_t GetROCIntegral(TH1D *histS, TH1D *histB) const
calculate the area (integral) under the ROC curve as a overall quality measure of the classification
virtual void AddMulticlassOutput(Types::ETreeType type)
prepare tree branch with the method's discriminating variable
virtual void CheckSetup()
check may be overridden by derived class (sometimes, eg, fitters are used which can only be implement...
void SetSource(const std::string &source)
Definition MsgLogger.h:68
PDF wrapper for histograms; uses user-defined spline interpolation.
Definition PDF.h:63
@ kSpline3
Definition PDF.h:70
@ kSpline2
Definition PDF.h:70
Class that is the base-class for a vector of result.
Class which takes the results of a multiclass classification.
Class that is the base-class for a vector of result.
Class that is the base-class for a vector of result.
Definition Results.h:57
Root finding using Brents algorithm (translated from CERNLIB function RZERO)
Definition RootFinder.h:48
Linear interpolation of TGraph.
Definition TSpline1.h:43
Timing information for training and evaluation of MVA methods.
Definition Timer.h:58
void ComputeStat(const std::vector< TMVA::Event * > &, std::vector< Float_t > *, Double_t &, Double_t &, Double_t &, Double_t &, Double_t &, Double_t &, Int_t signalClass, Bool_t norm=kFALSE)
sanity check
Definition Tools.cxx:203
TList * ParseFormatLine(TString theString, const char *sep=":")
Parse the string and cut into labels separated by ":".
Definition Tools.cxx:376
Double_t GetSeparation(TH1 *S, TH1 *B) const
compute "separation" defined as
Definition Tools.cxx:122
Double_t GetMutualInformation(const TH2F &)
Mutual Information method for non-linear correlations estimates in 2D histogram Author: Moritz Backes...
Definition Tools.cxx:564
const TString & Color(const TString &)
human readable color strings
Definition Tools.cxx:803
TXMLEngine & xmlengine()
Definition Tools.h:262
Bool_t CheckSplines(const TH1 *, const TSpline *)
check quality of splining by comparing splines and histograms in each bin
Definition Tools.cxx:454
void ReadAttr(void *node, const char *, T &value)
read attribute from xml
Definition Tools.h:329
void * GetChild(void *parent, const char *childname=nullptr)
get child node
Definition Tools.cxx:1125
void AddAttr(void *node, const char *, const T &value, Int_t precision=16)
add attribute to xml
Definition Tools.h:347
Double_t NormHist(TH1 *theHist, Double_t norm=1.0)
normalises histogram
Definition Tools.cxx:358
void * AddChild(void *parent, const char *childname, const char *content=nullptr, bool isRootNode=false)
add child node
Definition Tools.cxx:1099
void * GetNextChild(void *prevchild, const char *childname=nullptr)
XML helpers.
Definition Tools.cxx:1137
Singleton class for Global types used by TMVA.
Definition Types.h:71
@ kSignal
Never change this number - it is elsewhere assumed to be zero !
Definition Types.h:135
@ kBackground
Definition Types.h:136
@ kLikelihood
Definition Types.h:79
@ kHMatrix
Definition Types.h:81
@ kMulticlass
Definition Types.h:129
@ kNoAnalysisType
Definition Types.h:130
@ kClassification
Definition Types.h:127
@ kMaxAnalysisType
Definition Types.h:131
@ kRegression
Definition Types.h:128
@ kTraining
Definition Types.h:143
Linear interpolation class.
Gaussian Transformation of input variables.
Class for type info of MVA input variable.
Linear interpolation class.
Linear interpolation class.
Collectable string class.
Definition TObjString.h:28
Basic string class.
Definition TString.h:138
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:2068
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1170
const char * Data() const
Definition TString.h:386
@ kLeading
Definition TString.h:284
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2459
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:662
virtual const char * GetBuildNode() const
Return the build node name.
Definition TSystem.cxx:3968
virtual int mkdir(const char *name, Bool_t recursive=kFALSE)
Make a file system directory.
Definition TSystem.cxx:920
virtual const char * WorkingDirectory()
Return working directory.
Definition TSystem.cxx:885
virtual UserGroup_t * GetUserInfo(Int_t uid)
Returns all user info in the UserGroup_t structure.
Definition TSystem.cxx:1616
void SaveDoc(XMLDocPointer_t xmldoc, const char *filename, Int_t layout=1)
store document content to file if layout<=0, no any spaces or newlines will be placed between xmlnode...
void FreeDoc(XMLDocPointer_t xmldoc)
frees allocated document data and deletes document itself
XMLNodePointer_t DocGetRootElement(XMLDocPointer_t xmldoc)
returns root node of document
XMLDocPointer_t NewDoc(const char *version="1.0")
creates new xml document with provided version
XMLDocPointer_t ParseFile(const char *filename, Int_t maxbuf=100000)
Parses content of file and tries to produce xml structures.
XMLDocPointer_t ParseString(const char *xmlstring)
parses content of string and tries to produce xml structures
void DocSetRootElement(XMLDocPointer_t xmldoc, XMLNodePointer_t xmlnode)
set main (root) node for document
TLine * line
TH1F * h1
Definition legend1.C:5
Config & gConfig()
Tools & gTools()
void CreateVariableTransforms(const TString &trafoDefinition, TMVA::DataSetInfo &dataInfo, TMVA::TransformationHandler &transformationHandler, TMVA::MsgLogger &log)
MsgLogger & Endl(MsgLogger &ml)
Definition MsgLogger.h:148
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:675
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122