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