Logo ROOT   6.14/05
Reference Guide
MethodBDT.cxx
Go to the documentation of this file.
1 // Author: Andreas Hoecker, Joerg Stelzer, Helge Voss, Kai Voss, Eckhard v. Toerne, Jan Therhaag
2 
3 /**********************************************************************************
4  * Project: TMVA - a Root-integrated toolkit for multivariate data analysis *
5  * Package: TMVA *
6  * Class : MethodBDT (BDT = Boosted Decision Trees) *
7  * Web : http://tmva.sourceforge.net *
8  * *
9  * Description: *
10  * Analysis of Boosted Decision Trees *
11  * *
12  * Authors (alphabetical): *
13  * Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland *
14  * Helge Voss <Helge.Voss@cern.ch> - MPI-K Heidelberg, Germany *
15  * Kai Voss <Kai.Voss@cern.ch> - U. of Victoria, Canada *
16  * Doug Schouten <dschoute@sfu.ca> - Simon Fraser U., Canada *
17  * Jan Therhaag <jan.therhaag@cern.ch> - U. of Bonn, Germany *
18  * Eckhard v. Toerne <evt@uni-bonn.de> - U of Bonn, Germany *
19  * *
20  * Copyright (c) 2005-2011: *
21  * CERN, Switzerland *
22  * U. of Victoria, Canada *
23  * MPI-K Heidelberg, Germany *
24  * U. of Bonn, Germany *
25  * *
26  * Redistribution and use in source and binary forms, with or without *
27  * modification, are permitted according to the terms listed in LICENSE *
28  * (http://tmva.sourceforge.net/LICENSE) *
29  **********************************************************************************/
30 
31 /*! \class TMVA::MethodBDT
32 \ingroup TMVA
33 
34 Analysis of Boosted Decision Trees
35 
36 Boosted decision trees have been successfully used in High Energy
37 Physics analysis for example by the MiniBooNE experiment
38 (Yang-Roe-Zhu, physics/0508045). In Boosted Decision Trees, the
39 selection is done on a majority vote on the result of several decision
40 trees, which are all derived from the same training sample by
41 supplying different event weights during the training.
42 
43 ### Decision trees:
44 
45 Successive decision nodes are used to categorize the
46 events out of the sample as either signal or background. Each node
47 uses only a single discriminating variable to decide if the event is
48 signal-like ("goes right") or background-like ("goes left"). This
49 forms a tree like structure with "baskets" at the end (leave nodes),
50 and an event is classified as either signal or background according to
51 whether the basket where it ends up has been classified signal or
52 background during the training. Training of a decision tree is the
53 process to define the "cut criteria" for each node. The training
54 starts with the root node. Here one takes the full training event
55 sample and selects the variable and corresponding cut value that gives
56 the best separation between signal and background at this stage. Using
57 this cut criterion, the sample is then divided into two subsamples, a
58 signal-like (right) and a background-like (left) sample. Two new nodes
59 are then created for each of the two sub-samples and they are
60 constructed using the same mechanism as described for the root
61 node. The devision is stopped once a certain node has reached either a
62 minimum number of events, or a minimum or maximum signal purity. These
63 leave nodes are then called "signal" or "background" if they contain
64 more signal respective background events from the training sample.
65 
66 ### Boosting:
67 
68 The idea behind adaptive boosting (AdaBoost) is, that signal events
69 from the training sample, that end up in a background node
70 (and vice versa) are given a larger weight than events that are in
71 the correct leave node. This results in a re-weighed training event
72 sample, with which then a new decision tree can be developed.
73 The boosting can be applied several times (typically 100-500 times)
74 and one ends up with a set of decision trees (a forest).
75 Gradient boosting works more like a function expansion approach, where
76 each tree corresponds to a summand. The parameters for each summand (tree)
77 are determined by the minimization of a error function (binomial log-
78 likelihood for classification and Huber loss for regression).
79 A greedy algorithm is used, which means, that only one tree is modified
80 at a time, while the other trees stay fixed.
81 
82 ### Bagging:
83 
84 In this particular variant of the Boosted Decision Trees the boosting
85 is not done on the basis of previous training results, but by a simple
86 stochastic re-sampling of the initial training event sample.
87 
88 ### Random Trees:
89 
90 Similar to the "Random Forests" from Leo Breiman and Adele Cutler, it
91 uses the bagging algorithm together and bases the determination of the
92 best node-split during the training on a random subset of variables only
93 which is individually chosen for each split.
94 
95 ### Analysis:
96 
97 Applying an individual decision tree to a test event results in a
98 classification of the event as either signal or background. For the
99 boosted decision tree selection, an event is successively subjected to
100 the whole set of decision trees and depending on how often it is
101 classified as signal, a "likelihood" estimator is constructed for the
102 event being signal or background. The value of this estimator is the
103 one which is then used to select the events from an event sample, and
104 the cut value on this estimator defines the efficiency and purity of
105 the selection.
106 
107 */
108 
109 
110 #include "TMVA/MethodBDT.h"
111 #include "TMVA/Config.h"
112 
113 #include "TMVA/BDTEventWrapper.h"
114 #include "TMVA/BinarySearchTree.h"
115 #include "TMVA/ClassifierFactory.h"
116 #include "TMVA/Configurable.h"
117 #include "TMVA/CrossEntropy.h"
118 #include "TMVA/DecisionTree.h"
119 #include "TMVA/DataSet.h"
120 #include "TMVA/GiniIndex.h"
122 #include "TMVA/Interval.h"
123 #include "TMVA/IMethod.h"
124 #include "TMVA/LogInterval.h"
125 #include "TMVA/MethodBase.h"
127 #include "TMVA/MsgLogger.h"
129 #include "TMVA/PDF.h"
130 #include "TMVA/Ranking.h"
131 #include "TMVA/Results.h"
132 #include "TMVA/ResultsMulticlass.h"
133 #include "TMVA/SdivSqrtSplusB.h"
134 #include "TMVA/SeparationBase.h"
135 #include "TMVA/Timer.h"
136 #include "TMVA/Tools.h"
137 #include "TMVA/Types.h"
138 
139 #include "Riostream.h"
140 #include "TDirectory.h"
141 #include "TRandom3.h"
142 #include "TMath.h"
143 #include "TMatrixTSym.h"
144 #include "TObjString.h"
145 #include "TGraph.h"
146 
147 #include <algorithm>
148 #include <fstream>
149 #include <math.h>
150 #include <unordered_map>
151 
152 using std::vector;
153 using std::make_pair;
154 
156 
158 
160 
161 ////////////////////////////////////////////////////////////////////////////////
162 /// The standard constructor for the "boosted decision trees".
163 
165  const TString& methodTitle,
166  DataSetInfo& theData,
167  const TString& theOption ) :
168  TMVA::MethodBase( jobName, Types::kBDT, methodTitle, theData, theOption)
169  , fTrainSample(0)
170  , fNTrees(0)
171  , fSigToBkgFraction(0)
172  , fAdaBoostBeta(0)
173 // , fTransitionPoint(0)
174  , fShrinkage(0)
175  , fBaggedBoost(kFALSE)
176  , fBaggedGradBoost(kFALSE)
177 // , fSumOfWeights(0)
178  , fMinNodeEvents(0)
179  , fMinNodeSize(5)
180  , fMinNodeSizeS("5%")
181  , fNCuts(0)
182  , fUseFisherCuts(0) // don't use this initialisation, only here to make Coverity happy. Is set in DeclarOptions()
183  , fMinLinCorrForFisher(.8) // don't use this initialisation, only here to make Coverity happy. Is set in DeclarOptions()
184  , fUseExclusiveVars(0) // don't use this initialisation, only here to make Coverity happy. Is set in DeclarOptions()
185  , fUseYesNoLeaf(kFALSE)
186  , fNodePurityLimit(0)
187  , fNNodesMax(0)
188  , fMaxDepth(0)
189  , fPruneMethod(DecisionTree::kNoPruning)
190  , fPruneStrength(0)
191  , fFValidationEvents(0)
192  , fAutomatic(kFALSE)
193  , fRandomisedTrees(kFALSE)
194  , fUseNvars(0)
195  , fUsePoissonNvars(0) // don't use this initialisation, only here to make Coverity happy. Is set in Init()
196  , fUseNTrainEvents(0)
197  , fBaggedSampleFraction(0)
198  , fNoNegWeightsInTraining(kFALSE)
199  , fInverseBoostNegWeights(kFALSE)
200  , fPairNegWeightsGlobal(kFALSE)
201  , fTrainWithNegWeights(kFALSE)
202  , fDoBoostMonitor(kFALSE)
203  , fITree(0)
204  , fBoostWeight(0)
205  , fErrorFraction(0)
206  , fCss(0)
207  , fCts_sb(0)
208  , fCtb_ss(0)
209  , fCbb(0)
210  , fDoPreselection(kFALSE)
211  , fSkipNormalization(kFALSE)
212  , fHistoricBool(kFALSE)
213 {
214  fMonitorNtuple = NULL;
215  fSepType = NULL;
216  fRegressionLossFunctionBDTG = nullptr;
217 
218 #ifdef R__USE_IMT
220 #else
221  fNumPoolThreads = 1;
222 #endif
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 
228  const TString& theWeightFile)
229  : TMVA::MethodBase( Types::kBDT, theData, theWeightFile)
230  , fTrainSample(0)
231  , fNTrees(0)
232  , fSigToBkgFraction(0)
233  , fAdaBoostBeta(0)
234 // , fTransitionPoint(0)
235  , fShrinkage(0)
238 // , fSumOfWeights(0)
239  , fMinNodeEvents(0)
240  , fMinNodeSize(5)
241  , fMinNodeSizeS("5%")
242  , fNCuts(0)
243  , fUseFisherCuts(0) // don't use this initialisation, only here to make Coverity happy. Is set in DeclarOptions()
244  , fMinLinCorrForFisher(.8) // don't use this initialisation, only here to make Coverity happy. Is set in DeclarOptions()
245  , fUseExclusiveVars(0) // don't use this initialisation, only here to make Coverity happy. Is set in DeclarOptions()
247  , fNodePurityLimit(0)
248  , fNNodesMax(0)
249  , fMaxDepth(0)
250  , fPruneMethod(DecisionTree::kNoPruning)
251  , fPruneStrength(0)
252  , fFValidationEvents(0)
253  , fAutomatic(kFALSE)
255  , fUseNvars(0)
256  , fUsePoissonNvars(0) // don't use this initialisation, only here to make Coverity happy. Is set in Init()
257  , fUseNTrainEvents(0)
264  , fITree(0)
265  , fBoostWeight(0)
266  , fErrorFraction(0)
267  , fCss(0)
268  , fCts_sb(0)
269  , fCtb_ss(0)
270  , fCbb(0)
274 {
275  fMonitorNtuple = NULL;
276  fSepType = NULL;
277  fRegressionLossFunctionBDTG = nullptr;
278  // constructor for calculating BDT-MVA using previously generated decision trees
279  // the result of the previous training (the decision trees) are read in via the
280  // weight file. Make sure the the variables correspond to the ones used in
281  // creating the "weight"-file
282 
283 #ifdef R__USE_IMT
285 #else
286  fNumPoolThreads = 1;
287 #endif
288 }
289 
290 ////////////////////////////////////////////////////////////////////////////////
291 /// BDT can handle classification with multiple classes and regression with one regression-target.
292 
294 {
295  if (type == Types::kClassification && numberClasses == 2) return kTRUE;
296  if (type == Types::kMulticlass ) return kTRUE;
297  if( type == Types::kRegression && numberTargets == 1 ) return kTRUE;
298  return kFALSE;
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Define the options (their key words). That can be set in the option string.
303 ///
304 /// know options:
305 ///
306 /// - nTrees number of trees in the forest to be created
307 /// - BoostType the boosting type for the trees in the forest (AdaBoost e.t.c..).
308 /// Known:
309 /// - AdaBoost
310 /// - AdaBoostR2 (Adaboost for regression)
311 /// - Bagging
312 /// - GradBoost
313 /// - AdaBoostBeta the boosting parameter, beta, for AdaBoost
314 /// - UseRandomisedTrees choose at each node splitting a random set of variables
315 /// - UseNvars use UseNvars variables in randomised trees
316 /// - UsePoisson Nvars use UseNvars not as fixed number but as mean of a poisson distribution
317 /// - SeparationType the separation criterion applied in the node splitting.
318 /// Known:
319 /// - GiniIndex
320 /// - MisClassificationError
321 /// - CrossEntropy
322 /// - SDivSqrtSPlusB
323 /// - MinNodeSize: minimum percentage of training events in a leaf node (leaf criteria, stop splitting)
324 /// - nCuts: the number of steps in the optimisation of the cut for a node (if < 0, then
325 /// step size is determined by the events)
326 /// - UseFisherCuts: use multivariate splits using the Fisher criterion
327 /// - UseYesNoLeaf decide if the classification is done simply by the node type, or the S/B
328 /// (from the training) in the leaf node
329 /// - NodePurityLimit the minimum purity to classify a node as a signal node (used in pruning and boosting to determine
330 /// misclassification error rate)
331 /// - PruneMethod The Pruning method.
332 /// Known:
333 /// - NoPruning // switch off pruning completely
334 /// - ExpectedError
335 /// - CostComplexity
336 /// - PruneStrength a parameter to adjust the amount of pruning. Should be large enough such that overtraining is avoided.
337 /// - PruningValFraction number of events to use for optimizing pruning (only if PruneStrength < 0, i.e. automatic pruning)
338 /// - NegWeightTreatment
339 /// - IgnoreNegWeightsInTraining Ignore negative weight events in the training.
340 /// - DecreaseBoostWeight Boost ev. with neg. weight with 1/boostweight instead of boostweight
341 /// - PairNegWeightsGlobal Pair ev. with neg. and pos. weights in training sample and "annihilate" them
342 /// - MaxDepth maximum depth of the decision tree allowed before further splitting is stopped
343 /// - SkipNormalization Skip normalization at initialization, to keep expectation value of BDT output
344 /// according to the fraction of events
345 
347 {
348  DeclareOptionRef(fNTrees, "NTrees", "Number of trees in the forest");
349  if (DoRegression()) {
350  DeclareOptionRef(fMaxDepth=50,"MaxDepth","Max depth of the decision tree allowed");
351  }else{
352  DeclareOptionRef(fMaxDepth=3,"MaxDepth","Max depth of the decision tree allowed");
353  }
354 
355  TString tmp="5%"; if (DoRegression()) tmp="0.2%";
356  DeclareOptionRef(fMinNodeSizeS=tmp, "MinNodeSize", "Minimum percentage of training events required in a leaf node (default: Classification: 5%, Regression: 0.2%)");
357  // MinNodeSize: minimum percentage of training events in a leaf node (leaf criteria, stop splitting)
358  DeclareOptionRef(fNCuts, "nCuts", "Number of grid points in variable range used in finding optimal cut in node splitting");
359 
360  DeclareOptionRef(fBoostType, "BoostType", "Boosting type for the trees in the forest (note: AdaCost is still experimental)");
361 
362  AddPreDefVal(TString("AdaBoost"));
363  AddPreDefVal(TString("RealAdaBoost"));
364  AddPreDefVal(TString("AdaCost"));
365  AddPreDefVal(TString("Bagging"));
366  // AddPreDefVal(TString("RegBoost"));
367  AddPreDefVal(TString("AdaBoostR2"));
368  AddPreDefVal(TString("Grad"));
369  if (DoRegression()) {
370  fBoostType = "AdaBoostR2";
371  }else{
372  fBoostType = "AdaBoost";
373  }
374  DeclareOptionRef(fAdaBoostR2Loss="Quadratic", "AdaBoostR2Loss", "Type of Loss function in AdaBoostR2");
375  AddPreDefVal(TString("Linear"));
376  AddPreDefVal(TString("Quadratic"));
377  AddPreDefVal(TString("Exponential"));
378 
379  DeclareOptionRef(fBaggedBoost=kFALSE, "UseBaggedBoost","Use only a random subsample of all events for growing the trees in each boost iteration.");
380  DeclareOptionRef(fShrinkage=1.0, "Shrinkage", "Learning rate for GradBoost algorithm");
381  DeclareOptionRef(fAdaBoostBeta=.5, "AdaBoostBeta", "Learning rate for AdaBoost algorithm");
382  DeclareOptionRef(fRandomisedTrees,"UseRandomisedTrees","Determine at each node splitting the cut variable only as the best out of a random subset of variables (like in RandomForests)");
383  DeclareOptionRef(fUseNvars,"UseNvars","Size of the subset of variables used with RandomisedTree option");
384  DeclareOptionRef(fUsePoissonNvars,"UsePoissonNvars", "Interpret \"UseNvars\" not as fixed number but as mean of a Poisson distribution in each split with RandomisedTree option");
385  DeclareOptionRef(fBaggedSampleFraction=.6,"BaggedSampleFraction","Relative size of bagged event sample to original size of the data sample (used whenever bagging is used (i.e. UseBaggedBoost, Bagging,)" );
386 
387  DeclareOptionRef(fUseYesNoLeaf=kTRUE, "UseYesNoLeaf",
388  "Use Sig or Bkg categories, or the purity=S/(S+B) as classification of the leaf node -> Real-AdaBoost");
389  if (DoRegression()) {
391  }
392 
393  DeclareOptionRef(fNegWeightTreatment="InverseBoostNegWeights","NegWeightTreatment","How to treat events with negative weights in the BDT training (particular the boosting) : IgnoreInTraining; Boost With inverse boostweight; Pair events with negative and positive weights in training sample and *annihilate* them (experimental!)");
394  AddPreDefVal(TString("InverseBoostNegWeights"));
395  AddPreDefVal(TString("IgnoreNegWeightsInTraining"));
396  AddPreDefVal(TString("NoNegWeightsInTraining")); // well, let's be nice to users and keep at least this old name anyway ..
397  AddPreDefVal(TString("PairNegWeightsGlobal"));
398  AddPreDefVal(TString("Pray"));
399 
400 
401 
402  DeclareOptionRef(fCss=1., "Css", "AdaCost: cost of true signal selected signal");
403  DeclareOptionRef(fCts_sb=1.,"Cts_sb","AdaCost: cost of true signal selected bkg");
404  DeclareOptionRef(fCtb_ss=1.,"Ctb_ss","AdaCost: cost of true bkg selected signal");
405  DeclareOptionRef(fCbb=1., "Cbb", "AdaCost: cost of true bkg selected bkg ");
406 
407  DeclareOptionRef(fNodePurityLimit=0.5, "NodePurityLimit", "In boosting/pruning, nodes with purity > NodePurityLimit are signal; background otherwise.");
408 
409 
410  DeclareOptionRef(fSepTypeS, "SeparationType", "Separation criterion for node splitting");
411  AddPreDefVal(TString("CrossEntropy"));
412  AddPreDefVal(TString("GiniIndex"));
413  AddPreDefVal(TString("GiniIndexWithLaplace"));
414  AddPreDefVal(TString("MisClassificationError"));
415  AddPreDefVal(TString("SDivSqrtSPlusB"));
416  AddPreDefVal(TString("RegressionVariance"));
417  if (DoRegression()) {
418  fSepTypeS = "RegressionVariance";
419  }else{
420  fSepTypeS = "GiniIndex";
421  }
422 
423  DeclareOptionRef(fRegressionLossFunctionBDTGS = "Huber", "RegressionLossFunctionBDTG", "Loss function for BDTG regression.");
424  AddPreDefVal(TString("Huber"));
425  AddPreDefVal(TString("AbsoluteDeviation"));
426  AddPreDefVal(TString("LeastSquares"));
427 
428  DeclareOptionRef(fHuberQuantile = 0.7, "HuberQuantile", "In the Huber loss function this is the quantile that separates the core from the tails in the residuals distribution.");
429 
430  DeclareOptionRef(fDoBoostMonitor=kFALSE,"DoBoostMonitor","Create control plot with ROC integral vs tree number");
431 
432  DeclareOptionRef(fUseFisherCuts=kFALSE, "UseFisherCuts", "Use multivariate splits using the Fisher criterion");
433  DeclareOptionRef(fMinLinCorrForFisher=.8,"MinLinCorrForFisher", "The minimum linear correlation between two variables demanded for use in Fisher criterion in node splitting");
434  DeclareOptionRef(fUseExclusiveVars=kFALSE,"UseExclusiveVars","Variables already used in fisher criterion are not anymore analysed individually for node splitting");
435 
436 
437  DeclareOptionRef(fDoPreselection=kFALSE,"DoPreselection","and and apply automatic pre-selection for 100% efficient signal (bkg) cuts prior to training");
438 
439 
440  DeclareOptionRef(fSigToBkgFraction=1,"SigToBkgFraction","Sig to Bkg ratio used in Training (similar to NodePurityLimit, which cannot be used in real adaboost");
441 
442  DeclareOptionRef(fPruneMethodS, "PruneMethod", "Note: for BDTs use small trees (e.g.MaxDepth=3) and NoPruning: Pruning: Method used for pruning (removal) of statistically insignificant branches ");
443  AddPreDefVal(TString("NoPruning"));
444  AddPreDefVal(TString("ExpectedError"));
445  AddPreDefVal(TString("CostComplexity"));
446 
447  DeclareOptionRef(fPruneStrength, "PruneStrength", "Pruning strength");
448 
449  DeclareOptionRef(fFValidationEvents=0.5, "PruningValFraction", "Fraction of events to use for optimizing automatic pruning.");
450 
451  DeclareOptionRef(fSkipNormalization=kFALSE, "SkipNormalization", "Skip normalization at initialization, to keep expectation value of BDT output according to the fraction of events");
452 
453  // deprecated options, still kept for the moment:
454  DeclareOptionRef(fMinNodeEvents=0, "nEventsMin", "deprecated: Use MinNodeSize (in % of training events) instead");
455 
456  DeclareOptionRef(fBaggedGradBoost=kFALSE, "UseBaggedGrad","deprecated: Use *UseBaggedBoost* instead: Use only a random subsample of all events for growing the trees in each iteration.");
457  DeclareOptionRef(fBaggedSampleFraction, "GradBaggingFraction","deprecated: Use *BaggedSampleFraction* instead: Defines the fraction of events to be used in each iteration, e.g. when UseBaggedGrad=kTRUE. ");
458  DeclareOptionRef(fUseNTrainEvents,"UseNTrainEvents","deprecated: Use *BaggedSampleFraction* instead: Number of randomly picked training events used in randomised (and bagged) trees");
459  DeclareOptionRef(fNNodesMax,"NNodesMax","deprecated: Use MaxDepth instead to limit the tree size" );
460 
461 
462 }
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// Options that are used ONLY for the READER to ensure backward compatibility.
466 
469 
470 
471  DeclareOptionRef(fHistoricBool=kTRUE, "UseWeightedTrees",
472  "Use weighted trees or simple average in classification from the forest");
473  DeclareOptionRef(fHistoricBool=kFALSE, "PruneBeforeBoost", "Flag to prune the tree before applying boosting algorithm");
474  DeclareOptionRef(fHistoricBool=kFALSE,"RenormByClass","Individually re-normalize each event class to the original size after boosting");
475 
476  AddPreDefVal(TString("NegWeightTreatment"),TString("IgnoreNegWeights"));
477 
478 }
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 /// The option string is decoded, for available options see "DeclareOptions".
482 
484 {
485  fSepTypeS.ToLower();
486  if (fSepTypeS == "misclassificationerror") fSepType = new MisClassificationError();
487  else if (fSepTypeS == "giniindex") fSepType = new GiniIndex();
488  else if (fSepTypeS == "giniindexwithlaplace") fSepType = new GiniIndexWithLaplace();
489  else if (fSepTypeS == "crossentropy") fSepType = new CrossEntropy();
490  else if (fSepTypeS == "sdivsqrtsplusb") fSepType = new SdivSqrtSplusB();
491  else if (fSepTypeS == "regressionvariance") fSepType = NULL;
492  else {
493  Log() << kINFO << GetOptions() << Endl;
494  Log() << kFATAL << "<ProcessOptions> unknown Separation Index option " << fSepTypeS << " called" << Endl;
495  }
496 
497  if(!(fHuberQuantile >= 0.0 && fHuberQuantile <= 1.0)){
498  Log() << kINFO << GetOptions() << Endl;
499  Log() << kFATAL << "<ProcessOptions> Huber Quantile must be in range [0,1]. Value given, " << fHuberQuantile << ", does not match this criteria" << Endl;
500  }
501 
502 
507  else {
508  Log() << kINFO << GetOptions() << Endl;
509  Log() << kFATAL << "<ProcessOptions> unknown Regression Loss Function BDT option " << fRegressionLossFunctionBDTGS << " called" << Endl;
510  }
511 
514  else if (fPruneMethodS == "costcomplexity") fPruneMethod = DecisionTree::kCostComplexityPruning;
515  else if (fPruneMethodS == "nopruning") fPruneMethod = DecisionTree::kNoPruning;
516  else {
517  Log() << kINFO << GetOptions() << Endl;
518  Log() << kFATAL << "<ProcessOptions> unknown PruneMethod " << fPruneMethodS << " option called" << Endl;
519  }
521  else fAutomatic = kFALSE;
523  Log() << kFATAL
524  << "Sorry automatic pruning strength determination is not implemented yet for ExpectedErrorPruning" << Endl;
525  }
526 
527 
528  if (fMinNodeEvents > 0){
530  Log() << kWARNING << "You have explicitly set ** nEventsMin = " << fMinNodeEvents<<" ** the min absolute number \n"
531  << "of events in a leaf node. This is DEPRECATED, please use the option \n"
532  << "*MinNodeSize* giving the relative number as percentage of training \n"
533  << "events instead. \n"
534  << "nEventsMin="<<fMinNodeEvents<< "--> MinNodeSize="<<fMinNodeSize<<"%"
535  << Endl;
536  Log() << kWARNING << "Note also that explicitly setting *nEventsMin* so far OVERWRITES the option recommended \n"
537  << " *MinNodeSize* = " << fMinNodeSizeS << " option !!" << Endl ;
538  fMinNodeSizeS = Form("%F3.2",fMinNodeSize);
539 
540  }else{
542  }
543 
544 
546 
547  if (fBoostType=="Grad") {
549  if (fNegWeightTreatment=="InverseBoostNegWeights"){
550  Log() << kINFO << "the option *InverseBoostNegWeights* does not exist for BoostType=Grad --> change" << Endl;
551  Log() << kINFO << "to new default for GradBoost *Pray*" << Endl;
552  Log() << kDEBUG << "i.e. simply keep them as if which should work fine for Grad Boost" << Endl;
553  fNegWeightTreatment="Pray";
555  }
556  } else if (fBoostType=="RealAdaBoost"){
557  fBoostType = "AdaBoost";
559  } else if (fBoostType=="AdaCost"){
561  }
562 
563  if (fFValidationEvents < 0.0) fFValidationEvents = 0.0;
564  if (fAutomatic && fFValidationEvents > 0.5) {
565  Log() << kWARNING << "You have chosen to use more than half of your training sample "
566  << "to optimize the automatic pruning algorithm. This is probably wasteful "
567  << "and your overall results will be degraded. Are you sure you want this?"
568  << Endl;
569  }
570 
571 
572  if (this->Data()->HasNegativeEventWeights()){
573  Log() << kINFO << " You are using a Monte Carlo that has also negative weights. "
574  << "That should in principle be fine as long as on average you end up with "
575  << "something positive. For this you have to make sure that the minimal number "
576  << "of (un-weighted) events demanded for a tree node (currently you use: MinNodeSize="
577  << fMinNodeSizeS << " ("<< fMinNodeSize << "%)"
578  <<", (or the deprecated equivalent nEventsMin) you can set this via the "
579  <<"BDT option string when booking the "
580  << "classifier) is large enough to allow for reasonable averaging!!! "
581  << " If this does not help.. maybe you want to try the option: IgnoreNegWeightsInTraining "
582  << "which ignores events with negative weight in the training. " << Endl
583  << Endl << "Note: You'll get a WARNING message during the training if that should ever happen" << Endl;
584  }
585 
586  if (DoRegression()) {
588  Log() << kWARNING << "Regression Trees do not work with fUseYesNoLeaf=TRUE --> I will set it to FALSE" << Endl;
590  }
591 
592  if (fSepType != NULL){
593  Log() << kWARNING << "Regression Trees do not work with Separation type other than <RegressionVariance> --> I will use it instead" << Endl;
594  fSepType = NULL;
595  }
596  if (fUseFisherCuts){
597  Log() << kWARNING << "Sorry, UseFisherCuts is not available for regression analysis, I will ignore it!" << Endl;
599  }
600  if (fNCuts < 0) {
601  Log() << kWARNING << "Sorry, the option of nCuts<0 using a more elaborate node splitting algorithm " << Endl;
602  Log() << kWARNING << "is not implemented for regression analysis ! " << Endl;
603  Log() << kWARNING << "--> I switch do default nCuts = 20 and use standard node splitting"<<Endl;
604  fNCuts=20;
605  }
606  }
607  if (fRandomisedTrees){
608  Log() << kINFO << " Randomised trees use no pruning" << Endl;
610  // fBoostType = "Bagging";
611  }
612 
613  if (fUseFisherCuts) {
614  Log() << kWARNING << "When using the option UseFisherCuts, the other option nCuts<0 (i.e. using" << Endl;
615  Log() << " a more elaborate node splitting algorithm) is not implemented. " << Endl;
616  //I will switch o " << Endl;
617  //Log() << "--> I switch do default nCuts = 20 and use standard node splitting WITH possible Fisher criteria"<<Endl;
618  fNCuts=20;
619  }
620 
621  if (fNTrees==0){
622  Log() << kERROR << " Zero Decision Trees demanded... that does not work !! "
623  << " I set it to 1 .. just so that the program does not crash"
624  << Endl;
625  fNTrees = 1;
626  }
627 
629  if (fNegWeightTreatment == "ignorenegweightsintraining") fNoNegWeightsInTraining = kTRUE;
630  else if (fNegWeightTreatment == "nonegweightsintraining") fNoNegWeightsInTraining = kTRUE;
631  else if (fNegWeightTreatment == "inverseboostnegweights") fInverseBoostNegWeights = kTRUE;
632  else if (fNegWeightTreatment == "pairnegweightsglobal") fPairNegWeightsGlobal = kTRUE;
633  else if (fNegWeightTreatment == "pray") Log() << kDEBUG << "Yes, good luck with praying " << Endl;
634  else {
635  Log() << kINFO << GetOptions() << Endl;
636  Log() << kFATAL << "<ProcessOptions> unknown option for treating negative event weights during training " << fNegWeightTreatment << " requested" << Endl;
637  }
638 
639  if (fNegWeightTreatment == "pairnegweightsglobal")
640  Log() << kWARNING << " you specified the option NegWeightTreatment=PairNegWeightsGlobal : This option is still considered EXPERIMENTAL !! " << Endl;
641 
642 
643  // dealing with deprecated options !
644  if (fNNodesMax>0) {
645  UInt_t tmp=1; // depth=0 == 1 node
646  fMaxDepth=0;
647  while (tmp < fNNodesMax){
648  tmp+=2*tmp;
649  fMaxDepth++;
650  }
651  Log() << kWARNING << "You have specified a deprecated option *NNodesMax="<<fNNodesMax
652  << "* \n this has been translated to MaxDepth="<<fMaxDepth<<Endl;
653  }
654 
655 
656  if (fUseNTrainEvents>0){
658  Log() << kWARNING << "You have specified a deprecated option *UseNTrainEvents="<<fUseNTrainEvents
659  << "* \n this has been translated to BaggedSampleFraction="<<fBaggedSampleFraction<<"(%)"<<Endl;
660  }
661 
662  if (fBoostType=="Bagging") fBaggedBoost = kTRUE;
663  if (fBaggedGradBoost){
665  Log() << kWARNING << "You have specified a deprecated option *UseBaggedGrad* --> please use *UseBaggedBoost* instead" << Endl;
666  }
667 
668 }
669 
670 ////////////////////////////////////////////////////////////////////////////////
671 
673  if (sizeInPercent > 0 && sizeInPercent < 50){
674  fMinNodeSize=sizeInPercent;
675 
676  } else {
677  Log() << kFATAL << "you have demanded a minimal node size of "
678  << sizeInPercent << "% of the training events.. \n"
679  << " that somehow does not make sense "<<Endl;
680  }
681 
682 }
683 
684 ////////////////////////////////////////////////////////////////////////////////
685 
687  sizeInPercent.ReplaceAll("%","");
688  sizeInPercent.ReplaceAll(" ","");
689  if (sizeInPercent.IsFloat()) SetMinNodeSize(sizeInPercent.Atof());
690  else {
691  Log() << kFATAL << "I had problems reading the option MinNodeEvents, which "
692  << "after removing a possible % sign now reads " << sizeInPercent << Endl;
693  }
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////
697 /// Common initialisation with defaults for the BDT-Method.
698 
700 {
701  fNTrees = 800;
703  fMaxDepth = 3;
704  fBoostType = "AdaBoost";
705  if(DataInfo().GetNClasses()!=0) //workaround for multiclass application
706  fMinNodeSize = 5.;
707  }else {
708  fMaxDepth = 50;
709  fBoostType = "AdaBoostR2";
710  fAdaBoostR2Loss = "Quadratic";
711  if(DataInfo().GetNClasses()!=0) //workaround for multiclass application
712  fMinNodeSize = .2;
713  }
714 
715 
716  fNCuts = 20;
717  fPruneMethodS = "NoPruning";
719  fPruneStrength = 0;
720  fAutomatic = kFALSE;
721  fFValidationEvents = 0.5;
723  // fUseNvars = (GetNvar()>12) ? UInt_t(GetNvar()/8) : TMath::Max(UInt_t(2),UInt_t(GetNvar()/3));
726  fShrinkage = 1.0;
727 // fSumOfWeights = 0.0;
728 
729  // reference cut value to distinguish signal-like from background-like events
731 }
732 
733 
734 ////////////////////////////////////////////////////////////////////////////////
735 /// Reset the method, as if it had just been instantiated (forget all training etc.).
736 
738 {
739  // I keep the BDT EventSample and its Validation sample (eventually they should all
740  // disappear and just use the DataSet samples ..
741 
742  // remove all the trees
743  for (UInt_t i=0; i<fForest.size(); i++) delete fForest[i];
744  fForest.clear();
745 
746  fBoostWeights.clear();
748  fVariableImportance.clear();
749  fResiduals.clear();
750  fLossFunctionEventInfo.clear();
751  // now done in "InitEventSample" which is called in "Train"
752  // reset all previously stored/accumulated BOOST weights in the event sample
753  //for (UInt_t iev=0; iev<fEventSample.size(); iev++) fEventSample[iev]->SetBoostWeight(1.);
755  Log() << kDEBUG << " successfully(?) reset the method " << Endl;
756 }
757 
758 
759 ////////////////////////////////////////////////////////////////////////////////
760 /// Destructor.
761 ///
762 /// - Note: fEventSample and ValidationSample are already deleted at the end of TRAIN
763 /// When they are not used anymore
764 
766 {
767  for (UInt_t i=0; i<fForest.size(); i++) delete fForest[i];
768 }
769 
770 ////////////////////////////////////////////////////////////////////////////////
771 /// Initialize the event sample (i.e. reset the boost-weights... etc).
772 
774 {
775  if (!HasTrainingTree()) Log() << kFATAL << "<Init> Data().TrainingTree() is zero pointer" << Endl;
776 
777  if (fEventSample.size() > 0) { // do not re-initialise the event sample, just set all boostweights to 1. as if it were untouched
778  // reset all previously stored/accumulated BOOST weights in the event sample
779  for (UInt_t iev=0; iev<fEventSample.size(); iev++) fEventSample[iev]->SetBoostWeight(1.);
780  } else {
782  UInt_t nevents = Data()->GetNTrainingEvents();
783 
784  std::vector<const TMVA::Event*> tmpEventSample;
785  for (Long64_t ievt=0; ievt<nevents; ievt++) {
786  // const Event *event = new Event(*(GetEvent(ievt)));
787  Event* event = new Event( *GetTrainingEvent(ievt) );
788  tmpEventSample.push_back(event);
789  }
790 
791  if (!DoRegression()) DeterminePreselectionCuts(tmpEventSample);
792  else fDoPreselection = kFALSE; // just to make sure...
793 
794  for (UInt_t i=0; i<tmpEventSample.size(); i++) delete tmpEventSample[i];
795 
796 
797  Bool_t firstNegWeight=kTRUE;
798  Bool_t firstZeroWeight=kTRUE;
799  for (Long64_t ievt=0; ievt<nevents; ievt++) {
800  // const Event *event = new Event(*(GetEvent(ievt)));
801  // const Event* event = new Event( *GetTrainingEvent(ievt) );
802  Event* event = new Event( *GetTrainingEvent(ievt) );
803  if (fDoPreselection){
804  if (TMath::Abs(ApplyPreselectionCuts(event)) > 0.05) {
805  delete event;
806  continue;
807  }
808  }
809 
810  if (event->GetWeight() < 0 && (IgnoreEventsWithNegWeightsInTraining() || fNoNegWeightsInTraining)){
811  if (firstNegWeight) {
812  Log() << kWARNING << " Note, you have events with negative event weight in the sample, but you've chosen to ignore them" << Endl;
813  firstNegWeight=kFALSE;
814  }
815  delete event;
816  }else if (event->GetWeight()==0){
817  if (firstZeroWeight) {
818  firstZeroWeight = kFALSE;
819  Log() << "Events with weight == 0 are going to be simply ignored " << Endl;
820  }
821  delete event;
822  }else{
823  if (event->GetWeight() < 0) {
825  if (firstNegWeight){
826  firstNegWeight = kFALSE;
828  Log() << kWARNING << "Events with negative event weights are found and "
829  << " will be removed prior to the actual BDT training by global "
830  << " paring (and subsequent annihilation) with positiv weight events"
831  << Endl;
832  }else{
833  Log() << kWARNING << "Events with negative event weights are USED during "
834  << "the BDT training. This might cause problems with small node sizes "
835  << "or with the boosting. Please remove negative events from training "
836  << "using the option *IgnoreEventsWithNegWeightsInTraining* in case you "
837  << "observe problems with the boosting"
838  << Endl;
839  }
840  }
841  }
842  // if fAutomatic == true you need a validation sample to optimize pruning
843  if (fAutomatic) {
844  Double_t modulo = 1.0/(fFValidationEvents);
845  Int_t imodulo = static_cast<Int_t>( fmod(modulo,1.0) > 0.5 ? ceil(modulo) : floor(modulo) );
846  if (ievt % imodulo == 0) fValidationSample.push_back( event );
847  else fEventSample.push_back( event );
848  }
849  else {
850  fEventSample.push_back(event);
851  }
852  }
853  }
854 
855  if (fAutomatic) {
856  Log() << kINFO << "<InitEventSample> Internally I use " << fEventSample.size()
857  << " for Training and " << fValidationSample.size()
858  << " for Pruning Validation (" << ((Float_t)fValidationSample.size())/((Float_t)fEventSample.size()+fValidationSample.size())*100.0
859  << "% of training used for validation)" << Endl;
860  }
861 
862  // some pre-processing for events with negative weights
864  }
865 
866  if (DoRegression()) {
867  // Regression, no reweighting to do
868  } else if (DoMulticlass()) {
869  // Multiclass, only gradboost is supported. No reweighting.
870  } else if (!fSkipNormalization) {
871  // Binary classification.
872  Log() << kDEBUG << "\t<InitEventSample> For classification trees, "<< Endl;
873  Log() << kDEBUG << " \tthe effective number of backgrounds is scaled to match "<<Endl;
874  Log() << kDEBUG << " \tthe signal. Otherwise the first boosting step would do 'just that'!"<<Endl;
875  // it does not make sense in decision trees to start with unequal number of signal/background
876  // events (weights) .. hence normalize them now (happens otherwise in first 'boosting step'
877  // anyway..
878  // Also make sure, that the sum_of_weights == sample.size() .. as this is assumed in
879  // the DecisionTree to derive a sensible number for "fMinSize" (min.#events in node)
880  // that currently is an OR between "weighted" and "unweighted number"
881  // I want:
882  // nS + nB = n
883  // a*SW + b*BW = n
884  // (a*SW)/(b*BW) = fSigToBkgFraction
885  //
886  // ==> b = n/((1+f)BW) and a = (nf/(1+f))/SW
887 
888  Double_t nevents = fEventSample.size();
889  Double_t sumSigW=0, sumBkgW=0;
890  Int_t sumSig=0, sumBkg=0;
891  for (UInt_t ievt=0; ievt<fEventSample.size(); ievt++) {
892  if ((DataInfo().IsSignal(fEventSample[ievt])) ) {
893  sumSigW += fEventSample[ievt]->GetWeight();
894  sumSig++;
895  } else {
896  sumBkgW += fEventSample[ievt]->GetWeight();
897  sumBkg++;
898  }
899  }
900  if (sumSigW && sumBkgW){
901  Double_t normSig = nevents/((1+fSigToBkgFraction)*sumSigW)*fSigToBkgFraction;
902  Double_t normBkg = nevents/((1+fSigToBkgFraction)*sumBkgW); ;
903  Log() << kDEBUG << "\tre-normalise events such that Sig and Bkg have respective sum of weights = "
904  << fSigToBkgFraction << Endl;
905  Log() << kDEBUG << " \tsig->sig*"<<normSig << "ev. bkg->bkg*"<<normBkg << "ev." <<Endl;
906  Log() << kHEADER << "#events: (reweighted) sig: "<< sumSigW*normSig << " bkg: " << sumBkgW*normBkg << Endl;
907  Log() << kINFO << "#events: (unweighted) sig: "<< sumSig << " bkg: " << sumBkg << Endl;
908  for (Long64_t ievt=0; ievt<nevents; ievt++) {
909  if ((DataInfo().IsSignal(fEventSample[ievt])) ) fEventSample[ievt]->SetBoostWeight(normSig);
910  else fEventSample[ievt]->SetBoostWeight(normBkg);
911  }
912  }else{
913  Log() << kINFO << "--> could not determine scaling factors as either there are " << Endl;
914  Log() << kINFO << " no signal events (sumSigW="<<sumSigW<<") or no bkg ev. (sumBkgW="<<sumBkgW<<")"<<Endl;
915  }
916 
917  }
918 
920  if (fBaggedBoost){
923  }
924 
925  //just for debug purposes..
926  /*
927  sumSigW=0;
928  sumBkgW=0;
929  for (UInt_t ievt=0; ievt<fEventSample.size(); ievt++) {
930  if ((DataInfo().IsSignal(fEventSample[ievt])) ) sumSigW += fEventSample[ievt]->GetWeight();
931  else sumBkgW += fEventSample[ievt]->GetWeight();
932  }
933  Log() << kWARNING << "sigSumW="<<sumSigW<<"bkgSumW="<<sumBkgW<< Endl;
934  */
935 }
936 
937 ////////////////////////////////////////////////////////////////////////////////
938 /// O.k. you know there are events with negative event weights. This routine will remove
939 /// them by pairing them with the closest event(s) of the same event class with positive
940 /// weights
941 /// A first attempt is "brute force", I dont' try to be clever using search trees etc,
942 /// just quick and dirty to see if the result is any good
943 
945  Double_t totalNegWeights = 0;
946  Double_t totalPosWeights = 0;
947  Double_t totalWeights = 0;
948  std::vector<const Event*> negEvents;
949  for (UInt_t iev = 0; iev < fEventSample.size(); iev++){
950  if (fEventSample[iev]->GetWeight() < 0) {
951  totalNegWeights += fEventSample[iev]->GetWeight();
952  negEvents.push_back(fEventSample[iev]);
953  } else {
954  totalPosWeights += fEventSample[iev]->GetWeight();
955  }
956  totalWeights += fEventSample[iev]->GetWeight();
957  }
958  if (totalNegWeights == 0 ) {
959  Log() << kINFO << "no negative event weights found .. no preprocessing necessary" << Endl;
960  return;
961  } else {
962  Log() << kINFO << "found a total of " << totalNegWeights << " of negative event weights which I am going to try to pair with positive events to annihilate them" << Endl;
963  Log() << kINFO << "found a total of " << totalPosWeights << " of events with positive weights" << Endl;
964  Log() << kINFO << "--> total sum of weights = " << totalWeights << " = " << totalNegWeights+totalPosWeights << Endl;
965  }
966 
967  std::vector<TMatrixDSym*>* cov = gTools().CalcCovarianceMatrices( fEventSample, 2);
968 
969  TMatrixDSym *invCov;
970 
971  for (Int_t i=0; i<2; i++){
972  invCov = ((*cov)[i]);
973  if ( TMath::Abs(invCov->Determinant()) < 10E-24 ) {
974  std::cout << "<MethodBDT::PreProcessNeg...> matrix is almost singular with determinant="
975  << TMath::Abs(invCov->Determinant())
976  << " did you use the variables that are linear combinations or highly correlated?"
977  << std::endl;
978  }
979  if ( TMath::Abs(invCov->Determinant()) < 10E-120 ) {
980  std::cout << "<MethodBDT::PreProcessNeg...> matrix is singular with determinant="
981  << TMath::Abs(invCov->Determinant())
982  << " did you use the variables that are linear combinations?"
983  << std::endl;
984  }
985 
986  invCov->Invert();
987  }
988 
989 
990 
991  Log() << kINFO << "Found a total of " << totalNegWeights << " in negative weights out of " << fEventSample.size() << " training events " << Endl;
992  Timer timer(negEvents.size(),"Negative Event paired");
993  for (UInt_t nev = 0; nev < negEvents.size(); nev++){
994  timer.DrawProgressBar( nev );
995  Double_t weight = negEvents[nev]->GetWeight();
996  UInt_t iClassID = negEvents[nev]->GetClass();
997  invCov = ((*cov)[iClassID]);
998  while (weight < 0){
999  // find closest event with positive event weight and "pair" it with the negative event
1000  // (add their weight) until there is no negative weight anymore
1001  Int_t iMin=-1;
1002  Double_t dist, minDist=10E270;
1003  for (UInt_t iev = 0; iev < fEventSample.size(); iev++){
1004  if (iClassID==fEventSample[iev]->GetClass() && fEventSample[iev]->GetWeight() > 0){
1005  dist=0;
1006  for (UInt_t ivar=0; ivar < GetNvar(); ivar++){
1007  for (UInt_t jvar=0; jvar<GetNvar(); jvar++){
1008  dist += (negEvents[nev]->GetValue(ivar)-fEventSample[iev]->GetValue(ivar))*
1009  (*invCov)[ivar][jvar]*
1010  (negEvents[nev]->GetValue(jvar)-fEventSample[iev]->GetValue(jvar));
1011  }
1012  }
1013  if (dist < minDist) { iMin=iev; minDist=dist;}
1014  }
1015  }
1016 
1017  if (iMin > -1) {
1018  // std::cout << "Happily pairing .. weight before : " << negEvents[nev]->GetWeight() << " and " << fEventSample[iMin]->GetWeight();
1019  Double_t newWeight = (negEvents[nev]->GetWeight() + fEventSample[iMin]->GetWeight());
1020  if (newWeight > 0){
1021  negEvents[nev]->SetBoostWeight( 0 );
1022  fEventSample[iMin]->SetBoostWeight( newWeight/fEventSample[iMin]->GetOriginalWeight() ); // note the weight*boostweight should be "newWeight"
1023  } else {
1024  negEvents[nev]->SetBoostWeight( newWeight/negEvents[nev]->GetOriginalWeight() ); // note the weight*boostweight should be "newWeight"
1025  fEventSample[iMin]->SetBoostWeight( 0 );
1026  }
1027  // std::cout << " and afterwards " << negEvents[nev]->GetWeight() << " and the paired " << fEventSample[iMin]->GetWeight() << " dist="<<minDist<< std::endl;
1028  } else Log() << kFATAL << "preprocessing didn't find event to pair with the negative weight ... probably a bug" << Endl;
1029  weight = negEvents[nev]->GetWeight();
1030  }
1031  }
1032  Log() << kINFO << "<Negative Event Pairing> took: " << timer.GetElapsedTime()
1033  << " " << Endl;
1034 
1035  // just check.. now there should be no negative event weight left anymore
1036  totalNegWeights = 0;
1037  totalPosWeights = 0;
1038  totalWeights = 0;
1039  Double_t sigWeight=0;
1040  Double_t bkgWeight=0;
1041  Int_t nSig=0;
1042  Int_t nBkg=0;
1043 
1044  std::vector<const Event*> newEventSample;
1045 
1046  for (UInt_t iev = 0; iev < fEventSample.size(); iev++){
1047  if (fEventSample[iev]->GetWeight() < 0) {
1048  totalNegWeights += fEventSample[iev]->GetWeight();
1049  totalWeights += fEventSample[iev]->GetWeight();
1050  } else {
1051  totalPosWeights += fEventSample[iev]->GetWeight();
1052  totalWeights += fEventSample[iev]->GetWeight();
1053  }
1054  if (fEventSample[iev]->GetWeight() > 0) {
1055  newEventSample.push_back(new Event(*fEventSample[iev]));
1056  if (fEventSample[iev]->GetClass() == fSignalClass){
1057  sigWeight += fEventSample[iev]->GetWeight();
1058  nSig+=1;
1059  }else{
1060  bkgWeight += fEventSample[iev]->GetWeight();
1061  nBkg+=1;
1062  }
1063  }
1064  }
1065  if (totalNegWeights < 0) Log() << kFATAL << " compensation of negative event weights with positive ones did not work " << totalNegWeights << Endl;
1066 
1067  for (UInt_t i=0; i<fEventSample.size(); i++) delete fEventSample[i];
1068  fEventSample = newEventSample;
1069 
1070  Log() << kINFO << " after PreProcessing, the Event sample is left with " << fEventSample.size() << " events (unweighted), all with positive weights, adding up to " << totalWeights << Endl;
1071  Log() << kINFO << " nSig="<<nSig << " sigWeight="<<sigWeight << " nBkg="<<nBkg << " bkgWeight="<<bkgWeight << Endl;
1072 
1073 
1074 }
1075 
1076 ////////////////////////////////////////////////////////////////////////////////
1077 /// Call the Optimizer with the set of parameters and ranges that
1078 /// are meant to be tuned.
1079 
1080 std::map<TString,Double_t> TMVA::MethodBDT::OptimizeTuningParameters(TString fomType, TString fitType)
1081 {
1082  // fill all the tuning parameters that should be optimized into a map:
1083  std::map<TString,TMVA::Interval*> tuneParameters;
1084  std::map<TString,Double_t> tunedParameters;
1085 
1086  // note: the 3rd parameter in the interval is the "number of bins", NOT the stepsize !!
1087  // the actual VALUES at (at least for the scan, guess also in GA) are always
1088  // read from the middle of the bins. Hence.. the choice of Intervals e.g. for the
1089  // MaxDepth, in order to make nice integer values!!!
1090 
1091  // find some reasonable ranges for the optimisation of MinNodeEvents:
1092 
1093  tuneParameters.insert(std::pair<TString,Interval*>("NTrees", new Interval(10,1000,5))); // stepsize 50
1094  tuneParameters.insert(std::pair<TString,Interval*>("MaxDepth", new Interval(2,4,3))); // stepsize 1
1095  tuneParameters.insert(std::pair<TString,Interval*>("MinNodeSize", new LogInterval(1,30,30))); //
1096  //tuneParameters.insert(std::pair<TString,Interval*>("NodePurityLimit",new Interval(.4,.6,3))); // stepsize .1
1097  //tuneParameters.insert(std::pair<TString,Interval*>("BaggedSampleFraction",new Interval(.4,.9,6))); // stepsize .1
1098 
1099  // method-specific parameters
1100  if (fBoostType=="AdaBoost"){
1101  tuneParameters.insert(std::pair<TString,Interval*>("AdaBoostBeta", new Interval(.2,1.,5)));
1102 
1103  }else if (fBoostType=="Grad"){
1104  tuneParameters.insert(std::pair<TString,Interval*>("Shrinkage", new Interval(0.05,0.50,5)));
1105 
1106  }else if (fBoostType=="Bagging" && fRandomisedTrees){
1107  Int_t min_var = TMath::FloorNint( GetNvar() * .25 );
1108  Int_t max_var = TMath::CeilNint( GetNvar() * .75 );
1109  tuneParameters.insert(std::pair<TString,Interval*>("UseNvars", new Interval(min_var,max_var,4)));
1110 
1111  }
1112 
1113  Log()<<kINFO << " the following BDT parameters will be tuned on the respective *grid*\n"<<Endl;
1114  std::map<TString,TMVA::Interval*>::iterator it;
1115  for(it=tuneParameters.begin(); it!= tuneParameters.end(); ++it){
1116  Log() << kWARNING << it->first << Endl;
1117  std::ostringstream oss;
1118  (it->second)->Print(oss);
1119  Log()<<oss.str();
1120  Log()<<Endl;
1121  }
1122 
1123  OptimizeConfigParameters optimize(this, tuneParameters, fomType, fitType);
1124  tunedParameters=optimize.optimize();
1125 
1126  return tunedParameters;
1127 
1128 }
1129 
1130 ////////////////////////////////////////////////////////////////////////////////
1131 /// Set the tuning parameters according to the argument.
1132 
1133 void TMVA::MethodBDT::SetTuneParameters(std::map<TString,Double_t> tuneParameters)
1134 {
1135  std::map<TString,Double_t>::iterator it;
1136  for(it=tuneParameters.begin(); it!= tuneParameters.end(); ++it){
1137  Log() << kWARNING << it->first << " = " << it->second << Endl;
1138  if (it->first == "MaxDepth" ) SetMaxDepth ((Int_t)it->second);
1139  else if (it->first == "MinNodeSize" ) SetMinNodeSize (it->second);
1140  else if (it->first == "NTrees" ) SetNTrees ((Int_t)it->second);
1141  else if (it->first == "NodePurityLimit") SetNodePurityLimit (it->second);
1142  else if (it->first == "AdaBoostBeta" ) SetAdaBoostBeta (it->second);
1143  else if (it->first == "Shrinkage" ) SetShrinkage (it->second);
1144  else if (it->first == "UseNvars" ) SetUseNvars ((Int_t)it->second);
1145  else if (it->first == "BaggedSampleFraction" ) SetBaggedSampleFraction (it->second);
1146  else Log() << kFATAL << " SetParameter for " << it->first << " not yet implemented " <<Endl;
1147  }
1148 }
1149 
1150 ////////////////////////////////////////////////////////////////////////////////
1151 /// BDT training.
1152 
1153 
1155 {
1157 
1158  // fill the STL Vector with the event sample
1159  // (needs to be done here and cannot be done in "init" as the options need to be
1160  // known).
1161  InitEventSample();
1162 
1163  if (fNTrees==0){
1164  Log() << kERROR << " Zero Decision Trees demanded... that does not work !! "
1165  << " I set it to 1 .. just so that the program does not crash"
1166  << Endl;
1167  fNTrees = 1;
1168  }
1169 
1171  std::vector<TString> titles = {"Boost weight", "Error Fraction"};
1172  fInteractive->Init(titles);
1173  }
1174  fIPyMaxIter = fNTrees;
1175  fExitFromTraining = false;
1176 
1177  // HHV (it's been here since looong but I really don't know why we cannot handle
1178  // normalized variables in BDTs... todo
1179  if (IsNormalised()) Log() << kFATAL << "\"Normalise\" option cannot be used with BDT; "
1180  << "please remove the option from the configuration string, or "
1181  << "use \"!Normalise\""
1182  << Endl;
1183 
1184  if(DoRegression())
1185  Log() << kINFO << "Regression Loss Function: "<< fRegressionLossFunctionBDTG->Name() << Endl;
1186 
1187  Log() << kINFO << "Training "<< fNTrees << " Decision Trees ... patience please" << Endl;
1188 
1189  Log() << kDEBUG << "Training with maximal depth = " <<fMaxDepth
1190  << ", MinNodeEvents=" << fMinNodeEvents
1191  << ", NTrees="<<fNTrees
1192  << ", NodePurityLimit="<<fNodePurityLimit
1193  << ", AdaBoostBeta="<<fAdaBoostBeta
1194  << Endl;
1195 
1196  // weights applied in boosting
1197  Int_t nBins;
1198  Double_t xMin,xMax;
1199  TString hname = "AdaBooost weight distribution";
1200 
1201  nBins= 100;
1202  xMin = 0;
1203  xMax = 30;
1204 
1205  if (DoRegression()) {
1206  nBins= 100;
1207  xMin = 0;
1208  xMax = 1;
1209  hname="Boost event weights distribution";
1210  }
1211 
1212  // book monitoring histograms (for AdaBost only)
1213 
1214  TH1* h = new TH1F(Form("%s_BoostWeight",DataInfo().GetName()),hname,nBins,xMin,xMax);
1215  TH1* nodesBeforePruningVsTree = new TH1I(Form("%s_NodesBeforePruning",DataInfo().GetName()),"nodes before pruning",fNTrees,0,fNTrees);
1216  TH1* nodesAfterPruningVsTree = new TH1I(Form("%s_NodesAfterPruning",DataInfo().GetName()),"nodes after pruning",fNTrees,0,fNTrees);
1217 
1218 
1219 
1220  if(!DoMulticlass()){
1222 
1223  h->SetXTitle("boost weight");
1224  results->Store(h, "BoostWeights");
1225 
1226 
1227  // Monitor the performance (on TEST sample) versus number of trees
1228  if (fDoBoostMonitor){
1229  TH2* boostMonitor = new TH2F("BoostMonitor","ROC Integral Vs iTree",2,0,fNTrees,2,0,1.05);
1230  boostMonitor->SetXTitle("#tree");
1231  boostMonitor->SetYTitle("ROC Integral");
1232  results->Store(boostMonitor, "BoostMonitor");
1233  TGraph *boostMonitorGraph = new TGraph();
1234  boostMonitorGraph->SetName("BoostMonitorGraph");
1235  boostMonitorGraph->SetTitle("ROCIntegralVsNTrees");
1236  results->Store(boostMonitorGraph, "BoostMonitorGraph");
1237  }
1238 
1239  // weights applied in boosting vs tree number
1240  h = new TH1F("BoostWeightVsTree","Boost weights vs tree",fNTrees,0,fNTrees);
1241  h->SetXTitle("#tree");
1242  h->SetYTitle("boost weight");
1243  results->Store(h, "BoostWeightsVsTree");
1244 
1245  // error fraction vs tree number
1246  h = new TH1F("ErrFractHist","error fraction vs tree number",fNTrees,0,fNTrees);
1247  h->SetXTitle("#tree");
1248  h->SetYTitle("error fraction");
1249  results->Store(h, "ErrorFrac");
1250 
1251  // nNodesBeforePruning vs tree number
1252  nodesBeforePruningVsTree->SetXTitle("#tree");
1253  nodesBeforePruningVsTree->SetYTitle("#tree nodes");
1254  results->Store(nodesBeforePruningVsTree);
1255 
1256  // nNodesAfterPruning vs tree number
1257  nodesAfterPruningVsTree->SetXTitle("#tree");
1258  nodesAfterPruningVsTree->SetYTitle("#tree nodes");
1259  results->Store(nodesAfterPruningVsTree);
1260 
1261  }
1262 
1263  fMonitorNtuple= new TTree("MonitorNtuple","BDT variables");
1264  fMonitorNtuple->Branch("iTree",&fITree,"iTree/I");
1265  fMonitorNtuple->Branch("boostWeight",&fBoostWeight,"boostWeight/D");
1266  fMonitorNtuple->Branch("errorFraction",&fErrorFraction,"errorFraction/D");
1267 
1268  Timer timer( fNTrees, GetName() );
1269  Int_t nNodesBeforePruningCount = 0;
1270  Int_t nNodesAfterPruningCount = 0;
1271 
1272  Int_t nNodesBeforePruning = 0;
1273  Int_t nNodesAfterPruning = 0;
1274 
1275  if(fBoostType=="Grad"){
1277  }
1278 
1279  Int_t itree=0;
1280  Bool_t continueBoost=kTRUE;
1281  //for (int itree=0; itree<fNTrees; itree++) {
1282 
1283  while (itree < fNTrees && continueBoost){
1284  if (fExitFromTraining) break;
1285  fIPyCurrentIter = itree;
1286  timer.DrawProgressBar( itree );
1287  // Results* results = Data()->GetResults(GetMethodName(), Types::kTraining, GetAnalysisType());
1288  // TH1 *hxx = new TH1F(Form("swdist%d",itree),Form("swdist%d",itree),10000,0,15);
1289  // results->Store(hxx,Form("swdist%d",itree));
1290  // TH1 *hxy = new TH1F(Form("bwdist%d",itree),Form("bwdist%d",itree),10000,0,15);
1291  // results->Store(hxy,Form("bwdist%d",itree));
1292  // for (Int_t iev=0; iev<fEventSample.size(); iev++) {
1293  // if (fEventSample[iev]->GetClass()!=0) hxy->Fill((fEventSample[iev])->GetWeight());
1294  // else hxx->Fill((fEventSample[iev])->GetWeight());
1295  // }
1296 
1297  if(DoMulticlass()){
1298  if (fBoostType!="Grad"){
1299  Log() << kFATAL << "Multiclass is currently only supported by gradient boost. "
1300  << "Please change boost option accordingly (GradBoost)."
1301  << Endl;
1302  }
1303 
1304  UInt_t nClasses = DataInfo().GetNClasses();
1305  for (UInt_t i=0;i<nClasses;i++){
1306  // Careful: If fSepType is nullptr, the tree will be considered a regression tree and
1307  // use the correct output for gradboost (response rather than yesnoleaf) in checkEvent.
1308  // See TMVA::MethodBDT::InitGradBoost.
1309  fForest.push_back( new DecisionTree( fSepType, fMinNodeSize, fNCuts, &(DataInfo()), i,
1311  itree*nClasses+i, fNodePurityLimit, itree*nClasses+1));
1312  fForest.back()->SetNVars(GetNvar());
1313  if (fUseFisherCuts) {
1314  fForest.back()->SetUseFisherCuts();
1315  fForest.back()->SetMinLinCorrForFisher(fMinLinCorrForFisher);
1316  fForest.back()->SetUseExclusiveVars(fUseExclusiveVars);
1317  }
1318  // the minimum linear correlation between two variables demanded for use in fisher criterion in node splitting
1319 
1320  nNodesBeforePruning = fForest.back()->BuildTree(*fTrainSample);
1321  Double_t bw = this->Boost(*fTrainSample, fForest.back(),i);
1322  if (bw > 0) {
1323  fBoostWeights.push_back(bw);
1324  }else{
1325  fBoostWeights.push_back(0);
1326  Log() << kWARNING << "stopped boosting at itree="<<itree << Endl;
1327  // fNTrees = itree+1; // that should stop the boosting
1328  continueBoost=kFALSE;
1329  }
1330  }
1331  }
1332  else{
1333 
1336  itree, fNodePurityLimit, itree);
1337 
1338  fForest.push_back(dt);
1339  fForest.back()->SetNVars(GetNvar());
1340  if (fUseFisherCuts) {
1341  fForest.back()->SetUseFisherCuts();
1342  fForest.back()->SetMinLinCorrForFisher(fMinLinCorrForFisher);
1343  fForest.back()->SetUseExclusiveVars(fUseExclusiveVars);
1344  }
1345 
1346  nNodesBeforePruning = fForest.back()->BuildTree(*fTrainSample);
1347 
1348  if (fUseYesNoLeaf && !DoRegression() && fBoostType!="Grad") { // remove leaf nodes where both daughter nodes are of same type
1349  nNodesBeforePruning = fForest.back()->CleanTree();
1350  }
1351 
1352  nNodesBeforePruningCount += nNodesBeforePruning;
1353  nodesBeforePruningVsTree->SetBinContent(itree+1,nNodesBeforePruning);
1354 
1355  fForest.back()->SetPruneMethod(fPruneMethod); // set the pruning method for the tree
1356  fForest.back()->SetPruneStrength(fPruneStrength); // set the strength parameter
1357 
1358  std::vector<const Event*> * validationSample = NULL;
1359  if(fAutomatic) validationSample = &fValidationSample;
1360  Double_t bw = this->Boost(*fTrainSample, fForest.back());
1361  if (bw > 0) {
1362  fBoostWeights.push_back(bw);
1363  }else{
1364  fBoostWeights.push_back(0);
1365  Log() << kWARNING << "stopped boosting at itree="<<itree << Endl;
1366  continueBoost=kFALSE;
1367  }
1368 
1369  // if fAutomatic == true, pruneStrength will be the optimal pruning strength
1370  // determined by the pruning algorithm; otherwise, it is simply the strength parameter
1371  // set by the user
1372  if (fPruneMethod != DecisionTree::kNoPruning) fForest.back()->PruneTree(validationSample);
1373 
1374  if (fUseYesNoLeaf && !DoRegression() && fBoostType!="Grad"){ // remove leaf nodes where both daughter nodes are of same type
1375  fForest.back()->CleanTree();
1376  }
1377  nNodesAfterPruning = fForest.back()->GetNNodes();
1378  nNodesAfterPruningCount += nNodesAfterPruning;
1379  nodesAfterPruningVsTree->SetBinContent(itree+1,nNodesAfterPruning);
1380 
1381  if (fInteractive){
1383  }
1384  fITree = itree;
1385  fMonitorNtuple->Fill();
1386  if (fDoBoostMonitor){
1387  if (! DoRegression() ){
1388  if ( itree==fNTrees-1 || (!(itree%500)) ||
1389  (!(itree%250) && itree <1000)||
1390  (!(itree%100) && itree < 500)||
1391  (!(itree%50) && itree < 250)||
1392  (!(itree%25) && itree < 150)||
1393  (!(itree%10) && itree < 50)||
1394  (!(itree%5) && itree < 20)
1395  ) BoostMonitor(itree);
1396  }
1397  }
1398  }
1399  itree++;
1400  }
1401 
1402  // get elapsed time
1403  Log() << kDEBUG << "\t<Train> elapsed time: " << timer.GetElapsedTime()
1404  << " " << Endl;
1406  Log() << kDEBUG << "\t<Train> average number of nodes (w/o pruning) : "
1407  << nNodesBeforePruningCount/GetNTrees() << Endl;
1408  }
1409  else {
1410  Log() << kDEBUG << "\t<Train> average number of nodes before/after pruning : "
1411  << nNodesBeforePruningCount/GetNTrees() << " / "
1412  << nNodesAfterPruningCount/GetNTrees()
1413  << Endl;
1414  }
1416 
1417 
1418  // reset all previously stored/accumulated BOOST weights in the event sample
1419  // for (UInt_t iev=0; iev<fEventSample.size(); iev++) fEventSample[iev]->SetBoostWeight(1.);
1420  Log() << kDEBUG << "Now I delete the privat data sample"<< Endl;
1421  for (UInt_t i=0; i<fEventSample.size(); i++) delete fEventSample[i];
1422  for (UInt_t i=0; i<fValidationSample.size(); i++) delete fValidationSample[i];
1423  fEventSample.clear();
1424  fValidationSample.clear();
1425 
1427  ExitFromTraining();
1428 }
1429 
1430 
1431 ////////////////////////////////////////////////////////////////////////////////
1432 /// Returns MVA value: -1 for background, 1 for signal.
1433 
1435 {
1436  Double_t sum=0;
1437  for (UInt_t itree=0; itree<nTrees; itree++) {
1438  //loop over all trees in forest
1439  sum += fForest[itree]->CheckEvent(e,kFALSE);
1440 
1441  }
1442  return 2.0/(1.0+exp(-2.0*sum))-1; //MVA output between -1 and 1
1443 }
1444 
1445 ////////////////////////////////////////////////////////////////////////////////
1446 /// Calculate residual for all events.
1447 
1448 void TMVA::MethodBDT::UpdateTargets(std::vector<const TMVA::Event*>& eventSample, UInt_t cls)
1449 {
1450  if (DoMulticlass()) {
1451  UInt_t nClasses = DataInfo().GetNClasses();
1452  std::vector<Double_t> expCache;
1453  if (cls == nClasses - 1) {
1454  expCache.resize(nClasses);
1455  }
1456  for (auto e : eventSample) {
1457  fResiduals[e].at(cls) += fForest.back()->CheckEvent(e, kFALSE);
1458  if (cls == nClasses - 1) {
1459  auto &residualsThisEvent = fResiduals[e];
1460  std::transform(residualsThisEvent.begin(),
1461  residualsThisEvent.begin() + nClasses,
1462  expCache.begin(), [](Double_t d) { return exp(d); });
1463  for (UInt_t i = 0; i < nClasses; i++) {
1464  Double_t norm = 0.0;
1465  for (UInt_t j = 0; j < nClasses; j++) {
1466  if (i != j) {
1467  norm += expCache[j] / expCache[i];
1468  }
1469  }
1470  Double_t p_cls = 1.0 / (1.0 + norm);
1471  Double_t res = (e->GetClass() == i) ? (1.0 - p_cls) : (-p_cls);
1472  const_cast<TMVA::Event *>(e)->SetTarget(i, res);
1473  }
1474  }
1475  }
1476  } else {
1477  for (auto e : eventSample) {
1478  auto &residualAt0 = fResiduals[e].at(0);
1479  residualAt0 += fForest.back()->CheckEvent(e, kFALSE);
1480  Double_t p_sig = 1.0 / (1.0 + exp(-2.0 * residualAt0));
1481  Double_t res = (DataInfo().IsSignal(e) ? 1 : 0) - p_sig;
1482  const_cast<TMVA::Event *>(e)->SetTarget(0, res);
1483  }
1484  }
1485 }
1486 
1487 ////////////////////////////////////////////////////////////////////////////////
1488 /// Calculate current residuals for all events and update targets for next iteration.
1489 
1490 void TMVA::MethodBDT::UpdateTargetsRegression(std::vector<const TMVA::Event*>& eventSample, Bool_t first)
1491 {
1492  // Need to update the predictions for the next tree
1493  // #### Do this in parallel by partitioning the data into nPartitions
1494  #ifdef R__USE_IMT // multithreaded version if ROOT was compiled with multithreading
1495  if(!first){
1496 
1497  UInt_t nPartitions = fNumPoolThreads;
1498  auto seeds = ROOT::TSeqU(nPartitions);
1499 
1500  // need a lambda function to pass to TThreadExecutor::MapReduce
1501  auto f = [this, &eventSample, &nPartitions](UInt_t partition = 0) -> Int_t{
1502 
1503  Int_t start = 1.0*partition/nPartitions*eventSample.size();
1504  Int_t end = (partition+1.0)/nPartitions*eventSample.size();
1505 
1506  for(Int_t i=start; i<end; ++i)
1507  fLossFunctionEventInfo[eventSample[i]].predictedValue += fForest.back()->CheckEvent(eventSample[i],kFALSE);
1508 
1509  return 0;
1510  };
1511 
1513  }
1514  #else // ROOT was not compiled with multithreading, use standard version
1515  if(!first){
1516  for (std::vector<const TMVA::Event*>::const_iterator e=fEventSample.begin(); e!=fEventSample.end();e++) {
1517  fLossFunctionEventInfo[*e].predictedValue += fForest.back()->CheckEvent(*e,kFALSE);
1518  }
1519  }
1520  #endif
1521 
1522  // #### Parallelized at the loss function level
1524 
1525 }
1526 
1527 ////////////////////////////////////////////////////////////////////////////////
1528 /// Calculate the desired response value for each region.
1529 
1530 Double_t TMVA::MethodBDT::GradBoost(std::vector<const TMVA::Event*>& eventSample, DecisionTree *dt, UInt_t cls)
1531 {
1532  struct LeafInfo {
1533  Double_t sumWeightTarget = 0;
1534  Double_t sum2 = 0;
1535  };
1536 
1537  std::unordered_map<TMVA::DecisionTreeNode*, LeafInfo> leaves;
1538  for (auto e : eventSample) {
1539  Double_t weight = e->GetWeight();
1540  TMVA::DecisionTreeNode* node = dt->GetEventNode(*e);
1541  auto &v = leaves[node];
1542  auto target = e->GetTarget(cls);
1543  v.sumWeightTarget += target * weight;
1544  v.sum2 += fabs(target) * (1.0 - fabs(target)) * weight;
1545  }
1546  for (auto &iLeave : leaves) {
1547  constexpr auto minValue = 1e-30;
1548  if (iLeave.second.sum2 < minValue) {
1549  iLeave.second.sum2 = minValue;
1550  }
1551  const Double_t K = DataInfo().GetNClasses();
1552  iLeave.first->SetResponse(fShrinkage * (K - 1) / K * iLeave.second.sumWeightTarget / iLeave.second.sum2);
1553  }
1554 
1555  //call UpdateTargets before next tree is grown
1556 
1558  return 1; //trees all have the same weight
1559 }
1560 
1561 ////////////////////////////////////////////////////////////////////////////////
1562 /// Implementation of M_TreeBoost using any loss function as described by Friedman 1999.
1563 
1564 Double_t TMVA::MethodBDT::GradBoostRegression(std::vector<const TMVA::Event*>& eventSample, DecisionTree *dt )
1565 {
1566  // get the vector of events for each terminal so that we can calculate the constant fit value in each
1567  // terminal node
1568  // #### Not sure how many events are in each node in advance, so I can't parallelize this easily
1569  std::map<TMVA::DecisionTreeNode*,vector< TMVA::LossFunctionEventInfo > > leaves;
1570  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1571  TMVA::DecisionTreeNode* node = dt->GetEventNode(*(*e));
1572  (leaves[node]).push_back(fLossFunctionEventInfo[*e]);
1573  }
1574 
1575  // calculate the constant fit for each terminal node based upon the events in the node
1576  // node (iLeave->first), vector of event information (iLeave->second)
1577  // #### could parallelize this and do the leaves at the same time, but this doesn't take very long compared
1578  // #### to the other processes
1579  for (std::map<TMVA::DecisionTreeNode*,vector< TMVA::LossFunctionEventInfo > >::iterator iLeave=leaves.begin();
1580  iLeave!=leaves.end();++iLeave){
1581  Double_t fit = fRegressionLossFunctionBDTG->Fit(iLeave->second);
1582  (iLeave->first)->SetResponse(fShrinkage*fit);
1583  }
1584 
1586 
1587  return 1;
1588 }
1589 
1590 ////////////////////////////////////////////////////////////////////////////////
1591 /// Initialize targets for first tree.
1592 
1593 void TMVA::MethodBDT::InitGradBoost( std::vector<const TMVA::Event*>& eventSample)
1594 {
1595  // Should get rid of this line. It's just for debugging.
1596  //std::sort(eventSample.begin(), eventSample.end(), [](const TMVA::Event* a, const TMVA::Event* b){
1597  // return (a->GetTarget(0) < b->GetTarget(0)); });
1598  fSepType=NULL; //set fSepType to NULL (regression trees are used for both classification an regression)
1599  if(DoRegression()){
1600  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1601  fLossFunctionEventInfo[*e]= TMVA::LossFunctionEventInfo((*e)->GetTarget(0), 0, (*e)->GetWeight());
1602  }
1603 
1606 
1607  return;
1608  }
1609  else if(DoMulticlass()){
1610  UInt_t nClasses = DataInfo().GetNClasses();
1611  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1612  for (UInt_t i=0;i<nClasses;i++){
1613  //Calculate initial residua, assuming equal probability for all classes
1614  Double_t r = (*e)->GetClass()==i?(1-1.0/nClasses):(-1.0/nClasses);
1615  const_cast<TMVA::Event*>(*e)->SetTarget(i,r);
1616  fResiduals[*e].push_back(0);
1617  }
1618  }
1619  }
1620  else{
1621  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1622  Double_t r = (DataInfo().IsSignal(*e)?1:0)-0.5; //Calculate initial residua
1623  const_cast<TMVA::Event*>(*e)->SetTarget(0,r);
1624  fResiduals[*e].push_back(0);
1625  }
1626  }
1627 
1628 }
1629 ////////////////////////////////////////////////////////////////////////////////
1630 /// Test the tree quality.. in terms of Misclassification.
1631 
1633 {
1634  Double_t ncorrect=0, nfalse=0;
1635  for (UInt_t ievt=0; ievt<fValidationSample.size(); ievt++) {
1636  Bool_t isSignalType= (dt->CheckEvent(fValidationSample[ievt]) > fNodePurityLimit ) ? 1 : 0;
1637 
1638  if (isSignalType == (DataInfo().IsSignal(fValidationSample[ievt])) ) {
1639  ncorrect += fValidationSample[ievt]->GetWeight();
1640  }
1641  else{
1642  nfalse += fValidationSample[ievt]->GetWeight();
1643  }
1644  }
1645 
1646  return ncorrect / (ncorrect + nfalse);
1647 }
1648 
1649 ////////////////////////////////////////////////////////////////////////////////
1650 /// Apply the boosting algorithm (the algorithm is selecte via the the "option" given
1651 /// in the constructor. The return value is the boosting weight.
1652 
1653 Double_t TMVA::MethodBDT::Boost( std::vector<const TMVA::Event*>& eventSample, DecisionTree *dt, UInt_t cls )
1654 {
1655  Double_t returnVal=-1;
1656 
1657  if (fBoostType=="AdaBoost") returnVal = this->AdaBoost (eventSample, dt);
1658  else if (fBoostType=="AdaCost") returnVal = this->AdaCost (eventSample, dt);
1659  else if (fBoostType=="Bagging") returnVal = this->Bagging ( );
1660  else if (fBoostType=="RegBoost") returnVal = this->RegBoost (eventSample, dt);
1661  else if (fBoostType=="AdaBoostR2") returnVal = this->AdaBoostR2(eventSample, dt);
1662  else if (fBoostType=="Grad"){
1663  if(DoRegression())
1664  returnVal = this->GradBoostRegression(eventSample, dt);
1665  else if(DoMulticlass())
1666  returnVal = this->GradBoost (eventSample, dt, cls);
1667  else
1668  returnVal = this->GradBoost (eventSample, dt);
1669  }
1670  else {
1671  Log() << kINFO << GetOptions() << Endl;
1672  Log() << kFATAL << "<Boost> unknown boost option " << fBoostType<< " called" << Endl;
1673  }
1674 
1675  if (fBaggedBoost){
1677  }
1678 
1679 
1680  return returnVal;
1681 }
1682 
1683 ////////////////////////////////////////////////////////////////////////////////
1684 /// Fills the ROCIntegral vs Itree from the testSample for the monitoring plots
1685 /// during the training .. but using the testing events
1686 
1688 {
1690 
1691  TH1F *tmpS = new TH1F( "tmpS", "", 100 , -1., 1.00001 );
1692  TH1F *tmpB = new TH1F( "tmpB", "", 100 , -1., 1.00001 );
1693  TH1F *tmp;
1694 
1695 
1696  UInt_t signalClassNr = DataInfo().GetClassInfo("Signal")->GetNumber();
1697 
1698  // const std::vector<Event*> events=Data()->GetEventCollection(Types::kTesting);
1699  // // fMethod->GetTransformationHandler().CalcTransformations(fMethod->Data()->GetEventCollection(Types::kTesting));
1700  // for (UInt_t iev=0; iev < events.size() ; iev++){
1701  // if (events[iev]->GetClass() == signalClassNr) tmp=tmpS;
1702  // else tmp=tmpB;
1703  // tmp->Fill(PrivateGetMvaValue(*(events[iev])),events[iev]->GetWeight());
1704  // }
1705 
1706  UInt_t nevents = Data()->GetNTestEvents();
1707  for (UInt_t iev=0; iev < nevents; iev++){
1708  const Event* event = GetTestingEvent(iev);
1709 
1710  if (event->GetClass() == signalClassNr) {tmp=tmpS;}
1711  else {tmp=tmpB;}
1712  tmp->Fill(PrivateGetMvaValue(event),event->GetWeight());
1713  }
1714  Double_t max=1;
1715 
1716  std::vector<TH1F*> hS;
1717  std::vector<TH1F*> hB;
1718  for (UInt_t ivar=0; ivar<GetNvar(); ivar++){
1719  hS.push_back(new TH1F(Form("SigVar%dAtTree%d",ivar,iTree),Form("SigVar%dAtTree%d",ivar,iTree),100,DataInfo().GetVariableInfo(ivar).GetMin(),DataInfo().GetVariableInfo(ivar).GetMax()));
1720  hB.push_back(new TH1F(Form("BkgVar%dAtTree%d",ivar,iTree),Form("BkgVar%dAtTree%d",ivar,iTree),100,DataInfo().GetVariableInfo(ivar).GetMin(),DataInfo().GetVariableInfo(ivar).GetMax()));
1721  results->Store(hS.back(),hS.back()->GetTitle());
1722  results->Store(hB.back(),hB.back()->GetTitle());
1723  }
1724 
1725 
1726  for (UInt_t iev=0; iev < fEventSample.size(); iev++){
1727  if (fEventSample[iev]->GetBoostWeight() > max) max = 1.01*fEventSample[iev]->GetBoostWeight();
1728  }
1729  TH1F *tmpBoostWeightsS = new TH1F(Form("BoostWeightsInTreeS%d",iTree),Form("BoostWeightsInTreeS%d",iTree),100,0.,max);
1730  TH1F *tmpBoostWeightsB = new TH1F(Form("BoostWeightsInTreeB%d",iTree),Form("BoostWeightsInTreeB%d",iTree),100,0.,max);
1731  results->Store(tmpBoostWeightsS,tmpBoostWeightsS->GetTitle());
1732  results->Store(tmpBoostWeightsB,tmpBoostWeightsB->GetTitle());
1733 
1734  TH1F *tmpBoostWeights;
1735  std::vector<TH1F*> *h;
1736 
1737  for (UInt_t iev=0; iev < fEventSample.size(); iev++){
1738  if (fEventSample[iev]->GetClass() == signalClassNr) {
1739  tmpBoostWeights=tmpBoostWeightsS;
1740  h=&hS;
1741  }else{
1742  tmpBoostWeights=tmpBoostWeightsB;
1743  h=&hB;
1744  }
1745  tmpBoostWeights->Fill(fEventSample[iev]->GetBoostWeight());
1746  for (UInt_t ivar=0; ivar<GetNvar(); ivar++){
1747  (*h)[ivar]->Fill(fEventSample[iev]->GetValue(ivar),fEventSample[iev]->GetWeight());
1748  }
1749  }
1750 
1751 
1752  TMVA::PDF *sig = new TMVA::PDF( " PDF Sig", tmpS, TMVA::PDF::kSpline3 );
1753  TMVA::PDF *bkg = new TMVA::PDF( " PDF Bkg", tmpB, TMVA::PDF::kSpline3 );
1754 
1755 
1756  TGraph* gr=results->GetGraph("BoostMonitorGraph");
1757  Int_t nPoints = gr->GetN();
1758  gr->Set(nPoints+1);
1759  gr->SetPoint(nPoints,(Double_t)iTree+1,GetROCIntegral(sig,bkg));
1760 
1761  tmpS->Delete();
1762  tmpB->Delete();
1763 
1764  delete sig;
1765  delete bkg;
1766 
1767  return;
1768 }
1769 
1770 ////////////////////////////////////////////////////////////////////////////////
1771 /// The AdaBoost implementation.
1772 /// a new training sample is generated by weighting
1773 /// events that are misclassified by the decision tree. The weight
1774 /// applied is \f$ w = \frac{(1-err)}{err} \f$ or more general:
1775 /// \f$ w = (\frac{(1-err)}{err})^\beta \f$
1776 /// where \f$err\f$ is the fraction of misclassified events in the tree ( <0.5 assuming
1777 /// demanding the that previous selection was better than random guessing)
1778 /// and "beta" being a free parameter (standard: beta = 1) that modifies the
1779 /// boosting.
1780 
1781 Double_t TMVA::MethodBDT::AdaBoost( std::vector<const TMVA::Event*>& eventSample, DecisionTree *dt )
1782 {
1783  Double_t err=0, sumGlobalw=0, sumGlobalwfalse=0, sumGlobalwfalse2=0;
1784 
1785  std::vector<Double_t> sumw(DataInfo().GetNClasses(),0); //for individually re-scaling each class
1786 
1787  Double_t maxDev=0;
1788  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1789  Double_t w = (*e)->GetWeight();
1790  sumGlobalw += w;
1791  UInt_t iclass=(*e)->GetClass();
1792  sumw[iclass] += w;
1793 
1794  if ( DoRegression() ) {
1795  Double_t tmpDev = TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) );
1796  sumGlobalwfalse += w * tmpDev;
1797  sumGlobalwfalse2 += w * tmpDev*tmpDev;
1798  if (tmpDev > maxDev) maxDev = tmpDev;
1799  }else{
1800 
1801  if (fUseYesNoLeaf){
1802  Bool_t isSignalType = (dt->CheckEvent(*e,fUseYesNoLeaf) > fNodePurityLimit );
1803  if (!(isSignalType == DataInfo().IsSignal(*e))) {
1804  sumGlobalwfalse+= w;
1805  }
1806  }else{
1807  Double_t dtoutput = (dt->CheckEvent(*e,fUseYesNoLeaf) - 0.5)*2.;
1808  Int_t trueType;
1809  if (DataInfo().IsSignal(*e)) trueType = 1;
1810  else trueType = -1;
1811  sumGlobalwfalse+= w*trueType*dtoutput;
1812  }
1813  }
1814  }
1815 
1816  err = sumGlobalwfalse/sumGlobalw ;
1817  if ( DoRegression() ) {
1818  //if quadratic loss:
1819  if (fAdaBoostR2Loss=="linear"){
1820  err = sumGlobalwfalse/maxDev/sumGlobalw ;
1821  }
1822  else if (fAdaBoostR2Loss=="quadratic"){
1823  err = sumGlobalwfalse2/maxDev/maxDev/sumGlobalw ;
1824  }
1825  else if (fAdaBoostR2Loss=="exponential"){
1826  err = 0;
1827  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1828  Double_t w = (*e)->GetWeight();
1829  Double_t tmpDev = TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) );
1830  err += w * (1 - exp (-tmpDev/maxDev)) / sumGlobalw;
1831  }
1832 
1833  }
1834  else {
1835  Log() << kFATAL << " you've chosen a Loss type for Adaboost other than linear, quadratic or exponential "
1836  << " namely " << fAdaBoostR2Loss << "\n"
1837  << "and this is not implemented... a typo in the options ??" <<Endl;
1838  }
1839  }
1840 
1841  Log() << kDEBUG << "BDT AdaBoos wrong/all: " << sumGlobalwfalse << "/" << sumGlobalw << Endl;
1842 
1843 
1844  Double_t newSumGlobalw=0;
1845  std::vector<Double_t> newSumw(sumw.size(),0);
1846 
1847  Double_t boostWeight=1.;
1848  if (err >= 0.5 && fUseYesNoLeaf) { // sanity check ... should never happen as otherwise there is apparently
1849  // something odd with the assignment of the leaf nodes (rem: you use the training
1850  // events for this determination of the error rate)
1851  if (dt->GetNNodes() == 1){
1852  Log() << kERROR << " YOUR tree has only 1 Node... kind of a funny *tree*. I cannot "
1853  << "boost such a thing... if after 1 step the error rate is == 0.5"
1854  << Endl
1855  << "please check why this happens, maybe too many events per node requested ?"
1856  << Endl;
1857 
1858  }else{
1859  Log() << kERROR << " The error rate in the BDT boosting is > 0.5. ("<< err
1860  << ") That should not happen, please check your code (i.e... the BDT code), I "
1861  << " stop boosting here" << Endl;
1862  return -1;
1863  }
1864  err = 0.5;
1865  } else if (err < 0) {
1866  Log() << kERROR << " The error rate in the BDT boosting is < 0. That can happen"
1867  << " due to improper treatment of negative weights in a Monte Carlo.. (if you have"
1868  << " an idea on how to do it in a better way, please let me know (Helge.Voss@cern.ch)"
1869  << " for the time being I set it to its absolute value.. just to continue.." << Endl;
1870  err = TMath::Abs(err);
1871  }
1872  if (fUseYesNoLeaf)
1873  boostWeight = TMath::Log((1.-err)/err)*fAdaBoostBeta;
1874  else
1875  boostWeight = TMath::Log((1.+err)/(1-err))*fAdaBoostBeta;
1876 
1877 
1878  Log() << kDEBUG << "BDT AdaBoos wrong/all: " << sumGlobalwfalse << "/" << sumGlobalw << " 1-err/err="<<boostWeight<< " log.."<<TMath::Log(boostWeight)<<Endl;
1879 
1881 
1882 
1883  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1884 
1885  if (fUseYesNoLeaf||DoRegression()){
1886  if ((!( (dt->CheckEvent(*e,fUseYesNoLeaf) > fNodePurityLimit ) == DataInfo().IsSignal(*e))) || DoRegression()) {
1887  Double_t boostfactor = TMath::Exp(boostWeight);
1888 
1889  if (DoRegression()) boostfactor = TMath::Power(1/boostWeight,(1.-TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) )/maxDev ) );
1890  if ( (*e)->GetWeight() > 0 ){
1891  (*e)->SetBoostWeight( (*e)->GetBoostWeight() * boostfactor);
1892  // Helge change back (*e)->ScaleBoostWeight(boostfactor);
1893  if (DoRegression()) results->GetHist("BoostWeights")->Fill(boostfactor);
1894  } else {
1895  if ( fInverseBoostNegWeights )(*e)->ScaleBoostWeight( 1. / boostfactor); // if the original event weight is negative, and you want to "increase" the events "positive" influence, you'd rather make the event weight "smaller" in terms of it's absolute value while still keeping it something "negative"
1896  else (*e)->SetBoostWeight( (*e)->GetBoostWeight() * boostfactor);
1897 
1898  }
1899  }
1900 
1901  }else{
1902  Double_t dtoutput = (dt->CheckEvent(*e,fUseYesNoLeaf) - 0.5)*2.;
1903  Int_t trueType;
1904  if (DataInfo().IsSignal(*e)) trueType = 1;
1905  else trueType = -1;
1906  Double_t boostfactor = TMath::Exp(-1*boostWeight*trueType*dtoutput);
1907 
1908  if ( (*e)->GetWeight() > 0 ){
1909  (*e)->SetBoostWeight( (*e)->GetBoostWeight() * boostfactor);
1910  // Helge change back (*e)->ScaleBoostWeight(boostfactor);
1911  if (DoRegression()) results->GetHist("BoostWeights")->Fill(boostfactor);
1912  } else {
1913  if ( fInverseBoostNegWeights )(*e)->ScaleBoostWeight( 1. / boostfactor); // if the original event weight is negative, and you want to "increase" the events "positive" influence, you'd rather make the event weight "smaller" in terms of it's absolute value while still keeping it something "negative"
1914  else (*e)->SetBoostWeight( (*e)->GetBoostWeight() * boostfactor);
1915  }
1916  }
1917  newSumGlobalw+=(*e)->GetWeight();
1918  newSumw[(*e)->GetClass()] += (*e)->GetWeight();
1919  }
1920 
1921 
1922  // Double_t globalNormWeight=sumGlobalw/newSumGlobalw;
1923  Double_t globalNormWeight=( (Double_t) eventSample.size())/newSumGlobalw;
1924  Log() << kDEBUG << "new Nsig="<<newSumw[0]*globalNormWeight << " new Nbkg="<<newSumw[1]*globalNormWeight << Endl;
1925 
1926 
1927  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1928  // if (fRenormByClass) (*e)->ScaleBoostWeight( normWeightByClass[(*e)->GetClass()] );
1929  // else (*e)->ScaleBoostWeight( globalNormWeight );
1930  // else (*e)->ScaleBoostWeight( globalNormWeight );
1931  if (DataInfo().IsSignal(*e))(*e)->ScaleBoostWeight( globalNormWeight * fSigToBkgFraction );
1932  else (*e)->ScaleBoostWeight( globalNormWeight );
1933  }
1934 
1935  if (!(DoRegression()))results->GetHist("BoostWeights")->Fill(boostWeight);
1936  results->GetHist("BoostWeightsVsTree")->SetBinContent(fForest.size(),boostWeight);
1937  results->GetHist("ErrorFrac")->SetBinContent(fForest.size(),err);
1938 
1939  fBoostWeight = boostWeight;
1940  fErrorFraction = err;
1941 
1942  return boostWeight;
1943 }
1944 
1945 ////////////////////////////////////////////////////////////////////////////////
1946 /// The AdaCost boosting algorithm takes a simple cost Matrix (currently fixed for
1947 /// all events... later could be modified to use individual cost matrices for each
1948 /// events as in the original paper...
1949 ///
1950 /// true_signal true_bkg
1951 /// ----------------------------------
1952 /// sel_signal | Css Ctb_ss Cxx.. in the range [0,1]
1953 /// sel_bkg | Cts_sb Cbb
1954 ///
1955 /// and takes this into account when calculating the mis class. cost (former: error fraction):
1956 ///
1957 /// err = sum_events ( weight* y_true*y_sel * beta(event)
1958 
1959 Double_t TMVA::MethodBDT::AdaCost( vector<const TMVA::Event*>& eventSample, DecisionTree *dt )
1960 {
1961  Double_t Css = fCss;
1962  Double_t Cbb = fCbb;
1963  Double_t Cts_sb = fCts_sb;
1964  Double_t Ctb_ss = fCtb_ss;
1965 
1966  Double_t err=0, sumGlobalWeights=0, sumGlobalCost=0;
1967 
1968  std::vector<Double_t> sumw(DataInfo().GetNClasses(),0); //for individually re-scaling each class
1969 
1970  for (vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
1971  Double_t w = (*e)->GetWeight();
1972  sumGlobalWeights += w;
1973  UInt_t iclass=(*e)->GetClass();
1974 
1975  sumw[iclass] += w;
1976 
1977  if ( DoRegression() ) {
1978  Log() << kFATAL << " AdaCost not implemented for regression"<<Endl;
1979  }else{
1980 
1981  Double_t dtoutput = (dt->CheckEvent(*e,false) - 0.5)*2.;
1982  Int_t trueType;
1983  Bool_t isTrueSignal = DataInfo().IsSignal(*e);
1984  Bool_t isSelectedSignal = (dtoutput>0);
1985  if (isTrueSignal) trueType = 1;
1986  else trueType = -1;
1987 
1988  Double_t cost=0;
1989  if (isTrueSignal && isSelectedSignal) cost=Css;
1990  else if (isTrueSignal && !isSelectedSignal) cost=Cts_sb;
1991  else if (!isTrueSignal && isSelectedSignal) cost=Ctb_ss;
1992  else if (!isTrueSignal && !isSelectedSignal) cost=Cbb;
1993  else Log() << kERROR << "something went wrong in AdaCost" << Endl;
1994 
1995  sumGlobalCost+= w*trueType*dtoutput*cost;
1996 
1997  }
1998  }
1999 
2000  if ( DoRegression() ) {
2001  Log() << kFATAL << " AdaCost not implemented for regression"<<Endl;
2002  }
2003 
2004  // Log() << kDEBUG << "BDT AdaBoos wrong/all: " << sumGlobalCost << "/" << sumGlobalWeights << Endl;
2005  // Log() << kWARNING << "BDT AdaBoos wrong/all: " << sumGlobalCost << "/" << sumGlobalWeights << Endl;
2006  sumGlobalCost /= sumGlobalWeights;
2007  // Log() << kWARNING << "BDT AdaBoos wrong/all: " << sumGlobalCost << "/" << sumGlobalWeights << Endl;
2008 
2009 
2010  Double_t newSumGlobalWeights=0;
2011  vector<Double_t> newSumClassWeights(sumw.size(),0);
2012 
2013  Double_t boostWeight = TMath::Log((1+sumGlobalCost)/(1-sumGlobalCost)) * fAdaBoostBeta;
2014 
2016 
2017  for (vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
2018  Double_t dtoutput = (dt->CheckEvent(*e,false) - 0.5)*2.;
2019  Int_t trueType;
2020  Bool_t isTrueSignal = DataInfo().IsSignal(*e);
2021  Bool_t isSelectedSignal = (dtoutput>0);
2022  if (isTrueSignal) trueType = 1;
2023  else trueType = -1;
2024 
2025  Double_t cost=0;
2026  if (isTrueSignal && isSelectedSignal) cost=Css;
2027  else if (isTrueSignal && !isSelectedSignal) cost=Cts_sb;
2028  else if (!isTrueSignal && isSelectedSignal) cost=Ctb_ss;
2029  else if (!isTrueSignal && !isSelectedSignal) cost=Cbb;
2030  else Log() << kERROR << "something went wrong in AdaCost" << Endl;
2031 
2032  Double_t boostfactor = TMath::Exp(-1*boostWeight*trueType*dtoutput*cost);
2033  if (DoRegression())Log() << kFATAL << " AdaCost not implemented for regression"<<Endl;
2034  if ( (*e)->GetWeight() > 0 ){
2035  (*e)->SetBoostWeight( (*e)->GetBoostWeight() * boostfactor);
2036  // Helge change back (*e)->ScaleBoostWeight(boostfactor);
2037  if (DoRegression())Log() << kFATAL << " AdaCost not implemented for regression"<<Endl;
2038  } else {
2039  if ( fInverseBoostNegWeights )(*e)->ScaleBoostWeight( 1. / boostfactor); // if the original event weight is negative, and you want to "increase" the events "positive" influence, you'd rather make the event weight "smaller" in terms of it's absolute value while still keeping it something "negative"
2040  }
2041 
2042  newSumGlobalWeights+=(*e)->GetWeight();
2043  newSumClassWeights[(*e)->GetClass()] += (*e)->GetWeight();
2044  }
2045 
2046 
2047  // Double_t globalNormWeight=sumGlobalWeights/newSumGlobalWeights;
2048  Double_t globalNormWeight=Double_t(eventSample.size())/newSumGlobalWeights;
2049  Log() << kDEBUG << "new Nsig="<<newSumClassWeights[0]*globalNormWeight << " new Nbkg="<<newSumClassWeights[1]*globalNormWeight << Endl;
2050 
2051 
2052  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
2053  // if (fRenormByClass) (*e)->ScaleBoostWeight( normWeightByClass[(*e)->GetClass()] );
2054  // else (*e)->ScaleBoostWeight( globalNormWeight );
2055  if (DataInfo().IsSignal(*e))(*e)->ScaleBoostWeight( globalNormWeight * fSigToBkgFraction );
2056  else (*e)->ScaleBoostWeight( globalNormWeight );
2057  }
2058 
2059 
2060  if (!(DoRegression()))results->GetHist("BoostWeights")->Fill(boostWeight);
2061  results->GetHist("BoostWeightsVsTree")->SetBinContent(fForest.size(),boostWeight);
2062  results->GetHist("ErrorFrac")->SetBinContent(fForest.size(),err);
2063 
2064  fBoostWeight = boostWeight;
2065  fErrorFraction = err;
2066 
2067 
2068  return boostWeight;
2069 }
2070 
2071 ////////////////////////////////////////////////////////////////////////////////
2072 /// Call it boot-strapping, re-sampling or whatever you like, in the end it is nothing
2073 /// else but applying "random" poisson weights to each event.
2074 
2076 {
2077  // this is now done in "MethodBDT::Boost as it might be used by other boost methods, too
2078  // GetBaggedSample(eventSample);
2079 
2080  return 1.; //here as there are random weights for each event, just return a constant==1;
2081 }
2082 
2083 ////////////////////////////////////////////////////////////////////////////////
2084 /// Fills fEventSample with fBaggedSampleFraction*NEvents random training events.
2085 
2086 void TMVA::MethodBDT::GetBaggedSubSample(std::vector<const TMVA::Event*>& eventSample)
2087 {
2088 
2089  Double_t n;
2090  TRandom3 *trandom = new TRandom3(100*fForest.size()+1234);
2091 
2092  if (!fSubSample.empty()) fSubSample.clear();
2093 
2094  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
2095  n = trandom->PoissonD(fBaggedSampleFraction);
2096  for (Int_t i=0;i<n;i++) fSubSample.push_back(*e);
2097  }
2098 
2099  delete trandom;
2100  return;
2101 
2102  /*
2103  UInt_t nevents = fEventSample.size();
2104 
2105  if (!fSubSample.empty()) fSubSample.clear();
2106  TRandom3 *trandom = new TRandom3(fForest.size()+1);
2107 
2108  for (UInt_t ievt=0; ievt<nevents; ievt++) { // recreate new random subsample
2109  if(trandom->Rndm()<fBaggedSampleFraction)
2110  fSubSample.push_back(fEventSample[ievt]);
2111  }
2112  delete trandom;
2113  */
2114 
2115 }
2116 
2117 ////////////////////////////////////////////////////////////////////////////////
2118 /// A special boosting only for Regression (not implemented).
2119 
2120 Double_t TMVA::MethodBDT::RegBoost( std::vector<const TMVA::Event*>& /* eventSample */, DecisionTree* /* dt */ )
2121 {
2122  return 1;
2123 }
2124 
2125 ////////////////////////////////////////////////////////////////////////////////
2126 /// Adaption of the AdaBoost to regression problems (see H.Drucker 1997).
2127 
2128 Double_t TMVA::MethodBDT::AdaBoostR2( std::vector<const TMVA::Event*>& eventSample, DecisionTree *dt )
2129 {
2130  if ( !DoRegression() ) Log() << kFATAL << "Somehow you chose a regression boost method for a classification job" << Endl;
2131 
2132  Double_t err=0, sumw=0, sumwfalse=0, sumwfalse2=0;
2133  Double_t maxDev=0;
2134  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
2135  Double_t w = (*e)->GetWeight();
2136  sumw += w;
2137 
2138  Double_t tmpDev = TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) );
2139  sumwfalse += w * tmpDev;
2140  sumwfalse2 += w * tmpDev*tmpDev;
2141  if (tmpDev > maxDev) maxDev = tmpDev;
2142  }
2143 
2144  //if quadratic loss:
2145  if (fAdaBoostR2Loss=="linear"){
2146  err = sumwfalse/maxDev/sumw ;
2147  }
2148  else if (fAdaBoostR2Loss=="quadratic"){
2149  err = sumwfalse2/maxDev/maxDev/sumw ;
2150  }
2151  else if (fAdaBoostR2Loss=="exponential"){
2152  err = 0;
2153  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
2154  Double_t w = (*e)->GetWeight();
2155  Double_t tmpDev = TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) );
2156  err += w * (1 - exp (-tmpDev/maxDev)) / sumw;
2157  }
2158 
2159  }
2160  else {
2161  Log() << kFATAL << " you've chosen a Loss type for Adaboost other than linear, quadratic or exponential "
2162  << " namely " << fAdaBoostR2Loss << "\n"
2163  << "and this is not implemented... a typo in the options ??" <<Endl;
2164  }
2165 
2166 
2167  if (err >= 0.5) { // sanity check ... should never happen as otherwise there is apparently
2168  // something odd with the assignment of the leaf nodes (rem: you use the training
2169  // events for this determination of the error rate)
2170  if (dt->GetNNodes() == 1){
2171  Log() << kERROR << " YOUR tree has only 1 Node... kind of a funny *tree*. I cannot "
2172  << "boost such a thing... if after 1 step the error rate is == 0.5"
2173  << Endl
2174  << "please check why this happens, maybe too many events per node requested ?"
2175  << Endl;
2176 
2177  }else{
2178  Log() << kERROR << " The error rate in the BDT boosting is > 0.5. ("<< err
2179  << ") That should not happen, but is possible for regression trees, and"
2180  << " should trigger a stop for the boosting. please check your code (i.e... the BDT code), I "
2181  << " stop boosting " << Endl;
2182  return -1;
2183  }
2184  err = 0.5;
2185  } else if (err < 0) {
2186  Log() << kERROR << " The error rate in the BDT boosting is < 0. That can happen"
2187  << " due to improper treatment of negative weights in a Monte Carlo.. (if you have"
2188  << " an idea on how to do it in a better way, please let me know (Helge.Voss@cern.ch)"
2189  << " for the time being I set it to its absolute value.. just to continue.." << Endl;
2190  err = TMath::Abs(err);
2191  }
2192 
2193  Double_t boostWeight = err / (1.-err);
2194  Double_t newSumw=0;
2195 
2197 
2198  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
2199  Double_t boostfactor = TMath::Power(boostWeight,(1.-TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) )/maxDev ) );
2200  results->GetHist("BoostWeights")->Fill(boostfactor);
2201  // std::cout << "R2 " << boostfactor << " " << boostWeight << " " << (1.-TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) )/maxDev) << std::endl;
2202  if ( (*e)->GetWeight() > 0 ){
2203  Float_t newBoostWeight = (*e)->GetBoostWeight() * boostfactor;
2204  Float_t newWeight = (*e)->GetWeight() * (*e)->GetBoostWeight() * boostfactor;
2205  if (newWeight == 0) {
2206  Log() << kINFO << "Weight= " << (*e)->GetWeight() << Endl;
2207  Log() << kINFO << "BoostWeight= " << (*e)->GetBoostWeight() << Endl;
2208  Log() << kINFO << "boostweight="<<boostWeight << " err= " <<err << Endl;
2209  Log() << kINFO << "NewBoostWeight= " << newBoostWeight << Endl;
2210  Log() << kINFO << "boostfactor= " << boostfactor << Endl;
2211  Log() << kINFO << "maxDev = " << maxDev << Endl;
2212  Log() << kINFO << "tmpDev = " << TMath::Abs(dt->CheckEvent(*e,kFALSE) - (*e)->GetTarget(0) ) << Endl;
2213  Log() << kINFO << "target = " << (*e)->GetTarget(0) << Endl;
2214  Log() << kINFO << "estimate = " << dt->CheckEvent(*e,kFALSE) << Endl;
2215  }
2216  (*e)->SetBoostWeight( newBoostWeight );
2217  // (*e)->SetBoostWeight( (*e)->GetBoostWeight() * boostfactor);
2218  } else {
2219  (*e)->SetBoostWeight( (*e)->GetBoostWeight() / boostfactor);
2220  }
2221  newSumw+=(*e)->GetWeight();
2222  }
2223 
2224  // re-normalise the weights
2225  Double_t normWeight = sumw / newSumw;
2226  for (std::vector<const TMVA::Event*>::const_iterator e=eventSample.begin(); e!=eventSample.end();++e) {
2227  //Helge (*e)->ScaleBoostWeight( sumw/newSumw);
2228  // (*e)->ScaleBoostWeight( normWeight);
2229  (*e)->SetBoostWeight( (*e)->GetBoostWeight() * normWeight );
2230  }
2231 
2232 
2233  results->GetHist("BoostWeightsVsTree")->SetBinContent(fForest.size(),1./boostWeight);
2234  results->GetHist("ErrorFrac")->SetBinContent(fForest.size(),err);
2235 
2236  fBoostWeight = boostWeight;
2237  fErrorFraction = err;
2238 
2239  return TMath::Log(1./boostWeight);
2240 }
2241 
2242 ////////////////////////////////////////////////////////////////////////////////
2243 /// Write weights to XML.
2244 
2245 void TMVA::MethodBDT::AddWeightsXMLTo( void* parent ) const
2246 {
2247  void* wght = gTools().AddChild(parent, "Weights");
2248 
2249  if (fDoPreselection){
2250  for (UInt_t ivar=0; ivar<GetNvar(); ivar++){
2251  gTools().AddAttr( wght, Form("PreselectionLowBkgVar%d",ivar), fIsLowBkgCut[ivar]);
2252  gTools().AddAttr( wght, Form("PreselectionLowBkgVar%dValue",ivar), fLowBkgCut[ivar]);
2253  gTools().AddAttr( wght, Form("PreselectionLowSigVar%d",ivar), fIsLowSigCut[ivar]);
2254  gTools().AddAttr( wght, Form("PreselectionLowSigVar%dValue",ivar), fLowSigCut[ivar]);
2255  gTools().AddAttr( wght, Form("PreselectionHighBkgVar%d",ivar), fIsHighBkgCut[ivar]);
2256  gTools().AddAttr( wght, Form("PreselectionHighBkgVar%dValue",ivar),fHighBkgCut[ivar]);
2257  gTools().AddAttr( wght, Form("PreselectionHighSigVar%d",ivar), fIsHighSigCut[ivar]);
2258  gTools().AddAttr( wght, Form("PreselectionHighSigVar%dValue",ivar),fHighSigCut[ivar]);
2259  }
2260  }
2261 
2262 
2263  gTools().AddAttr( wght, "NTrees", fForest.size() );
2264  gTools().AddAttr( wght, "AnalysisType", fForest.back()->GetAnalysisType() );
2265 
2266  for (UInt_t i=0; i< fForest.size(); i++) {
2267  void* trxml = fForest[i]->AddXMLTo(wght);
2268  gTools().AddAttr( trxml, "boostWeight", fBoostWeights[i] );
2269  gTools().AddAttr( trxml, "itree", i );
2270  }
2271 }
2272 
2273 ////////////////////////////////////////////////////////////////////////////////
2274 /// Reads the BDT from the xml file.
2275 
2277  UInt_t i;
2278  for (i=0; i<fForest.size(); i++) delete fForest[i];
2279  fForest.clear();
2280  fBoostWeights.clear();
2281 
2282  UInt_t ntrees;
2283  UInt_t analysisType;
2284  Float_t boostWeight;
2285 
2286 
2287  if (gTools().HasAttr( parent, Form("PreselectionLowBkgVar%d",0))) {
2288  fIsLowBkgCut.resize(GetNvar());
2289  fLowBkgCut.resize(GetNvar());
2290  fIsLowSigCut.resize(GetNvar());
2291  fLowSigCut.resize(GetNvar());
2292  fIsHighBkgCut.resize(GetNvar());
2293  fHighBkgCut.resize(GetNvar());
2294  fIsHighSigCut.resize(GetNvar());
2295  fHighSigCut.resize(GetNvar());
2296 
2297  Bool_t tmpBool;
2298  Double_t tmpDouble;
2299  for (UInt_t ivar=0; ivar<GetNvar(); ivar++){
2300  gTools().ReadAttr( parent, Form("PreselectionLowBkgVar%d",ivar), tmpBool);
2301  fIsLowBkgCut[ivar]=tmpBool;
2302  gTools().ReadAttr( parent, Form("PreselectionLowBkgVar%dValue",ivar), tmpDouble);
2303  fLowBkgCut[ivar]=tmpDouble;
2304  gTools().ReadAttr( parent, Form("PreselectionLowSigVar%d",ivar), tmpBool);
2305  fIsLowSigCut[ivar]=tmpBool;
2306  gTools().ReadAttr( parent, Form("PreselectionLowSigVar%dValue",ivar), tmpDouble);
2307  fLowSigCut[ivar]=tmpDouble;
2308  gTools().ReadAttr( parent, Form("PreselectionHighBkgVar%d",ivar), tmpBool);
2309  fIsHighBkgCut[ivar]=tmpBool;
2310  gTools().ReadAttr( parent, Form("PreselectionHighBkgVar%dValue",ivar), tmpDouble);
2311  fHighBkgCut[ivar]=tmpDouble;
2312  gTools().ReadAttr( parent, Form("PreselectionHighSigVar%d",ivar),tmpBool);
2313  fIsHighSigCut[ivar]=tmpBool;
2314  gTools().ReadAttr( parent, Form("PreselectionHighSigVar%dValue",ivar), tmpDouble);
2315  fHighSigCut[ivar]=tmpDouble;
2316  }
2317  }
2318 
2319 
2320  gTools().ReadAttr( parent, "NTrees", ntrees );
2321 
2322  if(gTools().HasAttr(parent, "TreeType")) { // pre 4.1.0 version
2323  gTools().ReadAttr( parent, "TreeType", analysisType );
2324  } else { // from 4.1.0 onwards
2325  gTools().ReadAttr( parent, "AnalysisType", analysisType );
2326  }
2327 
2328  void* ch = gTools().GetChild(parent);
2329  i=0;
2330  while(ch) {
2331  fForest.push_back( dynamic_cast<DecisionTree*>( DecisionTree::CreateFromXML(ch, GetTrainingTMVAVersionCode()) ) );
2332  fForest.back()->SetAnalysisType(Types::EAnalysisType(analysisType));
2333  fForest.back()->SetTreeID(i++);
2334  gTools().ReadAttr(ch,"boostWeight",boostWeight);
2335  fBoostWeights.push_back(boostWeight);
2336  ch = gTools().GetNextChild(ch);
2337  }
2338 }
2339 
2340 ////////////////////////////////////////////////////////////////////////////////
2341 /// Read the weights (BDT coefficients).
2342 
2343 void TMVA::MethodBDT::ReadWeightsFromStream( std::istream& istr )
2344 {
2345  TString dummy;
2346  // Types::EAnalysisType analysisType;
2347  Int_t analysisType(0);
2348 
2349  // coverity[tainted_data_argument]
2350  istr >> dummy >> fNTrees;
2351  Log() << kINFO << "Read " << fNTrees << " Decision trees" << Endl;
2352 
2353  for (UInt_t i=0;i<fForest.size();i++) delete fForest[i];
2354  fForest.clear();
2355  fBoostWeights.clear();
2356  Int_t iTree;
2357  Double_t boostWeight;
2358  for (int i=0;i<fNTrees;i++) {
2359  istr >> dummy >> iTree >> dummy >> boostWeight;
2360  if (iTree != i) {
2361  fForest.back()->Print( std::cout );
2362  Log() << kFATAL << "Error while reading weight file; mismatch iTree="
2363  << iTree << " i=" << i
2364  << " dummy " << dummy
2365  << " boostweight " << boostWeight
2366  << Endl;
2367  }
2368  fForest.push_back( new DecisionTree() );
2369  fForest.back()->SetAnalysisType(Types::EAnalysisType(analysisType));
2370  fForest.back()->SetTreeID(i);
2371  fForest.back()->Read(istr, GetTrainingTMVAVersionCode());
2372  fBoostWeights.push_back(boostWeight);
2373  }
2374 }
2375 
2376 ////////////////////////////////////////////////////////////////////////////////
2377 
2379  return this->GetMvaValue( err, errUpper, 0 );
2380 }
2381 
2382 ////////////////////////////////////////////////////////////////////////////////
2383 /// Return the MVA value (range [-1;1]) that classifies the
2384 /// event according to the majority vote from the total number of
2385 /// decision trees.
2386 
2388 {
2389  const Event* ev = GetEvent();
2390  if (fDoPreselection) {
2391  Double_t val = ApplyPreselectionCuts(ev);
2392  if (TMath::Abs(val)>0.05) return val;
2393  }
2394  return PrivateGetMvaValue(ev, err, errUpper, useNTrees);
2395 
2396 }
2397 
2398 ////////////////////////////////////////////////////////////////////////////////
2399 /// Return the MVA value (range [-1;1]) that classifies the
2400 /// event according to the majority vote from the total number of
2401 /// decision trees.
2402 
2404 {
2405  // cannot determine error
2406  NoErrorCalc(err, errUpper);
2407 
2408  // allow for the possibility to use less trees in the actual MVA calculation
2409  // than have been originally trained.
2410  UInt_t nTrees = fForest.size();
2411 
2412  if (useNTrees > 0 ) nTrees = useNTrees;
2413 
2414  if (fBoostType=="Grad") return GetGradBoostMVA(ev,nTrees);
2415 
2416  Double_t myMVA = 0;
2417  Double_t norm = 0;
2418  for (UInt_t itree=0; itree<nTrees; itree++) {
2419  //
2420  myMVA += fBoostWeights[itree] * fForest[itree]->CheckEvent(ev,fUseYesNoLeaf);
2421  norm += fBoostWeights[itree];
2422  }
2423  return ( norm > std::numeric_limits<double>::epsilon() ) ? myMVA /= norm : 0 ;
2424 }
2425 
2426 
2427 ////////////////////////////////////////////////////////////////////////////////
2428 /// Get the multiclass MVA response for the BDT classifier.
2429 
2430 const std::vector<Float_t>& TMVA::MethodBDT::GetMulticlassValues()
2431 {
2432  const TMVA::Event *e = GetEvent();
2433  if (fMulticlassReturnVal == NULL) fMulticlassReturnVal = new std::vector<Float_t>();
2434  fMulticlassReturnVal->clear();
2435 
2436  UInt_t nClasses = DataInfo().GetNClasses();
2437  std::vector<Double_t> temp(nClasses);
2438  auto forestSize = fForest.size();
2439  // trees 0, nClasses, 2*nClasses, ... belong to class 0
2440  // trees 1, nClasses+1, 2*nClasses+1, ... belong to class 1 and so forth
2441  UInt_t classOfTree = 0;
2442  for (UInt_t itree = 0; itree < forestSize; ++itree) {
2443  temp[classOfTree] += fForest[itree]->CheckEvent(e, kFALSE);
2444  if (++classOfTree == nClasses) classOfTree = 0; // cheap modulo
2445  }
2446 
2447  // we want to calculate sum of exp(temp[j] - temp[i]) for all i,j (i!=j)
2448  // first calculate exp(), then replace minus with division.
2449  std::transform(temp.begin(), temp.end(), temp.begin(), [](Double_t d){return exp(d);});
2450 
2451  for(UInt_t iClass=0; iClass<nClasses; iClass++){
2452  Double_t norm = 0.0;
2453  for(UInt_t j=0;j<nClasses;j++){
2454  if(iClass!=j)
2455  norm += temp[j] / temp[iClass];
2456  }
2457  (*fMulticlassReturnVal).push_back(1.0/(1.0+norm));
2458  }
2459 
2460  return *fMulticlassReturnVal;
2461 }
2462 
2463 ////////////////////////////////////////////////////////////////////////////////
2464 /// Get the regression value generated by the BDTs.
2465 
2466 const std::vector<Float_t> & TMVA::MethodBDT::GetRegressionValues()
2467 {
2468 
2469  if (fRegressionReturnVal == NULL) fRegressionReturnVal = new std::vector<Float_t>();
2470  fRegressionReturnVal->clear();
2471 
2472  const Event * ev = GetEvent();
2473  Event * evT = new Event(*ev);
2474 
2475  Double_t myMVA = 0;
2476  Double_t norm = 0;
2477  if (fBoostType=="AdaBoostR2") {
2478  // rather than using the weighted average of the tree respones in the forest
2479  // H.Decker(1997) proposed to use the "weighted median"
2480 
2481  // sort all individual tree responses according to the prediction value
2482  // (keep the association to their tree weight)
2483  // the sum up all the associated weights (starting from the one whose tree
2484  // yielded the smalles response) up to the tree "t" at which you've
2485  // added enough tree weights to have more than half of the sum of all tree weights.
2486  // choose as response of the forest that one which belongs to this "t"
2487 
2488  vector< Double_t > response(fForest.size());
2489  vector< Double_t > weight(fForest.size());
2490  Double_t totalSumOfWeights = 0;
2491 
2492  for (UInt_t itree=0; itree<fForest.size(); itree++) {
2493  response[itree] = fForest[itree]->CheckEvent(ev,kFALSE);
2494  weight[itree] = fBoostWeights[itree];
2495  totalSumOfWeights += fBoostWeights[itree];
2496  }
2497 
2498  std::vector< std::vector<Double_t> > vtemp;
2499  vtemp.push_back( response ); // this is the vector that will get sorted
2500  vtemp.push_back( weight );
2501  gTools().UsefulSortAscending( vtemp );
2502 
2503  Int_t t=0;
2504  Double_t sumOfWeights = 0;
2505  while (sumOfWeights <= totalSumOfWeights/2.) {
2506  sumOfWeights += vtemp[1][t];
2507  t++;
2508  }
2509 
2510  Double_t rVal=0;
2511  Int_t count=0;
2512  for (UInt_t i= TMath::Max(UInt_t(0),UInt_t(t-(fForest.size()/6)-0.5));
2513  i< TMath::Min(UInt_t(fForest.size()),UInt_t(t+(fForest.size()/6)+0.5)); i++) {
2514  count++;
2515  rVal+=vtemp[0][i];
2516  }
2517  // fRegressionReturnVal->push_back( rVal/Double_t(count));
2518  evT->SetTarget(0, rVal/Double_t(count) );
2519  }
2520  else if(fBoostType=="Grad"){
2521  for (UInt_t itree=0; itree<fForest.size(); itree++) {
2522  myMVA += fForest[itree]->CheckEvent(ev,kFALSE);
2523  }
2524  // fRegressionReturnVal->push_back( myMVA+fBoostWeights[0]);
2525  evT->SetTarget(0, myMVA+fBoostWeights[0] );
2526  }
2527  else{
2528  for (UInt_t itree=0; itree<fForest.size(); itree++) {
2529  //
2530  myMVA += fBoostWeights[itree] * fForest[itree]->CheckEvent(ev,kFALSE);
2531  norm += fBoostWeights[itree];
2532  }
2533  // fRegressionReturnVal->push_back( ( norm > std::numeric_limits<double>::epsilon() ) ? myMVA /= norm : 0 );
2534  evT->SetTarget(0, ( norm > std::numeric_limits<double>::epsilon() ) ? myMVA /= norm : 0 );
2535  }
2536 
2537 
2538 
2539  const Event* evT2 = GetTransformationHandler().InverseTransform( evT );
2540  fRegressionReturnVal->push_back( evT2->GetTarget(0) );
2541 
2542  delete evT;
2543 
2544 
2545  return *fRegressionReturnVal;
2546 }
2547 
2548 ////////////////////////////////////////////////////////////////////////////////
2549 /// Here we could write some histograms created during the processing
2550 /// to the output file.
2551 
2553 {
2554  Log() << kDEBUG << "\tWrite monitoring histograms to file: " << BaseDir()->GetPath() << Endl;
2555 
2556  //Results* results = Data()->GetResults(GetMethodName(), Types::kTraining, Types::kMaxAnalysisType);
2557  //results->GetStorage()->Write();
2558  fMonitorNtuple->Write();
2559 }
2560 
2561 ////////////////////////////////////////////////////////////////////////////////
2562 /// Return the relative variable importance, normalized to all
2563 /// variables together having the importance 1. The importance in
2564 /// evaluated as the total separation-gain that this variable had in
2565 /// the decision trees (weighted by the number of events)
2566 
2568 {
2569  fVariableImportance.resize(GetNvar());
2570  for (UInt_t ivar = 0; ivar < GetNvar(); ivar++) {
2571  fVariableImportance[ivar]=0;
2572  }
2573  Double_t sum=0;
2574  for (UInt_t itree = 0; itree < GetNTrees(); itree++) {
2575  std::vector<Double_t> relativeImportance(fForest[itree]->GetVariableImportance());
2576  for (UInt_t i=0; i< relativeImportance.size(); i++) {
2577  fVariableImportance[i] += fBoostWeights[itree] * relativeImportance[i];
2578  }
2579  }
2580 
2581  for (UInt_t ivar=0; ivar< fVariableImportance.size(); ivar++){
2583  sum += fVariableImportance[ivar];
2584  }
2585  for (UInt_t ivar=0; ivar< fVariableImportance.size(); ivar++) fVariableImportance[ivar] /= sum;
2586 
2587  return fVariableImportance;
2588 }
2589 
2590 ////////////////////////////////////////////////////////////////////////////////
2591 /// Returns the measure for the variable importance of variable "ivar"
2592 /// which is later used in GetVariableImportance() to calculate the
2593 /// relative variable importances.
2594 
2596 {
2597  std::vector<Double_t> relativeImportance = this->GetVariableImportance();
2598  if (ivar < (UInt_t)relativeImportance.size()) return relativeImportance[ivar];
2599  else Log() << kFATAL << "<GetVariableImportance> ivar = " << ivar << " is out of range " << Endl;
2600 
2601  return -1;
2602 }
2603 
2604 ////////////////////////////////////////////////////////////////////////////////
2605 /// Compute ranking of input variables
2606 
2608 {
2609  // create the ranking object
2610  fRanking = new Ranking( GetName(), "Variable Importance" );
2611  vector< Double_t> importance(this->GetVariableImportance());
2612 
2613  for (UInt_t ivar=0; ivar<GetNvar(); ivar++) {
2614 
2615  fRanking->AddRank( Rank( GetInputLabel(ivar), importance[ivar] ) );
2616  }
2617 
2618  return fRanking;
2619 }
2620 
2621 ////////////////////////////////////////////////////////////////////////////////
2622 /// Get help message text.
2623 
2625 {
2626  Log() << Endl;
2627  Log() << gTools().Color("bold") << "--- Short description:" << gTools().Color("reset") << Endl;
2628  Log() << Endl;
2629  Log() << "Boosted Decision Trees are a collection of individual decision" << Endl;
2630  Log() << "trees which form a multivariate classifier by (weighted) majority " << Endl;
2631  Log() << "vote of the individual trees. Consecutive decision trees are " << Endl;
2632  Log() << "trained using the original training data set with re-weighted " << Endl;
2633  Log() << "events. By default, the AdaBoost method is employed, which gives " << Endl;
2634  Log() << "events that were misclassified in the previous tree a larger " << Endl;
2635  Log() << "weight in the training of the following tree." << Endl;
2636  Log() << Endl;
2637  Log() << "Decision trees are a sequence of binary splits of the data sample" << Endl;
2638  Log() << "using a single discriminant variable at a time. A test event " << Endl;
2639  Log() << "ending up after the sequence of left-right splits in a final " << Endl;
2640  Log() << "(\"leaf\") node is classified as either signal or background" << Endl;
2641  Log() << "depending on the majority type of training events in that node." << Endl;
2642  Log() << Endl;
2643  Log() << gTools().Color("bold") << "--- Performance optimisation:" << gTools().Color("reset") << Endl;
2644  Log() << Endl;
2645  Log() << "By the nature of the binary splits performed on the individual" << Endl;
2646  Log() << "variables, decision trees do not deal well with linear correlations" << Endl;
2647  Log() << "between variables (they need to approximate the linear split in" << Endl;
2648  Log() << "the two dimensional space by a sequence of splits on the two " << Endl;
2649  Log() << "variables individually). Hence decorrelation could be useful " << Endl;
2650  Log() << "to optimise the BDT performance." << Endl;
2651  Log() << Endl;
2652  Log() << gTools().Color("bold") << "--- Performance tuning via configuration options:" << gTools().Color("reset") << Endl;
2653  Log() << Endl;
2654  Log() << "The two most important parameters in the configuration are the " << Endl;
2655  Log() << "minimal number of events requested by a leaf node as percentage of the " <<Endl;
2656  Log() << " number of training events (option \"MinNodeSize\" replacing the actual number " << Endl;
2657  Log() << " of events \"nEventsMin\" as given in earlier versions" << Endl;
2658  Log() << "If this number is too large, detailed features " << Endl;
2659  Log() << "in the parameter space are hard to be modelled. If it is too small, " << Endl;
2660  Log() << "the risk to overtrain rises and boosting seems to be less effective" << Endl;
2661  Log() << " typical values from our current experience for best performance " << Endl;
2662  Log() << " are between 0.5(%) and 10(%) " << Endl;
2663  Log() << Endl;
2664  Log() << "The default minimal number is currently set to " << Endl;
2665  Log() << " max(20, (N_training_events / N_variables^2 / 10)) " << Endl;
2666  Log() << "and can be changed by the user." << Endl;
2667  Log() << Endl;
2668  Log() << "The other crucial parameter, the pruning strength (\"PruneStrength\")," << Endl;
2669  Log() << "is also related to overtraining. It is a regularisation parameter " << Endl;
2670  Log() << "that is used when determining after the training which splits " << Endl;
2671  Log() << "are considered statistically insignificant and are removed. The" << Endl;
2672  Log() << "user is advised to carefully watch the BDT screen output for" << Endl;
2673  Log() << "the comparison between efficiencies obtained on the training and" << Endl;
2674  Log() << "the independent test sample. They should be equal within statistical" << Endl;
2675  Log() << "errors, in order to minimize statistical fluctuations in different samples." << Endl;
2676 }
2677 
2678 ////////////////////////////////////////////////////////////////////////////////
2679 /// Make ROOT-independent C++ class for classifier response (classifier-specific implementation).
2680 
2681 void TMVA::MethodBDT::MakeClassSpecific( std::ostream& fout, const TString& className ) const
2682 {
2683  TString nodeName = className;
2684  nodeName.ReplaceAll("Read","");
2685  nodeName.Append("Node");
2686  // write BDT-specific classifier response
2687  fout << " std::vector<"<<nodeName<<"*> fForest; // i.e. root nodes of decision trees" << std::endl;
2688  fout << " std::vector<double> fBoostWeights; // the weights applied in the individual boosts" << std::endl;
2689  fout << "};" << std::endl << std::endl;
2690  fout << "double " << className << "::GetMvaValue__( const std::vector<double>& inputValues ) const" << std::endl;
2691  fout << "{" << std::endl;
2692  fout << " double myMVA = 0;" << std::endl;
2693  if (fDoPreselection){
2694  for (UInt_t ivar = 0; ivar< fIsLowBkgCut.size(); ivar++){
2695  if (fIsLowBkgCut[ivar]){
2696  fout << " if (inputValues["<<ivar<<"] < " << fLowBkgCut[ivar] << ") return -1; // is background preselection cut" << std::endl;
2697  }
2698  if (fIsLowSigCut[ivar]){
2699  fout << " if (inputValues["<<ivar<<"] < "<< fLowSigCut[ivar] << ") return 1; // is signal preselection cut" << std::endl;
2700  }
2701  if (fIsHighBkgCut[ivar]){
2702  fout << " if (inputValues["<<ivar<<"] > "<<fHighBkgCut[ivar] <<") return -1; // is background preselection cut" << std::endl;
2703  }
2704  if (fIsHighSigCut[ivar]){
2705  fout << " if (inputValues["<<ivar<<"] > "<<fHighSigCut[ivar]<<") return 1; // is signal preselection cut" << std::endl;
2706  }
2707  }
2708  }
2709 
2710  if (fBoostType!="Grad"){
2711  fout << " double norm = 0;" << std::endl;
2712  }
2713  fout << " for (unsigned int itree=0; itree<fForest.size(); itree++){" << std::endl;
2714  fout << " "<<nodeName<<" *current = fForest[itree];" << std::endl;
2715  fout << " while (current->GetNodeType() == 0) { //intermediate node" << std::endl;
2716  fout << " if (current->GoesRight(inputValues)) current=("<<nodeName<<"*)current->GetRight();" << std::endl;
2717  fout << " else current=("<<nodeName<<"*)current->GetLeft();" << std::endl;
2718  fout << " }" << std::endl;
2719  if (fBoostType=="Grad"){
2720  fout << " myMVA += current->GetResponse();" << std::endl;
2721  }else{
2722  if (fUseYesNoLeaf) fout << " myMVA += fBoostWeights[itree] * current->GetNodeType();" << std::endl;
2723  else fout << " myMVA += fBoostWeights[itree] * current->GetPurity();" << std::endl;
2724  fout << " norm += fBoostWeights[itree];" << std::endl;
2725  }
2726  fout << " }" << std::endl;
2727  if (fBoostType=="Grad"){
2728  fout << " return 2.0/(1.0+exp(-2.0*myMVA))-1.0;" << std::endl;
2729  }
2730  else fout << " return myMVA /= norm;" << std::endl;
2731  fout << "};" << std::endl << std::endl;
2732  fout << "void " << className << "::Initialize()" << std::endl;
2733  fout << "{" << std::endl;
2734  //Now for each decision tree, write directly the constructors of the nodes in the tree structure
2735  for (UInt_t itree=0; itree<GetNTrees(); itree++) {
2736  fout << " // itree = " << itree << std::endl;
2737  fout << " fBoostWeights.push_back(" << fBoostWeights[itree] << ");" << std::endl;
2738  fout << " fForest.push_back( " << std::endl;
2739  this->MakeClassInstantiateNode((DecisionTreeNode*)fForest[itree]->GetRoot(), fout, className);
2740  fout <<" );" << std::endl;
2741  }
2742  fout << " return;" << std::endl;
2743  fout << "};" << std::endl;
2744  fout << " " << std::endl;
2745  fout << "// Clean up" << std::endl;
2746  fout << "inline void " << className << "::Clear() " << std::endl;
2747  fout << "{" << std::endl;
2748  fout << " for (unsigned int itree=0; itree<fForest.size(); itree++) { " << std::endl;
2749  fout << " delete fForest[itree]; " << std::endl;
2750  fout << " }" << std::endl;
2751  fout << "}" << std::endl;
2752 }
2753 
2754 ////////////////////////////////////////////////////////////////////////////////
2755 /// Specific class header.
2756 
2757 void TMVA::MethodBDT::MakeClassSpecificHeader( std::ostream& fout, const TString& className) const
2758 {
2759  TString nodeName = className;
2760  nodeName.ReplaceAll("Read","");
2761  nodeName.Append("Node");
2762  //fout << "#ifndef NN" << std::endl; commented out on purpose see next line
2763  fout << "#define NN new "<<nodeName << std::endl; // NN definition depends on individual methods. Important to have NO #ifndef if several BDT methods compile together
2764  //fout << "#endif" << std::endl; commented out on purpose see previous line
2765  fout << " " << std::endl;
2766  fout << "#ifndef "<<nodeName<<"__def" << std::endl;
2767  fout << "#define "<<nodeName<<"__def" << std::endl;
2768  fout << " " << std::endl;
2769  fout << "class "<<nodeName<<" {" << std::endl;
2770  fout << " " << std::endl;
2771  fout << "public:" << std::endl;
2772  fout << " " << std::endl;
2773  fout << " // constructor of an essentially \"empty\" node floating in space" << std::endl;
2774  fout << " "<<nodeName<<" ( "<<nodeName<<"* left,"<<nodeName<<"* right," << std::endl;
2775  if (fUseFisherCuts){
2776  fout << " int nFisherCoeff," << std::endl;
2777  for (UInt_t i=0;i<GetNVariables()+1;i++){
2778  fout << " double fisherCoeff"<<i<<"," << std::endl;
2779  }
2780  }
2781  fout << " int selector, double cutValue, bool cutType, " << std::endl;
2782  fout << " int nodeType, double purity, double response ) :" << std::endl;
2783  fout << " fLeft ( left )," << std::endl;
2784  fout << " fRight ( right )," << std::endl;
2785  if (fUseFisherCuts) fout << " fNFisherCoeff ( nFisherCoeff )," << std::endl;
2786  fout << " fSelector ( selector )," << std::endl;
2787  fout << " fCutValue ( cutValue )," << std::endl;
2788  fout << " fCutType ( cutType )," << std::endl;
2789  fout << " fNodeType ( nodeType )," << std::endl;
2790  fout << " fPurity ( purity )," << std::endl;
2791  fout << " fResponse ( response ){" << std::endl;
2792  if (fUseFisherCuts){
2793  for (UInt_t i=0;i<GetNVariables()+1;i++){
2794  fout << " fFisherCoeff.push_back(fisherCoeff"<<i<<");" << std::endl;
2795  }
2796  }
2797  fout << " }" << std::endl << std::endl;
2798  fout << " virtual ~"<<nodeName<<"();" << std::endl << std::endl;
2799  fout << " // test event if it descends the tree at this node to the right" << std::endl;
2800  fout << " virtual bool GoesRight( const std::vector<double>& inputValues ) const;" << std::endl;
2801  fout << " "<<nodeName<<"* GetRight( void ) {return fRight; };" << std::endl << std::endl;
2802  fout << " // test event if it descends the tree at this node to the left " << std::endl;
2803  fout << " virtual bool GoesLeft ( const std::vector<double>& inputValues ) const;" << std::endl;
2804  fout << " "<<nodeName<<"* GetLeft( void ) { return fLeft; }; " << std::endl << std::endl;
2805  fout << " // return S/(S+B) (purity) at this node (from training)" << std::endl << std::endl;
2806  fout << " double GetPurity( void ) const { return fPurity; } " << std::endl;
2807  fout << " // return the node type" << std::endl;
2808  fout << " int GetNodeType( void ) const { return fNodeType; }" << std::endl;
2809  fout << " double GetResponse(void) const {return fResponse;}" << std::endl << std::endl;
2810  fout << "private:" << std::endl << std::endl;
2811  fout << " "<<nodeName<<"* fLeft; // pointer to the left daughter node" << std::endl;
2812  fout << " "<<nodeName<<"* fRight; // pointer to the right daughter node" << std::endl;
2813  if (fUseFisherCuts){
2814  fout << " int fNFisherCoeff; // =0 if this node doesn't use fisher, else =nvar+1 " << std::endl;
2815  fout << " std::vector<double> fFisherCoeff; // the fisher coeff (offset at the last element)" << std::endl;
2816  }
2817  fout << " int fSelector; // index of variable used in node selection (decision tree) " << std::endl;
2818  fout << " double fCutValue; // cut value applied on this node to discriminate bkg against sig" << std::endl;
2819  fout << " bool fCutType; // true: if event variable > cutValue ==> signal , false otherwise" << std::endl;
2820  fout << " int fNodeType; // Type of node: -1 == Bkg-leaf, 1 == Signal-leaf, 0 = internal " << std::endl;
2821  fout << " double fPurity; // Purity of node from training"<< std::endl;
2822  fout << " double fResponse; // Regression response value of node" << std::endl;
2823  fout << "}; " << std::endl;
2824  fout << " " << std::endl;
2825  fout << "//_______________________________________________________________________" << std::endl;
2826  fout << " "<<nodeName<<"::~"<<nodeName<<"()" << std::endl;
2827  fout << "{" << std::endl;
2828  fout << " if (fLeft != NULL) delete fLeft;" << std::endl;
2829  fout << " if (fRight != NULL) delete fRight;" << std::endl;
2830  fout << "}; " << std::endl;
2831  fout << " " << std::endl;
2832  fout << "//_______________________________________________________________________" << std::endl;
2833  fout << "bool "<<nodeName<<"::GoesRight( const std::vector<double>& inputValues ) const" << std::endl;
2834  fout << "{" << std::endl;
2835  fout << " // test event if it descends the tree at this node to the right" << std::endl;
2836  fout << " bool result;" << std::endl;
2837  if (fUseFisherCuts){
2838  fout << " if (fNFisherCoeff == 0){" << std::endl;
2839  fout << " result = (inputValues[fSelector] > fCutValue );" << std::endl;
2840  fout << " }else{" << std::endl;
2841  fout << " double fisher = fFisherCoeff.at(fFisherCoeff.size()-1);" << std::endl;
2842  fout << " for (unsigned int ivar=0; ivar<fFisherCoeff.size()-1; ivar++)" << std::endl;
2843  fout << " fisher += fFisherCoeff.at(ivar)*inputValues.at(ivar);" << std::endl;
2844  fout << " result = fisher > fCutValue;" << std::endl;
2845  fout << " }" << std::endl;
2846  }else{
2847  fout << " result = (inputValues[fSelector] > fCutValue );" << std::endl;
2848  }
2849  fout << " if (fCutType == true) return result; //the cuts are selecting Signal ;" << std::endl;
2850  fout << " else return !result;" << std::endl;
2851  fout << "}" << std::endl;
2852  fout << " " << std::endl;
2853  fout << "//_______________________________________________________________________" << std::endl;
2854  fout << "bool "<<nodeName<<"::GoesLeft( const std::vector<double>& inputValues ) const" << std::endl;
2855  fout << "{" << std::endl;
2856  fout << " // test event if it descends the tree at this node to the left" << std::endl;
2857  fout << " if (!this->GoesRight(inputValues)) return true;" << std::endl;
2858  fout << " else return false;" << std::endl;
2859  fout << "}" << std::endl;
2860  fout << " " << std::endl;
2861  fout << "#endif" << std::endl;
2862  fout << " " << std::endl;
2863 }
2864 
2865 ////////////////////////////////////////////////////////////////////////////////
2866 /// Recursively descends a tree and writes the node instance to the output stream.
2867 
2868 void TMVA::MethodBDT::MakeClassInstantiateNode( DecisionTreeNode *n, std::ostream& fout, const TString& className ) const
2869 {
2870  if (n == NULL) {
2871  Log() << kFATAL << "MakeClassInstantiateNode: started with undefined node" <<Endl;
2872  return ;
2873  }
2874  fout << "NN("<<std::endl;
2875  if (n->GetLeft() != NULL){
2876  this->MakeClassInstantiateNode( (DecisionTreeNode*)n->GetLeft() , fout, className);
2877  }
2878  else {
2879  fout << "0";
2880  }
2881  fout << ", " <<std::endl;
2882  if (n->GetRight() != NULL){
2883  this->MakeClassInstantiateNode( (DecisionTreeNode*)n->GetRight(), fout, className );
2884  }
2885  else {
2886  fout << "0";
2887  }
2888  fout << ", " << std::endl
2889  << std::setprecision(6);
2890  if (fUseFisherCuts){
2891  fout << n->GetNFisherCoeff() << ", ";
2892  for (UInt_t i=0; i< GetNVariables()+1; i++) {
2893  if (n->GetNFisherCoeff() == 0 ){
2894  fout << "0, ";
2895  }else{
2896  fout << n->GetFisherCoeff(i) << ", ";
2897  }
2898  }
2899  }
2900  fout << n->GetSelector() << ", "
2901  << n->GetCutValue() << ", "
2902  << n->GetCutType() << ", "
2903  << n->GetNodeType() << ", "
2904  << n->GetPurity() << ","
2905  << n->GetResponse() << ") ";
2906 }
2907 
2908 ////////////////////////////////////////////////////////////////////////////////
2909 /// Find useful preselection cuts that will be applied before
2910 /// and Decision Tree training.. (and of course also applied
2911 /// in the GetMVA .. --> -1 for background +1 for Signal)
2912 
2913 void TMVA::MethodBDT::DeterminePreselectionCuts(const std::vector<const TMVA::Event*>& eventSample)
2914 {
2915  Double_t nTotS = 0.0, nTotB = 0.0;
2916  Int_t nTotS_unWeighted = 0, nTotB_unWeighted = 0;
2917 
2918  std::vector<TMVA::BDTEventWrapper> bdtEventSample;
2919 
2920  fIsLowSigCut.assign(GetNvar(),kFALSE);
2921  fIsLowBkgCut.assign(GetNvar(),kFALSE);
2922  fIsHighSigCut.assign(GetNvar(),kFALSE);
2923  fIsHighBkgCut.assign(GetNvar(),kFALSE);
2924 
2925  fLowSigCut.assign(GetNvar(),0.); // ---------------| --> in var is signal (accept all above lower cut)
2926  fLowBkgCut.assign(GetNvar(),0.); // ---------------| --> in var is bkg (accept all above lower cut)
2927  fHighSigCut.assign(GetNvar(),0.); // <-- | -------------- in var is signal (accept all blow cut)
2928  fHighBkgCut.assign(GetNvar(),0.); // <-- | -------------- in var is blg (accept all blow cut)
2929 
2930 
2931  // Initialize (un)weighted counters for signal & background
2932  // Construct a list of event wrappers that point to the original data
2933  for( std::vector<const TMVA::Event*>::const_iterator it = eventSample.begin(); it != eventSample.end(); ++it ) {
2934  if (DataInfo().IsSignal(*it)){
2935  nTotS += (*it)->GetWeight();
2936  ++nTotS_unWeighted;
2937  }
2938  else {
2939  nTotB += (*it)->GetWeight();
2940  ++nTotB_unWeighted;
2941  }
2942  bdtEventSample.push_back(TMVA::BDTEventWrapper(*it));
2943  }
2944 
2945  for( UInt_t ivar = 0; ivar < GetNvar(); ivar++ ) { // loop over all discriminating variables
2946  TMVA::BDTEventWrapper::SetVarIndex(ivar); // select the variable to sort by
2947  std::sort( bdtEventSample.begin(),bdtEventSample.end() ); // sort the event data
2948 
2949  Double_t bkgWeightCtr = 0.0, sigWeightCtr = 0.0;
2950  std::vector<TMVA::BDTEventWrapper>::iterator it = bdtEventSample.begin(), it_end = bdtEventSample.end();
2951  for( ; it != it_end; ++it ) {
2952  if (DataInfo().IsSignal(**it))
2953  sigWeightCtr += (**it)->GetWeight();
2954  else
2955  bkgWeightCtr += (**it)->GetWeight();
2956  // Store the accumulated signal (background) weights
2957  it->SetCumulativeWeight(false,bkgWeightCtr);
2958  it->SetCumulativeWeight(true,sigWeightCtr);
2959  }
2960 
2961  //variable that determines how "exact" you cut on the preselection found in the training data. Here I chose
2962  //1% of the variable range...
2963  Double_t dVal = (DataInfo().GetVariableInfo(ivar).GetMax() - DataInfo().GetVariableInfo(ivar).GetMin())/100. ;
2964  Double_t nSelS, nSelB, effS=0.05, effB=0.05, rejS=0.05, rejB=0.05;
2965  Double_t tmpEffS, tmpEffB, tmpRejS, tmpRejB;
2966  // Locate the optimal cut for this (ivar-th) variable
2967 
2968 
2969 
2970  for(UInt_t iev = 1; iev < bdtEventSample.size(); iev++) {
2971  //dVal = bdtEventSample[iev].GetVal() - bdtEventSample[iev-1].GetVal();
2972 
2973  nSelS = bdtEventSample[iev].GetCumulativeWeight(true);
2974  nSelB = bdtEventSample[iev].GetCumulativeWeight(false);
2975  // you look for some 100% efficient pre-selection cut to remove background.. i.e. nSelS=0 && nSelB>5%nTotB or ( nSelB=0 nSelS>5%nTotS)
2976  tmpEffS=nSelS/nTotS;
2977  tmpEffB=nSelB/nTotB;
2978  tmpRejS=1-tmpEffS;
2979  tmpRejB=1-tmpEffB;
2980  if (nSelS==0 && tmpEffB>effB) {effB=tmpEffB; fLowBkgCut[ivar] = bdtEventSample[iev].GetVal() - dVal; fIsLowBkgCut[ivar]=kTRUE;}
2981  else if (nSelB==0 && tmpEffS>effS) {effS=tmpEffS; fLowSigCut[ivar] = bdtEventSample[iev].GetVal() - dVal; fIsLowSigCut[ivar]=kTRUE;}
2982  else if (nSelB==nTotB && tmpRejS>rejS) {rejS=tmpRejS; fHighSigCut[ivar] = bdtEventSample[iev].GetVal() + dVal; fIsHighSigCut[ivar]=kTRUE;}
2983  else if (nSelS==nTotS && tmpRejB>rejB) {rejB=tmpRejB; fHighBkgCut[ivar] = bdtEventSample[iev].GetVal() + dVal; fIsHighBkgCut[ivar]=kTRUE;}
2984 
2985  }
2986  }
2987 
2988  Log() << kDEBUG << " \tfound and suggest the following possible pre-selection cuts " << Endl;
2989  if (fDoPreselection) Log() << kDEBUG << "\tthe training will be done after these cuts... and GetMVA value returns +1, (-1) for a signal (bkg) event that passes these cuts" << Endl;
2990  else Log() << kDEBUG << "\tas option DoPreselection was not used, these cuts however will not be performed, but the training will see the full sample"<<Endl;
2991  for (UInt_t ivar=0; ivar < GetNvar(); ivar++ ) { // loop over all discriminating variables
2992  if (fIsLowBkgCut[ivar]){
2993  Log() << kDEBUG << " \tfound cut: Bkg if var " << ivar << " < " << fLowBkgCut[ivar] << Endl;
2994  }
2995  if (fIsLowSigCut[ivar]){
2996  Log() << kDEBUG << " \tfound cut: Sig if var " << ivar << " < " << fLowSigCut[ivar] << Endl;
2997  }
2998  if (fIsHighBkgCut[ivar]){
2999  Log() << kDEBUG << " \tfound cut: Bkg if var " << ivar << " > " << fHighBkgCut[ivar] << Endl;
3000  }
3001  if (fIsHighSigCut[ivar]){
3002  Log() << kDEBUG << " \tfound cut: Sig if var " << ivar << " > " << fHighSigCut[ivar] << Endl;
3003  }
3004  }
3005 
3006  return;
3007 }
3008 
3009 ////////////////////////////////////////////////////////////////////////////////
3010 /// Apply the preselection cuts before even bothering about any
3011 /// Decision Trees in the GetMVA .. --> -1 for background +1 for Signal
3012 
3014 {
3015  Double_t result=0;
3016 
3017  for (UInt_t ivar=0; ivar < GetNvar(); ivar++ ) { // loop over all discriminating variables
3018  if (fIsLowBkgCut[ivar]){
3019  if (ev->GetValue(ivar) < fLowBkgCut[ivar]) result = -1; // is background
3020  }
3021  if (fIsLowSigCut[ivar]){
3022  if (ev->GetValue(ivar) < fLowSigCut[ivar]) result = 1; // is signal
3023  }
3024  if (fIsHighBkgCut[ivar]){
3025  if (ev->GetValue(ivar) > fHighBkgCut[ivar]) result = -1; // is background
3026  }
3027  if (fIsHighSigCut[ivar]){
3028  if (ev->GetValue(ivar) > fHighSigCut[ivar]) result = 1; // is signal
3029  }
3030  }
3031 
3032  return result;
3033 }
3034 
Bool_t fUseYesNoLeaf
Definition: MethodBDT.h:242
Types::EAnalysisType fAnalysisType
Definition: MethodBase.h:584
void Train(void)
BDT training.
Definition: MethodBDT.cxx:1154
void PreProcessNegativeEventWeights()
O.k.
Definition: MethodBDT.cxx:944
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3251
double dist(Rotation3D const &r1, Rotation3D const &r2)
Definition: 3DDistances.cxx:48
void GetBaggedSubSample(std::vector< const TMVA::Event *> &)
Fills fEventSample with fBaggedSampleFraction*NEvents random training events.
Definition: MethodBDT.cxx:2086
static long int sum(long int i)
Definition: Factory.cxx:2258
virtual Double_t Fit(std::vector< LossFunctionEventInfo > &evs)=0
Random number generator class based on M.
Definition: TRandom3.h:27
THist< 1, int, THistStatContent > TH1I
Definition: THist.hxx:287
virtual Double_t PoissonD(Double_t mean)
Generates a random number according to a Poisson law.
Definition: TRandom.cxx:435
MsgLogger & Endl(MsgLogger &ml)
Definition: MsgLogger.h:158
Singleton class for Global types used by TMVA.
Definition: Types.h:73
long long Long64_t
Definition: RtypesCore.h:69
std::vector< Bool_t > fIsLowSigCut
Definition: MethodBDT.h:292
Double_t RegBoost(std::vector< const TMVA::Event *> &, DecisionTree *dt)
A special boosting only for Regression (not implemented).
Definition: MethodBDT.cxx:2120
void DeclareCompatibilityOptions()
Options that are used ONLY for the READER to ensure backward compatibility.
Definition: MethodBDT.cxx:467
std::map< const TMVA::Event *, LossFunctionEventInfo > fLossFunctionEventInfo
Definition: MethodBDT.h:227
Bool_t fPairNegWeightsGlobal
Definition: MethodBDT.h:261
void AddPoint(Double_t x, Double_t y1, Double_t y2)
This function is used only in 2 TGraph case, and it will add new data points to graphs.
Definition: MethodBase.cxx:212
void SetUseNvars(Int_t n)
Definition: MethodBDT.h:145
Bool_t fRandomisedTrees
Definition: MethodBDT.h:252
TString fMinNodeSizeS
Definition: MethodBDT.h:236
Double_t Log(Double_t x)
Definition: TMath.h:759
const Ranking * CreateRanking()
Compute ranking of input variables.
Definition: MethodBDT.cxx:2607
virtual void Delete(Option_t *option="")
Delete this tree from memory or/and disk.
Definition: TTree.cxx:3550
Bool_t IsConstructedFromWeightFile() const
Definition: MethodBase.h:529
float Float_t
Definition: RtypesCore.h:53
TString fPruneMethodS
Definition: MethodBDT.h:248
Double_t GetMin() const
Definition: VariableInfo.h:63
TString fSepTypeS
Definition: MethodBDT.h:233
Double_t CheckEvent(const TMVA::Event *, Bool_t UseYesNoLeaf=kFALSE) const
the event e is put into the decision tree (starting at the root node) and the output is NodeType (sig...
void BDT(TString dataset, const TString &fin="TMVA.root")
Absolute Deviation BDT Loss Function.
Definition: LossFunction.h:282
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:687
UInt_t GetNvar() const
Definition: MethodBase.h:335
TTree * fMonitorNtuple
Definition: MethodBDT.h:267
UInt_t GetNNodes() const
Definition: BinaryTree.h:86
virtual Int_t Fill()
Fill all branches.
Definition: TTree.cxx:4374
THist< 1, float, THistStatContent, THistStatUncertainty > TH1F
Definition: THist.hxx:285
Double_t fAdaBoostBeta
Definition: MethodBDT.h:219
MsgLogger & Log() const
Definition: Configurable.h:122
std::vector< Bool_t > fIsHighSigCut
Definition: MethodBDT.h:294
OptionBase * DeclareOptionRef(T &ref, const TString &name, const TString &desc="")
void DeclareOptions()
Define the options (their key words).
Definition: MethodBDT.cxx:346
std::vector< Double_t > fVariableImportance
Definition: MethodBDT.h:281
Bool_t IsFloat() const
Returns kTRUE if string contains a floating point or integer number.
Definition: TString.cxx:1766
void DeterminePreselectionCuts(const std::vector< const TMVA::Event *> &eventSample)
Find useful preselection cuts that will be applied before and Decision Tree training.
Definition: MethodBDT.cxx:2913
static Config & Instance()
static function: returns TMVA instance
Definition: Config.cxx:109
EAnalysisType
Definition: Types.h:127
void MakeClassInstantiateNode(DecisionTreeNode *n, std::ostream &fout, const TString &className) const
Recursively descends a tree and writes the node instance to the output stream.
Definition: MethodBDT.cxx:2868
Double_t fMinLinCorrForFisher
Definition: MethodBDT.h:240
Virtual base Class for all MVA method.
Definition: MethodBase.h:109
std::vector< const TMVA::Event * > fEventSample
Definition: MethodBDT.h:209
Double_t Bagging()
Call it boot-strapping, re-sampling or whatever you like, in the end it is nothing else but applying ...
Definition: MethodBDT.cxx:2075
bool fExitFromTraining
Definition: MethodBase.h:438
Bool_t fBaggedGradBoost
Definition: MethodBDT.h:224
Bool_t fDoBoostMonitor
Definition: MethodBDT.h:263
Basic string class.
Definition: TString.h:131
1-D histogram with a float per channel (see TH1 documentation)}
Definition: TH1.h:567
TransformationHandler & GetTransformationHandler(Bool_t takeReroutedIfAvailable=true)
Definition: MethodBase.h:385
Ranking for variables in method (implementation)
Definition: Ranking.h:48
#define f(i)
Definition: RSha256.hxx:104
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1100
int Int_t
Definition: RtypesCore.h:41
virtual void SetYTitle(const char *title)
Definition: TH1.h:406
bool Bool_t
Definition: RtypesCore.h:59
virtual void SetTitle(const char *title="")
Set graph title.
Definition: TGraph.cxx:2216
Double_t AdaBoost(std::vector< const TMVA::Event *> &, DecisionTree *dt)
The AdaBoost implementation.
Definition: MethodBDT.cxx:1781
UInt_t GetNClasses() const
Definition: DataSetInfo.h:136
void ProcessOptions()
The option string is decoded, for available options see "DeclareOptions".
Definition: MethodBDT.cxx:483
Bool_t fBaggedBoost
Definition: MethodBDT.h:223
Int_t FloorNint(Double_t x)
Definition: TMath.h:706
void GetHelpMessage() const
Get help message text.
Definition: MethodBDT.cxx:2624
Bool_t GetCutType(void) const
std::vector< Bool_t > fIsHighBkgCut
Definition: MethodBDT.h:295
void SetShrinkage(Double_t s)
Definition: MethodBDT.h:144
Double_t AdaCost(std::vector< const TMVA::Event *> &, DecisionTree *dt)
The AdaCost boosting algorithm takes a simple cost Matrix (currently fixed for all events...
Definition: MethodBDT.cxx:1959
Bool_t fAutomatic
Definition: MethodBDT.h:251
void MakeClassSpecific(std::ostream &, const TString &) const
Make ROOT-independent C++ class for classifier response (classifier-specific implementation).
Definition: MethodBDT.cxx:2681
void AddAttr(void *node, const char *, const T &value, Int_t precision=16)
add attribute to xml
Definition: Tools.h:353
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 ...
Double_t fCts_sb
Definition: MethodBDT.h:273
void * AddChild(void *parent, const char *childname, const char *content=0, bool isRootNode=false)
add child node
Definition: Tools.cxx:1136
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
TString fRegressionLossFunctionBDTGS
Definition: MethodBDT.h:299
Double_t fBoostWeight
Definition: MethodBDT.h:269
Double_t GetMvaValue(Double_t *err=0, Double_t *errUpper=0)
Definition: MethodBDT.cxx:2378
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Definition: TMath.h:734
const TString & GetInputLabel(Int_t i) const
Definition: MethodBase.h:341
UInt_t GetNumThreadsInPool()
Definition: MethodBDT.h:114
Huber BDT Loss Function.
Definition: LossFunction.h:200
UInt_t fSignalClass
Definition: MethodBase.h:678
Double_t fPruneStrength
Definition: MethodBDT.h:249
std::vector< Double_t > fHighBkgCut
Definition: MethodBDT.h:290
Double_t GetGradBoostMVA(const TMVA::Event *e, UInt_t nTrees)
Returns MVA value: -1 for background, 1 for signal.
Definition: MethodBDT.cxx:1434
TClass * GetClass(T *)
Definition: TClass.h:577
TSeq< unsigned int > TSeqU
Definition: TSeq.hxx:195
Double_t fBaggedSampleFraction
Definition: MethodBDT.h:257
Implementation of the CrossEntropy as separation criterion.
Definition: CrossEntropy.h:43
Bool_t fInverseBoostNegWeights
Definition: MethodBDT.h:260
Double_t GradBoostRegression(std::vector< const TMVA::Event *> &, DecisionTree *dt)
Implementation of M_TreeBoost using any loss function as described by Friedman 1999.
Definition: MethodBDT.cxx:1564
virtual void SetTuneParameters(std::map< TString, Double_t > tuneParameters)
Set the tuning parameters according to the argument.
Definition: MethodBDT.cxx:1133
virtual void SetName(const char *name="")
Set graph name.
Definition: TGraph.cxx:2207
void MakeClassSpecificHeader(std::ostream &, const TString &) const
Specific class header.
Definition: MethodBDT.cxx:2757
Float_t GetCutValue(void) const
UInt_t GetTrainingTMVAVersionCode() const
Definition: MethodBase.h:380
const Event * GetEvent() const
Definition: MethodBase.h:740
DataSet * Data() const
Definition: MethodBase.h:400
Double_t fSigToBkgFraction
Definition: MethodBDT.h:217
virtual Bool_t HasAnalysisType(Types::EAnalysisType type, UInt_t numberClasses, UInt_t numberTargets)
BDT can handle classification with multiple classes and regression with one regression-target.
Definition: MethodBDT.cxx:293
UInt_t GetNFisherCoeff() const
Bool_t fDoPreselection
Definition: MethodBDT.h:277
void * GetChild(void *parent, const char *childname=0)
get child node
Definition: Tools.cxx:1162
void Reset(void)
Reset the method, as if it had just been instantiated (forget all training etc.). ...
Definition: MethodBDT.cxx:737
TString & Append(const char *cs)
Definition: TString.h:559
void SetMinNodeSize(Double_t sizeInPercent)
Definition: MethodBDT.cxx:672
TString fAdaBoostR2Loss
Definition: MethodBDT.h:220
void Init(std::vector< TString > &graphTitles)
This function gets some title and it creates a TGraph for every title.
Definition: MethodBase.cxx:174
DataSetInfo & DataInfo() const
Definition: MethodBase.h:401
Bool_t DoRegression() const
Definition: MethodBase.h:429
Int_t fMinNodeEvents
Definition: MethodBDT.h:234
Double_t AdaBoostR2(std::vector< const TMVA::Event *> &, DecisionTree *dt)
Adaption of the AdaBoost to regression problems (see H.Drucker 1997).
Definition: MethodBDT.cxx:2128
void SetNTrees(Int_t d)
Definition: MethodBDT.h:141
std::vector< Double_t > fHighSigCut
Definition: MethodBDT.h:289
Class that contains all the data information.
Definition: DataSetInfo.h:60
Least Squares BDT Loss Function.
Definition: LossFunction.h:243
Implementation of the SdivSqrtSplusB as separation criterion.
PDF wrapper for histograms; uses user-defined spline interpolation.
Definition: PDF.h:63
ROOT::TThreadExecutor & GetThreadExecutor()
Definition: Config.h:82
Double_t fCtb_ss
Definition: MethodBDT.h:274
Long64_t GetNTrainingEvents() const
Definition: DataSet.h:79
const std::vector< Float_t > & GetMulticlassValues()
Get the multiclass MVA response for the BDT classifier.
Definition: MethodBDT.cxx:2430
UInt_t fIPyCurrentIter
Definition: MethodBase.h:439
virtual void Print(Option_t *option="") const
Print TNamed name and title.
Definition: TNamed.cxx:128
Float_t fMinNodeSize
Definition: MethodBDT.h:235
const Event * GetTrainingEvent(Long64_t ievt) const
Definition: MethodBase.h:760
Implementation of the MisClassificationError as separation criterion.
Bool_t fNoNegWeightsInTraining
Definition: MethodBDT.h:259
TString GetElapsedTime(Bool_t Scientific=kTRUE)
returns pretty string with elapsed time
Definition: Timer.cxx:134
Double_t GetMax() const
Definition: VariableInfo.h:64
Bool_t DoMulticlass() const
Definition: MethodBase.h:430
const std::vector< Float_t > & GetRegressionValues()
Get the regression value generated by the BDTs.
Definition: MethodBDT.cxx:2466
static const uint32_t K[64]
Definition: RSha256.hxx:148
void InitEventSample()
Initialize the event sample (i.e. reset the boost-weights... etc).
Definition: MethodBDT.cxx:773
std::vector< Bool_t > fIsLowBkgCut
Definition: MethodBDT.h:293
void WriteMonitoringHistosToFile(void) const
Here we could write some histograms created during the processing to the output file.
Definition: MethodBDT.cxx:2552
virtual void Delete(Option_t *option="")
Delete this object.
Definition: TObject.cxx:169
Double_t fErrorFraction
Definition: MethodBDT.h:270
VecExpr< UnaryOp< Fabs< T >, VecExpr< A, T, D >, T >, T, D > fabs(const VecExpr< A, T, D > &rhs)
const Event * GetTestingEvent(Long64_t ievt) const
Definition: MethodBase.h:766
virtual Double_t Determinant() const
virtual Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition: TTree.cxx:9298
Float_t GetTarget(UInt_t itgt) const
Definition: Event.h:97
Bool_t HasTrainingTree() const
Definition: MethodBase.h:502
Results * GetResults(const TString &, Types::ETreeType type, Types::EAnalysisType analysistype)
Definition: DataSet.cxx:265
std::vector< Double_t > fLowBkgCut
Definition: MethodBDT.h:288
Int_t GetNodeType(void) const
ROOT::R::TRInterface & r
Definition: Object.C:4
Double_t fNodePurityLimit
Definition: MethodBDT.h:243
Service class for 2-Dim histogram classes.
Definition: TH2.h:30
Bool_t fHistoricBool
Definition: MethodBDT.h:297
void SetBaggedSampleFraction(Double_t f)
Definition: MethodBDT.h:146
SVector< double, 2 > v
Definition: Dict.h:5
virtual TString Name()=0
const char * GetName() const
Definition: MethodBase.h:325
ClassInfo * GetClassInfo(Int_t clNum) const
std::map< TString, Double_t > optimize()
TGraph * GetGraph(const TString &alias) const
Definition: Results.cxx:153
void BoostMonitor(Int_t iTree)
Fills the ROCIntegral vs Itree from the testSample for the monitoring plots during the training ...
Definition: MethodBDT.cxx:1687
The TMVA::Interval Class.
Definition: Interval.h:61
Double_t GetFisherCoeff(Int_t ivar) const
Bool_t fTrainWithNegWeights
Definition: MethodBDT.h:262
Bool_t fSkipNormalization
Definition: MethodBDT.h:279
void DeleteResults(const TString &, Types::ETreeType type, Types::EAnalysisType analysistype)
delete the results stored for this particular Method instance.
Definition: DataSet.cxx:316
virtual ~MethodBDT(void)
Destructor.
Definition: MethodBDT.cxx:765
Implementation of the GiniIndex as separation criterion.
Definition: GiniIndex.h:63
virtual void SetBinContent(Int_t bin, Double_t content)
Set bin content see convention for numbering bins in TH1::GetBin In case the bin number is greater th...
Definition: TH1.cxx:8514
void SetNodePurityLimit(Double_t l)
Definition: MethodBDT.h:143
UInt_t fIPyMaxIter
Definition: MethodBase.h:439
Double_t PrivateGetMvaValue(const TMVA::Event *ev, Double_t *err=0, Double_t *errUpper=0, UInt_t useNTrees=0)
Return the MVA value (range [-1;1]) that classifies the event according to the majority vote from the...
Definition: MethodBDT.cxx:2403
Implementation of a Decision Tree.
Definition: DecisionTree.h:64
unsigned int UInt_t
Definition: RtypesCore.h:42
Double_t GradBoost(std::vector< const TMVA::Event *> &, DecisionTree *dt, UInt_t cls=0)
Calculate the desired response value for each region.
Definition: MethodBDT.cxx:1530
char * Form(const char *fmt,...)
const Event * InverseTransform(const Event *, Bool_t suppressIfNoTargets=true) const
double floor(double)
Int_t GetN() const
Definition: TGraph.h:122
const TString & GetMethodName() const
Definition: MethodBase.h:322
void SetTarget(UInt_t itgt, Float_t value)
set the target value (dimension itgt) to value
Definition: Event.cxx:360
Double_t fCbb
Definition: MethodBDT.h:275
void ReadAttr(void *node, const char *, T &value)
read attribute from xml
Definition: Tools.h:335
SeparationBase * fSepType
Definition: MethodBDT.h:232
void Init(void)
Common initialisation with defaults for the BDT-Method.
Definition: MethodBDT.cxx:699
Tools & gTools()
void ReadWeightsFromXML(void *parent)
Reads the BDT from the xml file.
Definition: MethodBDT.cxx:2276
TMVA::DecisionTreeNode * GetEventNode(const TMVA::Event &e) const
get the pointer to the leaf node where a particular event ends up in...
virtual const char * GetPath() const
Returns the full path of the directory.
Definition: TDirectory.cxx:987
Bool_t fUseExclusiveVars
Definition: MethodBDT.h:241
TGraphErrors * gr
Definition: legend1.C:25
REAL epsilon
Definition: triangle.c:617
constexpr Double_t E()
Base of natural log: .
Definition: TMath.h:97
#define h(i)
Definition: RSha256.hxx:106
Double_t TestTreeQuality(DecisionTree *dt)
Test the tree quality.. in terms of Misclassification.
Definition: MethodBDT.cxx:1632
Implementation of the GiniIndex With Laplace correction as separation criterion.
Long64_t GetNTestEvents() const
Definition: DataSet.h:80
UInt_t GetNVariables() const
Definition: MethodBase.h:336
const Bool_t kFALSE
Definition: RtypesCore.h:88
Float_t GetValue(UInt_t ivar) const
return value of i&#39;th variable
Definition: Event.cxx:237
DecisionTree::EPruneMethod fPruneMethod
Definition: MethodBDT.h:247
static void SetVarIndex(Int_t iVar)
UInt_t fUseNvars
Definition: MethodBDT.h:253
UInt_t fMaxDepth
Definition: MethodBDT.h:245
Float_t GetPurity(void) const
#define d(i)
Definition: RSha256.hxx:102
Bool_t IgnoreEventsWithNegWeightsInTraining() const
Definition: MethodBase.h:675
Double_t Exp(Double_t x)
Definition: TMath.h:726
#define ClassImp(name)
Definition: Rtypes.h:359
void ReadWeightsFromStream(std::istream &istr)
Read the weights (BDT coefficients).
Definition: MethodBDT.cxx:2343
double Double_t
Definition: RtypesCore.h:55
Double_t ApplyPreselectionCuts(const Event *ev)
Apply the preselection cuts before even bothering about any Decision Trees in the GetMVA ...
Definition: MethodBDT.cxx:3013
void UpdateTargets(std::vector< const TMVA::Event *> &, UInt_t cls=0)
Calculate residual for all events.
Definition: MethodBDT.cxx:1448
std::vector< Float_t > * fMulticlassReturnVal
Definition: MethodBase.h:587
Bool_t IsNormalised() const
Definition: MethodBase.h:485
void SetMaxDepth(Int_t d)
Definition: MethodBDT.h:137
TH1 * GetHist(const TString &alias) const
Definition: Results.cxx:136
int type
Definition: TGX11.cxx:120
void AddWeightsXMLTo(void *parent) const
Write weights to XML.
Definition: MethodBDT.cxx:2245
Double_t fShrinkage
Definition: MethodBDT.h:222
Bool_t fUsePoissonNvars
Definition: MethodBDT.h:254
static DecisionTree * CreateFromXML(void *node, UInt_t tmva_Version_Code=TMVA_VERSION_CODE)
re-create a new tree (decision tree or search tree) from XML
static RooMathCoreReg dummy
UInt_t fNumPoolThreads
Definition: MethodBDT.h:307
void * GetNextChild(void *prevchild, const char *childname=0)
XML helpers.
Definition: Tools.cxx:1174
void SetAdaBoostBeta(Double_t b)
Definition: MethodBDT.h:142
void SetCurrentType(Types::ETreeType type) const
Definition: DataSet.h:100
The TH1 histogram class.
Definition: TH1.h:56
std::vector< const TMVA::Event * > * fTrainSample
Definition: MethodBDT.h:212
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
void UsefulSortAscending(std::vector< std::vector< Double_t > > &, std::vector< TString > *vs=0)
sort 2D vector (AND in parallel a TString vector) in such a way that the "first vector is sorted" and...
Definition: Tools.cxx:550
VariableInfo & GetVariableInfo(Int_t i)
Definition: DataSetInfo.h:96
void AddPreDefVal(const T &)
Definition: Configurable.h:168
Double_t Boost(std::vector< const TMVA::Event *> &, DecisionTree *dt, UInt_t cls=0)
Apply the boosting algorithm (the algorithm is selecte via the the "option" given in the constructor...
Definition: MethodBDT.cxx:1653
UInt_t GetNumber() const
Definition: ClassInfo.h:65
void ExitFromTraining()
Definition: MethodBase.h:453
The TMVA::Interval Class.
Definition: LogInterval.h:83
const TString & GetOptions() const
Definition: Configurable.h:84
LossFunctionBDT * fRegressionLossFunctionBDTG
Definition: MethodBDT.h:302
TString fBoostType
Definition: MethodBDT.h:218
Bool_t fUseFisherCuts
Definition: MethodBDT.h:239
const TString & Color(const TString &)
human readable color strings
Definition: Tools.cxx:840
TMatrixTSym< Element > & Invert(Double_t *det=0)
Invert the matrix and calculate its determinant Notice that the LU decomposition is used instead of B...
UInt_t fUseNTrainEvents
Definition: MethodBDT.h:255
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.
Definition: MethodBDT.cxx:1080
virtual Int_t Branch(TCollection *list, Int_t bufsize=32000, Int_t splitlevel=99, const char *name="")
Create one branch for each element in the collection.
Definition: TTree.cxx:1711
#define REGISTER_METHOD(CLASS)
for example
TString fNegWeightTreatment
Definition: MethodBDT.h:258
Abstract ClassifierFactory template that handles arbitrary types.
Ranking * fRanking
Definition: MethodBase.h:576
virtual void SetXTitle(const char *title)
Definition: TH1.h:405
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Set x and y values for point number i.
Definition: TGraph.cxx:2184
IPythonInteractive * fInteractive
Definition: MethodBase.h:437
auto Map(F func, unsigned nTimes) -> std::vector< typename std::result_of< F()>::type >
Execute func (with no arguments) nTimes in parallel.
TDirectory * BaseDir() const
returns the ROOT directory where info/histograms etc of the corresponding MVA method instance are sto...
Float_t GetResponse(void) const
virtual void AddRank(const Rank &rank)
Add a new rank take ownership of it.
Definition: Ranking.cxx:86
virtual void DeclareCompatibilityOptions()
options that are used ONLY for the READER to ensure backward compatibility they are hence without any...
Definition: MethodBase.cxx:601
Class that is the base-class for a vector of result.
Definition: Results.h:57
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
double ceil(double)
A Graph is a graphics object made of two arrays X and Y with npoints each.
Definition: TGraph.h:41
virtual DecisionTreeNode * GetLeft() const
std::vector< const TMVA::Event * > fValidationSample
Definition: MethodBDT.h:210
std::vector< DecisionTree * > fForest
Definition: MethodBDT.h:215
virtual DecisionTreeNode * GetRight() const
Bool_t IsSignal(const Event *ev) const
void DrawProgressBar(Int_t, const TString &comment="")
draws progress bar in color or B&W caution:
Definition: Timer.cxx:190
std::vector< Double_t > GetVariableImportance()
Return the relative variable importance, normalized to all variables together having the importance 1...
Definition: MethodBDT.cxx:2567
Double_t fFValidationEvents
Definition: MethodBDT.h:250
std::vector< Double_t > fLowSigCut
Definition: MethodBDT.h:287
std::vector< Float_t > * fRegressionReturnVal
Definition: MethodBase.h:586
Double_t Atof() const
Return floating-point value contained in string.
Definition: TString.cxx:1962
void UpdateTargetsRegression(std::vector< const TMVA::Event *> &, Bool_t first=kFALSE)
Calculate current residuals for all events and update targets for next iteration. ...
Definition: MethodBDT.cxx:1490
Types::EAnalysisType GetAnalysisType() const
Definition: MethodBase.h:428
A TTree object has a header with a name and a title.
Definition: TTree.h:70
Short_t GetSelector() const
std::map< const TMVA::Event *, std::vector< double > > fResiduals
Definition: MethodBDT.h:229
Definition: first.py:1
void Store(TObject *obj, const char *alias=0)
Definition: Results.cxx:86
static const Int_t fgDebugLevel
Definition: MethodBDT.h:305
virtual void Init(std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap, std::vector< double > &boostWeights)=0
Double_t Sqrt(Double_t x)
Definition: TMath.h:690
std::vector< TMatrixDSym * > * CalcCovarianceMatrices(const std::vector< Event *> &events, Int_t maxCls, VariableTransformBase *transformBase=0)
compute covariance matrices
Definition: Tools.cxx:1526
virtual void Set(Int_t n)
Set number of points in the graph Existing coordinates are preserved New coordinates above fNpoints a...
Definition: TGraph.cxx:2133
double exp(double)
THist< 2, float, THistStatContent, THistStatUncertainty > TH2F
Definition: THist.hxx:291
Double_t fCss
Definition: MethodBDT.h:272
const Bool_t kTRUE
Definition: RtypesCore.h:87
const Int_t n
Definition: legend1.C:16
std::vector< const TMVA::Event * > fSubSample
Definition: MethodBDT.h:211
Timing information for training and evaluation of MVA methods.
Definition: Timer.h:58
UInt_t GetNTrees() const
Definition: MethodBDT.h:110
Analysis of Boosted Decision Trees.
Definition: MethodBDT.h:61
Int_t CeilNint(Double_t x)
Definition: TMath.h:698
Double_t fHuberQuantile
Definition: MethodBDT.h:300
UInt_t fNNodesMax
Definition: MethodBDT.h:244
virtual void SetTargets(std::vector< const TMVA::Event *> &evs, std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap)=0
void InitGradBoost(std::vector< const TMVA::Event *> &)
Initialize targets for first tree.
Definition: MethodBDT.cxx:1593
void NoErrorCalc(Double_t *const err, Double_t *const errUpper)
Definition: MethodBase.cxx:841
void SetSignalReferenceCut(Double_t cut)
Definition: MethodBase.h:355
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
std::vector< double > fBoostWeights
Definition: MethodBDT.h:216
MethodBDT(const TString &jobName, const TString &methodTitle, DataSetInfo &theData, const TString &theOption="")
The standard constructor for the "boosted decision trees".
Definition: MethodBDT.cxx:164