Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
DataSetFactory.cxx
Go to the documentation of this file.
1// @(#)root/tmva $Id$
2// Author: Andreas Hoecker, Peter Speckmayer, Joerg Stelzer, Eckhard von Toerne, Helge Voss
3
4/*****************************************************************************
5 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis *
6 * Package: TMVA *
7 * Class : DataSetFactory *
8 * *
9 * *
10 * Description: *
11 * Implementation (see header for description) *
12 * *
13 * Authors (alphabetical): *
14 * Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland *
15 * Peter Speckmayer <Peter.Speckmayer@cern.ch> - CERN, Switzerland *
16 * Joerg Stelzer <Joerg.Stelzer@cern.ch> - MSU, USA *
17 * Eckhard von Toerne <evt@physik.uni-bonn.de> - U. of Bonn, Germany *
18 * Helge Voss <Helge.Voss@cern.ch> - MPI-K Heidelberg, Germany *
19 * *
20 * Copyright (c) 2009: *
21 * CERN, Switzerland *
22 * MPI-K Heidelberg, Germany *
23 * U. of Bonn, Germany *
24 * Redistribution and use in source and binary forms, with or without *
25 * modification, are permitted according to the terms listed in LICENSE *
26 * (see tmva/doc/LICENSE) *
27 *****************************************************************************/
28
29/*! \class TMVA::DataSetFactory
30\ingroup TMVA
31
32Class that contains all the data information
33
34*/
35
36#include <cassert>
37
38#include <map>
39#include <vector>
40#include <iomanip>
41#include <iostream>
42
43#include <algorithm>
44
45#include "TMVA/DataSetFactory.h"
46
47#include "TFile.h"
48#include "TRandom3.h"
49#include "TMath.h"
50#include "TTree.h"
51#include "TBranch.h"
52
53#include "TMVA/MsgLogger.h"
54#include "TMVA/Configurable.h"
55#include "TMVA/DataSet.h"
56#include "TMVA/DataSetInfo.h"
58#include "TMVA/Event.h"
59
60#include "TMVA/Tools.h"
61#include "TMVA/Types.h"
62#include "TMVA/VariableInfo.h"
63
64using std::setiosflags, std::ios;
65
66//TMVA::DataSetFactory* TMVA::DataSetFactory::fgInstance = 0;
67
68namespace TMVA {
69 // calculate the largest common divider
70 // this function is not happy if numbers are negative!
72 {
73 if (a<b) {Int_t tmp = a; a=b; b=tmp; } // achieve a>=b
74 if (b==0) return a;
75 Int_t fullFits = a/b;
77 }
78}
79
80
81////////////////////////////////////////////////////////////////////////////////
82/// constructor
83
85 fVerbose(kFALSE),
86 fVerboseLevel(TString("Info")),
87 fScaleWithPreselEff(0),
88 fCurrentTree(0),
89 fCurrentEvtIdx(0),
90 fInputFormulas(0),
91 fLogger( new MsgLogger("DataSetFactory", kINFO) )
92{
93}
94
95////////////////////////////////////////////////////////////////////////////////
96/// destructor
97
99{
100 std::vector<TTreeFormula*>::const_iterator formIt;
101
102 for (formIt = fInputFormulas.begin() ; formIt!=fInputFormulas.end() ; ++formIt) if (*formIt) delete *formIt;
103 for (formIt = fTargetFormulas.begin() ; formIt!=fTargetFormulas.end() ; ++formIt) if (*formIt) delete *formIt;
104 for (formIt = fCutFormulas.begin() ; formIt!=fCutFormulas.end() ; ++formIt) if (*formIt) delete *formIt;
105 for (formIt = fWeightFormula.begin() ; formIt!=fWeightFormula.end() ; ++formIt) if (*formIt) delete *formIt;
106 for (formIt = fSpectatorFormulas.begin(); formIt!=fSpectatorFormulas.end(); ++formIt) if (*formIt) delete *formIt;
107
108 delete fLogger;
109}
110
111////////////////////////////////////////////////////////////////////////////////
112/// steering the creation of a new dataset
113
116{
117 // build the first dataset from the data input
118 DataSet * ds = BuildInitialDataSet( dsi, dataInput );
119
120 if (ds->GetNEvents() > 1 && fComputeCorrelations ) {
121 CalcMinMax(ds,dsi);
122
123 // from the final dataset build the correlation matrix
124 for (UInt_t cl = 0; cl< dsi.GetNClasses(); cl++) {
125 const TString className = dsi.GetClassInfo(cl)->GetName();
126 dsi.SetCorrelationMatrix( className, CalcCorrelationMatrix( ds, cl ) );
127 if (fCorrelations) {
128 dsi.PrintCorrelationMatrix(className);
129 }
130 }
131 //Log() << kHEADER << Endl;
132 Log() << kHEADER << Form("[%s] : ",dsi.GetName()) << " " << Endl << Endl;
133 }
134
135 return ds;
136}
137
138////////////////////////////////////////////////////////////////////////////////
139
141{
142 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "Build DataSet consisting of one Event with dynamically changing variables" << Endl;
143 DataSet* ds = new DataSet(dsi);
144
145 // create a DataSet with one Event which uses dynamic variables
146 // (pointers to variables)
147 if(dsi.GetNClasses()==0){
148 dsi.AddClass( "data" );
149 dsi.GetClassInfo( "data" )->SetNumber(0);
150 }
151
152 std::vector<Float_t*>* evdyn = new std::vector<Float_t*>(0);
153
154 std::vector<VariableInfo>& varinfos = dsi.GetVariableInfos();
155
156 if (varinfos.empty())
157 Log() << kFATAL << Form("Dataset[%s] : ",dsi.GetName()) << "Dynamic data set cannot be built, since no variable informations are present. Apparently no variables have been set. This should not happen, please contact the TMVA authors." << Endl;
158
159 std::vector<VariableInfo>::iterator it = varinfos.begin(), itEnd=varinfos.end();
160 for (;it!=itEnd;++it) {
161 Float_t* external=(Float_t*)(*it).GetExternalLink();
162 if (external==0)
163 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "The link to the external variable is NULL while I am trying to build a dynamic data set. In this case fTmpEvent from MethodBase HAS TO BE USED in the method to get useful values in variables." << Endl;
164 else evdyn->push_back (external);
165 }
166
167 std::vector<VariableInfo>& spectatorinfos = dsi.GetSpectatorInfos();
168 std::vector<char> spectatorTypes;
169 spectatorTypes.reserve(spectatorinfos.size());
170 for (auto &&info: spectatorinfos) {
171 evdyn->push_back( (Float_t*)info.GetExternalLink() );
172 spectatorTypes.push_back(info.GetVarType());
173 }
174
175 TMVA::Event * ev = new Event((const std::vector<Float_t*>*&)evdyn, varinfos.size());
176 ev->SetSpectatorTypes(spectatorTypes);
177 std::vector<Event *> *newEventVector = new std::vector<Event *>;
178 newEventVector->push_back(ev);
179
180 ds->SetEventCollection(newEventVector, Types::kTraining);
181 ds->SetCurrentType( Types::kTraining );
182 ds->SetCurrentEvent( 0 );
183
184 delete newEventVector;
185 return ds;
186}
187
188////////////////////////////////////////////////////////////////////////////////
189/// if no entries, than create a DataSet with one Event which uses
190/// dynamic variables (pointers to variables)
191
195{
196 if (dataInput.GetEntries()==0) return BuildDynamicDataSet( dsi );
197 // -------------------------------------------------------------------------
198
199 // register the classes in the datasetinfo-object
200 // information comes from the trees in the dataInputHandler-object
201 std::vector< TString >* classList = dataInput.GetClassList();
202 for (std::vector<TString>::iterator it = classList->begin(); it< classList->end(); ++it) {
203 dsi.AddClass( (*it) );
204 }
205 delete classList;
206
207 EvtStatsPerClass eventCounts(dsi.GetNClasses());
212
213 InitOptions( dsi, eventCounts, normMode, splitSeed, splitMode , mixMode );
214 // ======= build event-vector from input, apply preselection ===============
216 BuildEventVector( dsi, dataInput, tmpEventVector, eventCounts );
217
218 DataSet* ds = MixEvents( dsi, tmpEventVector, eventCounts,
220
223 Int_t maxL = dsi.GetClassNameMaxLength();
224 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "Collected:" << Endl;
225 for (UInt_t cl = 0; cl < dsi.GetNClasses(); cl++) {
226 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " "
227 << setiosflags(ios::left) << std::setw(maxL) << dsi.GetClassInfo(cl)->GetName()
228 << " training entries: " << ds->GetNClassEvents( 0, cl ) << Endl;
229 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " "
230 << setiosflags(ios::left) << std::setw(maxL) << dsi.GetClassInfo(cl)->GetName()
231 << " testing entries: " << ds->GetNClassEvents( 1, cl ) << Endl;
232 }
233 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " " << Endl;
234 }
235
236 return ds;
237}
238
239////////////////////////////////////////////////////////////////////////////////
240/// checks a TTreeFormula for problems
241
243 const TString& expression,
245{
247
248 if( ttf->GetNdim() <= 0 )
249 Log() << kFATAL << "Expression " << expression.Data()
250 << " could not be resolved to a valid formula. " << Endl;
251 if( ttf->GetNdata() == 0 ){
252 Log() << kWARNING << "Expression: " << expression.Data()
253 << " does not provide data for this event. "
254 << "This event is not taken into account. --> please check if you use as a variable "
255 << "an entry of an array which is not filled for some events "
256 << "(e.g. arr[4] when arr has only 3 elements)." << Endl;
257 Log() << kWARNING << "If you want to take the event into account you can do something like: "
258 << "\"Alt$(arr[4],0)\" where in cases where arr doesn't have a 4th element, "
259 << " 0 is taken as an alternative." << Endl;
260 worked = kFALSE;
261 }
262 if( expression.Contains("$") )
264 else
265 {
266 for (int i = 0, iEnd = ttf->GetNcodes (); i < iEnd; ++i)
267 {
268 TLeaf* leaf = ttf->GetLeaf (i);
269 if (!leaf->IsOnTerminalBranch())
271 }
272 }
273 return worked;
274}
275
276
277////////////////////////////////////////////////////////////////////////////////
278/// While the data gets copied into the local training and testing
279/// trees, the input tree can change (for instance when changing from
280/// signal to background tree, or using TChains as input) The
281/// TTreeFormulas, that hold the input expressions need to be
282/// re-associated with the new tree, which is done here
283
285{
286 TTree *tr = tinfo.GetTree()->GetTree();
287
288 //tr->SetBranchStatus("*",1); // nor needed when using TTReeFormula
289 tr->ResetBranchAddresses();
290
291 Bool_t hasDollar = kTRUE; // Set to false if wants to enable only some branch in the tree
292
293 // 1) the input variable formulas
294 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " create input formulas for tree " << tr->GetName() << Endl;
295 std::vector<TTreeFormula*>::const_iterator formIt, formItEnd;
296 for (formIt = fInputFormulas.begin(), formItEnd=fInputFormulas.end(); formIt!=formItEnd; ++formIt) if (*formIt) delete *formIt;
297 fInputFormulas.clear();
298 TTreeFormula* ttf = 0;
299 fInputTableFormulas.clear(); // this contains shallow pointer copies
300
301 bool firstArrayVar = kTRUE;
302 int firstArrayVarIndex = -1;
303 int arraySize = -1;
304 for (UInt_t i = 0; i < dsi.GetNVariables(); i++) {
305
306 // create TTreeformula
307 if (! dsi.IsVariableFromArray(i) ) {
308 ttf = new TTreeFormula(Form("Formula%s", dsi.GetVariableInfo(i).GetInternalName().Data()),
309 dsi.GetVariableInfo(i).GetExpression().Data(), tr);
310 CheckTTreeFormula(ttf, dsi.GetVariableInfo(i).GetExpression(), hasDollar);
311 fInputFormulas.emplace_back(ttf);
312 fInputTableFormulas.emplace_back(std::make_pair(ttf, (Int_t) 0));
313 } else {
314 // it is a variable from an array
315 if (firstArrayVar) {
316
317 // create a new TFormula
318 ttf = new TTreeFormula(Form("Formula%s", dsi.GetVariableInfo(i).GetInternalName().Data()),
319 dsi.GetVariableInfo(i).GetExpression().Data(), tr);
320 CheckTTreeFormula(ttf, dsi.GetVariableInfo(i).GetExpression(), hasDollar);
321 fInputFormulas.push_back(ttf);
322
323 arraySize = dsi.GetVarArraySize(dsi.GetVariableInfo(i).GetExpression());
326
327 Log() << kINFO << "Using variable " << dsi.GetVariableInfo(i).GetInternalName() <<
328 " from array expression " << dsi.GetVariableInfo(i).GetExpression() << " of size " << arraySize << Endl;
329 }
330 fInputTableFormulas.push_back(std::make_pair(ttf, (Int_t) i-firstArrayVarIndex));
331 if (int(i)-firstArrayVarIndex == arraySize-1 ) {
332 // I am the last element of the array
335 Log() << kDEBUG << "Using Last variable from array : " << dsi.GetVariableInfo(i).GetInternalName() << Endl;
336 }
337 }
338
339 }
340
341 //
342 // targets
343 //
344 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "transform regression targets" << Endl;
345 for (formIt = fTargetFormulas.begin(), formItEnd = fTargetFormulas.end(); formIt!=formItEnd; ++formIt) if (*formIt) delete *formIt;
346 fTargetFormulas.clear();
347 for (UInt_t i=0; i<dsi.GetNTargets(); i++) {
348 ttf = new TTreeFormula( TString::Format( "Formula%s", dsi.GetTargetInfo(i).GetInternalName().Data() ),
349 dsi.GetTargetInfo(i).GetExpression().Data(), tr );
350 CheckTTreeFormula( ttf, dsi.GetTargetInfo(i).GetExpression(), hasDollar );
351 fTargetFormulas.push_back( ttf );
352 }
353
354 //
355 // spectators
356 //
357 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "transform spectator variables" << Endl;
358 for (formIt = fSpectatorFormulas.begin(), formItEnd = fSpectatorFormulas.end(); formIt!=formItEnd; ++formIt) if (*formIt) delete *formIt;
359 fSpectatorFormulas.clear();
360 for (UInt_t i=0; i<dsi.GetNSpectators(); i++) {
361 ttf = new TTreeFormula( TString::Format( "Formula%s", dsi.GetSpectatorInfo(i).GetInternalName().Data() ),
362 dsi.GetSpectatorInfo(i).GetExpression().Data(), tr );
363 CheckTTreeFormula( ttf, dsi.GetSpectatorInfo(i).GetExpression(), hasDollar );
364 fSpectatorFormulas.push_back( ttf );
365 }
366
367 //
368 // the cuts (one per class, if non-existent: formula pointer = 0)
369 //
370 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "transform cuts" << Endl;
371 for (formIt = fCutFormulas.begin(), formItEnd = fCutFormulas.end(); formIt!=formItEnd; ++formIt) if (*formIt) delete *formIt;
372 fCutFormulas.clear();
373 for (UInt_t clIdx=0; clIdx<dsi.GetNClasses(); clIdx++) {
374 const TCut& tmpCut = dsi.GetClassInfo(clIdx)->GetCut();
375 const TString tmpCutExp(tmpCut.GetTitle());
376 ttf = 0;
377 if (tmpCutExp!="") {
378 ttf = new TTreeFormula( Form("CutClass%i",clIdx), tmpCutExp, tr );
379 Bool_t worked = CheckTTreeFormula( ttf, tmpCutExp, hasDollar );
380 if( !worked ){
381 Log() << kWARNING << "Please check class \"" << dsi.GetClassInfo(clIdx)->GetName()
382 << "\" cut \"" << dsi.GetClassInfo(clIdx)->GetCut() << Endl;
383 }
384 }
385 fCutFormulas.push_back( ttf );
386 }
387
388 //
389 // the weights (one per class, if non-existent: formula pointer = 0)
390 //
391 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "transform weights" << Endl;
392 for (formIt = fWeightFormula.begin(), formItEnd = fWeightFormula.end(); formIt!=formItEnd; ++formIt) if (*formIt) delete *formIt;
393 fWeightFormula.clear();
394 for (UInt_t clIdx=0; clIdx<dsi.GetNClasses(); clIdx++) {
395 const TString tmpWeight = dsi.GetClassInfo(clIdx)->GetWeight();
396
397 if (dsi.GetClassInfo(clIdx)->GetName() != tinfo.GetClassName() ) { // if the tree is of another class
398 fWeightFormula.push_back( 0 );
399 continue;
400 }
401
402 ttf = 0;
403 if (tmpWeight!="") {
404 ttf = new TTreeFormula( "FormulaWeight", tmpWeight, tr );
405 Bool_t worked = CheckTTreeFormula( ttf, tmpWeight, hasDollar );
406 if( !worked ){
407 Log() << kWARNING << Form("Dataset[%s] : ",dsi.GetName()) << "Please check class \"" << dsi.GetClassInfo(clIdx)->GetName()
408 << "\" weight \"" << dsi.GetClassInfo(clIdx)->GetWeight() << Endl;
409 }
410 }
411 else {
412 ttf = 0;
413 }
414 fWeightFormula.push_back( ttf );
415 }
416 return;
417 // all this code below is not needed when using TTReeFormula
418
419 Log() << kDEBUG << Form("Dataset[%s] : ", dsi.GetName()) << "enable branches" << Endl;
420 // now enable only branches that are needed in any input formula, target, cut, weight
421
422 if (!hasDollar) {
423 tr->SetBranchStatus("*",0);
424 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "enable branches: input variables" << Endl;
425 // input vars
426 for (formIt = fInputFormulas.begin(); formIt!=fInputFormulas.end(); ++formIt) {
427 ttf = *formIt;
428 for (Int_t bi = 0; bi<ttf->GetNcodes(); bi++) {
429 tr->SetBranchStatus( ttf->GetLeaf(bi)->GetBranch()->GetName(), 1 );
430 }
431 }
432 // targets
433 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "enable branches: targets" << Endl;
434 for (formIt = fTargetFormulas.begin(); formIt!=fTargetFormulas.end(); ++formIt) {
435 ttf = *formIt;
436 for (Int_t bi = 0; bi<ttf->GetNcodes(); bi++)
437 tr->SetBranchStatus( ttf->GetLeaf(bi)->GetBranch()->GetName(), 1 );
438 }
439 // spectators
440 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "enable branches: spectators" << Endl;
441 for (formIt = fSpectatorFormulas.begin(); formIt!=fSpectatorFormulas.end(); ++formIt) {
442 ttf = *formIt;
443 for (Int_t bi = 0; bi<ttf->GetNcodes(); bi++)
444 tr->SetBranchStatus( ttf->GetLeaf(bi)->GetBranch()->GetName(), 1 );
445 }
446 // cuts
447 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "enable branches: cuts" << Endl;
448 for (formIt = fCutFormulas.begin(); formIt!=fCutFormulas.end(); ++formIt) {
449 ttf = *formIt;
450 if (!ttf) continue;
451 for (Int_t bi = 0; bi<ttf->GetNcodes(); bi++)
452 tr->SetBranchStatus( ttf->GetLeaf(bi)->GetBranch()->GetName(), 1 );
453 }
454 // weights
455 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName()) << "enable branches: weights" << Endl;
456 for (formIt = fWeightFormula.begin(); formIt!=fWeightFormula.end(); ++formIt) {
457 ttf = *formIt;
458 if (!ttf) continue;
459 for (Int_t bi = 0; bi<ttf->GetNcodes(); bi++)
460 tr->SetBranchStatus( ttf->GetLeaf(bi)->GetBranch()->GetName(), 1 );
461 }
462 }
463 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "tree initialized" << Endl;
464 return;
465}
466
467////////////////////////////////////////////////////////////////////////////////
468/// compute covariance matrix
469
471{
472 const UInt_t nvar = ds->GetNVariables();
473 const UInt_t ntgts = ds->GetNTargets();
474 const UInt_t nvis = ds->GetNSpectators();
475
476 Float_t *min = new Float_t[nvar];
477 Float_t *max = new Float_t[nvar];
478 Float_t *tgmin = new Float_t[ntgts];
479 Float_t *tgmax = new Float_t[ntgts];
480 Float_t *vmin = new Float_t[nvis];
481 Float_t *vmax = new Float_t[nvis];
482
483 for (UInt_t ivar=0; ivar<nvar ; ivar++) { min[ivar] = FLT_MAX; max[ivar] = -FLT_MAX; }
484 for (UInt_t ivar=0; ivar<ntgts; ivar++) { tgmin[ivar] = FLT_MAX; tgmax[ivar] = -FLT_MAX; }
485 for (UInt_t ivar=0; ivar<nvis; ivar++) { vmin[ivar] = FLT_MAX; vmax[ivar] = -FLT_MAX; }
486
487 // perform event loop
488
489 for (Int_t i=0; i<ds->GetNEvents(); i++) {
490 const Event * ev = ds->GetEvent(i);
491 for (UInt_t ivar=0; ivar<nvar; ivar++) {
492 Double_t v = ev->GetValue(ivar);
493 if (v<min[ivar]) min[ivar] = v;
494 if (v>max[ivar]) max[ivar] = v;
495 }
496 for (UInt_t itgt=0; itgt<ntgts; itgt++) {
497 Double_t v = ev->GetTarget(itgt);
498 if (v<tgmin[itgt]) tgmin[itgt] = v;
499 if (v>tgmax[itgt]) tgmax[itgt] = v;
500 }
501 for (UInt_t ivis=0; ivis<nvis; ivis++) {
502 Double_t v = ev->GetSpectator(ivis);
503 if (v<vmin[ivis]) vmin[ivis] = v;
504 if (v>vmax[ivis]) vmax[ivis] = v;
505 }
506 }
507
508 for (UInt_t ivar=0; ivar<nvar; ivar++) {
509 dsi.GetVariableInfo(ivar).SetMin(min[ivar]);
510 dsi.GetVariableInfo(ivar).SetMax(max[ivar]);
511 if( TMath::Abs(max[ivar]-min[ivar]) <= FLT_MIN )
512 Log() << kWARNING << Form("Dataset[%s] : ",dsi.GetName()) << "Variable " << dsi.GetVariableInfo(ivar).GetExpression().Data() << " is constant. Please remove the variable." << Endl;
513 }
514 for (UInt_t ivar=0; ivar<ntgts; ivar++) {
515 dsi.GetTargetInfo(ivar).SetMin(tgmin[ivar]);
516 dsi.GetTargetInfo(ivar).SetMax(tgmax[ivar]);
518 Log() << kFATAL << Form("Dataset[%s] : ",dsi.GetName()) << "Target " << dsi.GetTargetInfo(ivar).GetExpression().Data() << " is constant. Please remove the variable." << Endl;
519 }
520 for (UInt_t ivar=0; ivar<nvis; ivar++) {
521 dsi.GetSpectatorInfo(ivar).SetMin(vmin[ivar]);
522 dsi.GetSpectatorInfo(ivar).SetMax(vmax[ivar]);
523 // if( TMath::Abs(vmax[ivar]-vmin[ivar]) <= FLT_MIN )
524 // Log() << kWARNING << "Spectator variable " << dsi.GetSpectatorInfo(ivar).GetExpression().Data() << " is constant." << Endl;
525 }
526 delete [] min;
527 delete [] max;
528 delete [] tgmin;
529 delete [] tgmax;
530 delete [] vmin;
531 delete [] vmax;
532}
533
534////////////////////////////////////////////////////////////////////////////////
535/// computes correlation matrix for variables "theVars" in tree;
536/// "theType" defines the required event "type"
537/// ("type" variable must be present in tree)
538
540{
541 // first compute variance-covariance
542 TMatrixD* mat = CalcCovarianceMatrix( ds, classNumber );
543
544 // now the correlation
545 UInt_t nvar = ds->GetNVariables(), ivar, jvar;
546
547 for (ivar=0; ivar<nvar; ivar++) {
548 for (jvar=0; jvar<nvar; jvar++) {
549 if (ivar != jvar) {
550 Double_t d = (*mat)(ivar, ivar)*(*mat)(jvar, jvar);
551 if (d > 0) (*mat)(ivar, jvar) /= sqrt(d);
552 else {
553 Log() << kWARNING << Form("Dataset[%s] : ",DataSetInfo().GetName())<< "<GetCorrelationMatrix> Zero variances for variables "
554 << "(" << ivar << ", " << jvar << ") = " << d
555 << Endl;
556 (*mat)(ivar, jvar) = 0;
557 }
558 }
559 }
560 }
561
562 for (ivar=0; ivar<nvar; ivar++) (*mat)(ivar, ivar) = 1.0;
563
564 return mat;
565}
566
567////////////////////////////////////////////////////////////////////////////////
568/// compute covariance matrix
569
571{
572 UInt_t nvar = ds->GetNVariables();
573 UInt_t ivar = 0, jvar = 0;
574
575 TMatrixD* mat = new TMatrixD( nvar, nvar );
576
577 // init matrices
578 TVectorD vec(nvar);
579 TMatrixD mat2(nvar, nvar);
580 for (ivar=0; ivar<nvar; ivar++) {
581 vec(ivar) = 0;
582 for (jvar=0; jvar<nvar; jvar++) mat2(ivar, jvar) = 0;
583 }
584
585 // perform event loop
586 Double_t ic = 0;
587 for (Int_t i=0; i<ds->GetNEvents(); i++) {
588
589 const Event * ev = ds->GetEvent(i);
590 if (ev->GetClass() != classNumber ) continue;
591
592 Double_t weight = ev->GetWeight();
593 ic += weight; // count used events
594
595 for (ivar=0; ivar<nvar; ivar++) {
596
597 Double_t xi = ev->GetValue(ivar);
598 vec(ivar) += xi*weight;
599 mat2(ivar, ivar) += (xi*xi*weight);
600
601 for (jvar=ivar+1; jvar<nvar; jvar++) {
602 Double_t xj = ev->GetValue(jvar);
603 mat2(ivar, jvar) += (xi*xj*weight);
604 }
605 }
606 }
607
608 for (ivar=0; ivar<nvar; ivar++)
609 for (jvar=ivar+1; jvar<nvar; jvar++)
610 mat2(jvar, ivar) = mat2(ivar, jvar); // symmetric matrix
611
612
613 // variance-covariance
614 for (ivar=0; ivar<nvar; ivar++) {
615 for (jvar=0; jvar<nvar; jvar++) {
616 (*mat)(ivar, jvar) = mat2(ivar, jvar)/ic - vec(ivar)*vec(jvar)/(ic*ic);
617 }
618 }
619
620 return mat;
621}
622
623// --------------------------------------- new versions
624
625////////////////////////////////////////////////////////////////////////////////
626/// the dataset splitting
627
628void
635{
636 Configurable splitSpecs( dsi.GetSplitOptions() );
637 splitSpecs.SetConfigName("DataSetFactory");
638 splitSpecs.SetConfigDescription( "Configuration options given in the \"PrepareForTrainingAndTesting\" call; these options define the creation of the data sets used for training and expert validation by TMVA" );
639
640 splitMode = "Random"; // the splitting mode
641 splitSpecs.DeclareOptionRef( splitMode, "SplitMode",
642 "Method of picking training and testing events (default: random)" );
643 splitSpecs.AddPreDefVal(TString("Random"));
644 splitSpecs.AddPreDefVal(TString("Alternate"));
645 splitSpecs.AddPreDefVal(TString("Block"));
646
647 mixMode = "SameAsSplitMode"; // the splitting mode
648 splitSpecs.DeclareOptionRef( mixMode, "MixMode",
649 "Method of mixing events of different classes into one dataset (default: SameAsSplitMode)" );
650 splitSpecs.AddPreDefVal(TString("SameAsSplitMode"));
651 splitSpecs.AddPreDefVal(TString("Random"));
652 splitSpecs.AddPreDefVal(TString("Alternate"));
653 splitSpecs.AddPreDefVal(TString("Block"));
654
655 splitSeed = 100;
656 splitSpecs.DeclareOptionRef( splitSeed, "SplitSeed",
657 "Seed for random event shuffling" );
658
659 normMode = "EqualNumEvents"; // the weight normalisation modes
660 splitSpecs.DeclareOptionRef( normMode, "NormMode",
661 "Overall renormalisation of event-by-event weights used in the training (NumEvents: average weight of 1 per event, independently for signal and background; EqualNumEvents: average weight of 1 per event for signal, and sum of weights for background equal to sum of weights for signal)" );
662 splitSpecs.AddPreDefVal(TString("None"));
663 splitSpecs.AddPreDefVal(TString("NumEvents"));
664 splitSpecs.AddPreDefVal(TString("EqualNumEvents"));
665
666 splitSpecs.DeclareOptionRef(fScaleWithPreselEff=kFALSE,"ScaleWithPreselEff","Scale the number of requested events by the eff. of the preselection cuts (or not)" );
667
668 // the number of events
669
670 // fill in the numbers
671 for (UInt_t cl = 0; cl < dsi.GetNClasses(); cl++) {
672 TString clName = dsi.GetClassInfo(cl)->GetName();
673 TString titleTrain = TString().Format("Number of training events of class %s (default: 0 = all)",clName.Data()).Data();
674 TString titleTest = TString().Format("Number of test events of class %s (default: 0 = all)",clName.Data()).Data();
675 TString titleSplit = TString().Format("Split in training and test events of class %s (default: 0 = deactivated)",clName.Data()).Data();
676
677 splitSpecs.DeclareOptionRef( nEventRequests.at(cl).nTrainingEventsRequested, TString("nTrain_")+clName, titleTrain );
678 splitSpecs.DeclareOptionRef( nEventRequests.at(cl).nTestingEventsRequested , TString("nTest_")+clName , titleTest );
679 splitSpecs.DeclareOptionRef( nEventRequests.at(cl).TrainTestSplitRequested , TString("TrainTestSplit_")+clName , titleTest );
680 }
681
682 splitSpecs.DeclareOptionRef( fVerbose, "V", "Verbosity (default: true)" );
683
684 splitSpecs.DeclareOptionRef( fVerboseLevel=TString("Info"), "VerboseLevel", "VerboseLevel (Debug/Verbose/Info)" );
685 splitSpecs.AddPreDefVal(TString("Debug"));
686 splitSpecs.AddPreDefVal(TString("Verbose"));
687 splitSpecs.AddPreDefVal(TString("Info"));
688
689 fCorrelations = kTRUE;
690 splitSpecs.DeclareOptionRef(fCorrelations, "Correlations", "Boolean to show correlation output (Default: true)");
691 fComputeCorrelations = kTRUE;
692 splitSpecs.DeclareOptionRef(fComputeCorrelations, "CalcCorrelations", "Compute correlations and also some variable statistics, e.g. min/max (Default: true )");
693
694 splitSpecs.ParseOptions();
695 splitSpecs.CheckForUnusedOptions();
696
697 // output logging verbosity
698 if (Verbose()) fLogger->SetMinType( kVERBOSE );
699 if (fVerboseLevel.CompareTo("Debug") ==0) fLogger->SetMinType( kDEBUG );
700 if (fVerboseLevel.CompareTo("Verbose") ==0) fLogger->SetMinType( kVERBOSE );
701 if (fVerboseLevel.CompareTo("Info") ==0) fLogger->SetMinType( kINFO );
702
703 // put all to upper case
704 splitMode.ToUpper(); mixMode.ToUpper(); normMode.ToUpper();
705 // adjust mixmode if same as splitmode option has been set
706 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
707 << "\tSplitmode is: \"" << splitMode << "\" the mixmode is: \"" << mixMode << "\"" << Endl;
708 if (mixMode=="SAMEASSPLITMODE") mixMode = splitMode;
709 else if (mixMode!=splitMode)
710 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "DataSet splitmode="<<splitMode
711 <<" differs from mixmode="<<mixMode<<Endl;
712}
713
714////////////////////////////////////////////////////////////////////////////////
715/// build empty event vectors
716/// distributes events between kTraining/kTesting/kMaxTreeType
717
718void
723{
724 const UInt_t nclasses = dsi.GetNClasses();
725
729
730 // create the type, weight and boostweight branches
731 const UInt_t nvars = dsi.GetNVariables();
732 const UInt_t ntgts = dsi.GetNTargets();
733 const UInt_t nvis = dsi.GetNSpectators();
734
735 for (size_t i=0; i<nclasses; i++) {
736 eventCounts[i].varAvLength = new Float_t[nvars];
737 for (UInt_t ivar=0; ivar<nvars; ivar++)
738 eventCounts[i].varAvLength[ivar] = 0;
739 }
740
741 //Bool_t haveArrayVariable = kFALSE;
742 //Bool_t *varIsArray = new Bool_t[nvars];
743
744 // If there are NaNs in the tree:
745 // => warn if used variables/cuts/weights contain nan (no problem if event is cut out)
746 // => fatal if cut value is nan or (event not cut out and nans somewhere)
747 // Count & collect all these warnings/errors and output them at the end.
748 std::map<TString, int> nanInfWarnings;
749 std::map<TString, int> nanInfErrors;
750
751 // if we work with chains we need to remember the current tree if
752 // the chain jumps to a new tree we have to reset the formulas
753 for (UInt_t cl=0; cl<nclasses; cl++) {
754
755 //Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "Create training and testing trees -- looping over class \"" << dsi.GetClassInfo(cl)->GetName() << "\" ..." << Endl;
756
758
759 // info output for weights
760 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
761 << "\tWeight expression for class \'" << dsi.GetClassInfo(cl)->GetName() << "\': \""
762 << dsi.GetClassInfo(cl)->GetWeight() << "\"" << Endl;
763
764 // used for chains only
766
767 std::vector<TreeInfo>::const_iterator treeIt(dataInput.begin(dsi.GetClassInfo(cl)->GetName()));
768 for (;treeIt!=dataInput.end(dsi.GetClassInfo(cl)->GetName()); ++treeIt) {
769
770 // read first the variables
771 std::vector<Float_t> vars(nvars);
772 std::vector<Float_t> tgts(ntgts);
773 std::vector<Float_t> vis(nvis);
775
776 Log() << kINFO << "Building event vectors for type " << currentInfo.GetTreeType() << " " << currentInfo.GetClassName() << Endl;
777
778 EventVector& event_v = eventsmap[currentInfo.GetTreeType()].at(cl);
779
780 Bool_t isChain = (TString("TChain") == currentInfo.GetTree()->ClassName());
781 currentInfo.GetTree()->LoadTree(0);
782 // create the TTReeFormula to evalute later on on each single event
783 ChangeToNewTree( currentInfo, dsi );
784
785 // count number of events in tree before cut
786 classEventCounts.nInitialEvents += currentInfo.GetTree()->GetEntries();
787
788 // flag to control a warning message when size of array in disk are bigger than what requested
790
791 // loop over events in ntuple
792 const UInt_t nEvts = currentInfo.GetTree()->GetEntries();
793 for (Long64_t evtIdx = 0; evtIdx < nEvts; evtIdx++) {
794 currentInfo.GetTree()->LoadTree(evtIdx);
795
796 // may need to reload tree in case of chains
797 if (isChain) {
798 if (currentInfo.GetTree()->GetTree()->GetDirectory()->GetFile()->GetName() != currentFileName) {
799 currentFileName = currentInfo.GetTree()->GetTree()->GetDirectory()->GetFile()->GetName();
800 ChangeToNewTree( currentInfo, dsi );
801 }
802 }
803 currentInfo.GetTree()->GetEntry(evtIdx);
805 Int_t prevArrExpr = 0;
807
808 // ======= evaluate all formulas =================
809
810 // first we check if some of the formulas are arrays
811 // This is the case when all inputs (variables, targets and spectetors are array and a TMVA event is not
812 // an event of the tree but an event + array index). In this case we set the flag haveAllArrayData = true
813 // Otherwise we support for arrays of variables where each
814 // element of the array corresponds to a different variable like in the case of image
815 // In that case the VAriableInfo has a bit, IsVariableFromArray that is set and we have a single formula for the array
816 // fInputFormulaTable contains a map of the formula and the variable index to evaluate the formula
817 for (UInt_t ivar = 0; ivar < nvars; ivar++) {
818 // distinguish case where variable is not from an array
819 if (dsi.IsVariableFromArray(ivar)) continue;
820 auto inputFormula = fInputTableFormulas[ivar].first;
821
822 Int_t ndata = inputFormula->GetNdata();
823
824 classEventCounts.varAvLength[ivar] += ndata;
825 if (ndata == 1) continue;
827 //varIsArray[ivar] = kTRUE;
828 //std::cout << "Found array !!!" << std::endl;
829 if (sizeOfArrays == 1) {
832 }
833 else if (sizeOfArrays!=ndata) {
834 Log() << kERROR << Form("Dataset[%s] : ",dsi.GetName())<< "ERROR while preparing training and testing trees:" << Endl;
835 Log() << Form("Dataset[%s] : ",dsi.GetName())<< " multiple array-type expressions of different length were encountered" << Endl;
836 Log() << Form("Dataset[%s] : ",dsi.GetName())<< " location of error: event " << evtIdx
837 << " in tree " << currentInfo.GetTree()->GetName()
838 << " of file " << currentInfo.GetTree()->GetCurrentFile()->GetName() << Endl;
839 Log() << Form("Dataset[%s] : ",dsi.GetName())<< " expression " << inputFormula->GetTitle() << " has "
840 << Form("Dataset[%s] : ",dsi.GetName()) << ndata << " entries, while" << Endl;
841 Log() << Form("Dataset[%s] : ",dsi.GetName())<< " expression " << fInputTableFormulas[prevArrExpr].first->GetTitle() << " has "
842 << Form("Dataset[%s] : ",dsi.GetName())<< fInputTableFormulas[prevArrExpr].first->GetNdata() << " entries" << Endl;
843 Log() << kFATAL << Form("Dataset[%s] : ",dsi.GetName())<< "Need to abort" << Endl;
844 }
845 }
846
847 // now we read the information
848 for (Int_t idata = 0; idata<sizeOfArrays; idata++) {
850
851 auto checkNanInf = [&](std::map<TString, int> &msgMap, Float_t value, const char *what, const char *formulaTitle) {
852 if (TMath::IsNaN(value)) {
854 ++msgMap[TString::Format("Dataset[%s] : %s expression resolves to indeterminate value (NaN): %s", dsi.GetName(), what, formulaTitle)];
855 } else if (!TMath::Finite(value)) {
857 ++msgMap[TString::Format("Dataset[%s] : %s expression resolves to infinite value (+inf or -inf): %s", dsi.GetName(), what, formulaTitle)];
858 }
859 };
860
861 TTreeFormula* formula = 0;
862
863 // the cut expression
864 Double_t cutVal = 1.;
865 formula = fCutFormulas[cl];
866 if (formula) {
867 Int_t ndata = formula->GetNdata();
868 cutVal = (ndata==1 ?
869 formula->EvalInstance(0) :
870 formula->EvalInstance(idata));
871 checkNanInf(nanInfErrors, cutVal, "Cut", formula->GetTitle());
872 }
873
874 // if event is cut out, add to warnings, else add to errors.
876
877 // the input variable
878 for (UInt_t ivar=0; ivar<nvars; ivar++) {
879 auto formulaMap = fInputTableFormulas[ivar];
880 formula = formulaMap.first;
881 int inputVarIndex = formulaMap.second;
882 // check fomula ndata size (in case of arrays variable)
883 // enough to check for ivarindex = 0 then formula is the same
884 // this check might take some time. Maybe do only in debug mode
885 if (inputVarIndex == 0 && dsi.IsVariableFromArray(ivar)) {
886 Int_t ndata = formula->GetNdata();
887 Int_t arraySize = dsi.GetVarArraySize(dsi.GetVariableInfo(ivar).GetExpression());
888 if (ndata < arraySize) {
889 Log() << kFATAL << "Size of array " << dsi.GetVariableInfo(ivar).GetExpression()
890 << " in the current tree " << currentInfo.GetTree()->GetName() << " for the event " << evtIdx
891 << " is " << ndata << " instead of " << arraySize << Endl;
892 } else if (ndata > arraySize && !foundLargerArraySize) {
893 Log() << kWARNING << "Size of array " << dsi.GetVariableInfo(ivar).GetExpression()
894 << " in the current tree " << currentInfo.GetTree()->GetName() << " for the event "
895 << evtIdx << " is " << ndata << ", larger than " << arraySize << Endl;
896 Log() << kWARNING << "Some data will then be ignored. This WARNING is printed only once, "
897 << " check in case for the other variables and events " << Endl;
898 // note that following warnings will be suppressed
900 }
901 }
902 formula->SetQuickLoad(true); // is this needed ???
903
904 vars[ivar] = ( !haveAllArrayData ?
905 formula->EvalInstance(inputVarIndex) :
906 formula->EvalInstance(idata));
907 checkNanInf(nanMessages, vars[ivar], "Input", formula->GetTitle());
908 }
909
910 // the targets
911 for (UInt_t itrgt=0; itrgt<ntgts; itrgt++) {
912 formula = fTargetFormulas[itrgt];
913 Int_t ndata = formula->GetNdata();
914 tgts[itrgt] = (ndata == 1 ?
915 formula->EvalInstance(0) :
916 formula->EvalInstance(idata));
917 checkNanInf(nanMessages, tgts[itrgt], "Target", formula->GetTitle());
918 }
919
920 // the spectators
921 for (UInt_t itVis=0; itVis<nvis; itVis++) {
922 formula = fSpectatorFormulas[itVis];
923 Int_t ndata = formula->GetNdata();
924 vis[itVis] = (ndata == 1 ?
925 formula->EvalInstance(0) :
926 formula->EvalInstance(idata));
927 checkNanInf(nanMessages, vis[itVis], "Spectator", formula->GetTitle());
928 }
929
930
931 // the weight
932 Float_t weight = currentInfo.GetWeight(); // multiply by tree weight
933 formula = fWeightFormula[cl];
934 if (formula!=0) {
935 Int_t ndata = formula->GetNdata();
936 weight *= (ndata == 1 ?
937 formula->EvalInstance() :
938 formula->EvalInstance(idata));
939 checkNanInf(nanMessages, weight, "Weight", formula->GetTitle());
940 }
941
942 // Count the events before rejection due to cut or NaN
943 // value (weighted and unweighted)
944 classEventCounts.nEvBeforeCut++;
945 if (!TMath::IsNaN(weight))
946 classEventCounts.nWeEvBeforeCut += weight;
947
948 // apply the cut, skip rest if cut is not fulfilled
949 if (cutVal<0.5) continue;
950
951 // global flag if negative weights exist -> can be used
952 // by classifiers who may require special data
953 // treatment (also print warning)
954 if (weight < 0) classEventCounts.nNegWeights++;
955
956 // now read the event-values (variables and regression targets)
957
959 Log() << kWARNING << Form("Dataset[%s] : ",dsi.GetName())<< "NaN or +-inf in Event " << evtIdx << Endl;
960 if (sizeOfArrays>1) Log() << kWARNING << Form("Dataset[%s] : ",dsi.GetName())<< " rejected" << Endl;
961 continue;
962 }
963
964 // Count the events after rejection due to cut or NaN value
965 // (weighted and unweighted)
966 classEventCounts.nEvAfterCut++;
967 classEventCounts.nWeEvAfterCut += weight;
968
969 // event accepted, fill temporary ntuple
970 event_v.push_back(new Event(vars, tgts , vis, cl , weight));
971 }
972 }
973 currentInfo.GetTree()->ResetBranchAddresses();
974 }
975 }
976
977 if (!nanInfWarnings.empty()) {
978 Log() << kWARNING << "Found events with NaN and/or +-inf values" << Endl;
979 for (const auto &warning : nanInfWarnings) {
980 auto &log = Log() << kWARNING << warning.first;
981 if (warning.second > 1) log << " (" << warning.second << " times)";
982 log << Endl;
983 }
984 Log() << kWARNING << "These NaN and/or +-infs were all removed by the specified cut, continuing." << Endl;
985 Log() << Endl;
986 }
987
988 if (!nanInfErrors.empty()) {
989 Log() << kWARNING << "Found events with NaN and/or +-inf values (not removed by cut)" << Endl;
990 for (const auto &error : nanInfErrors) {
991 auto &log = Log() << kWARNING << error.first;
992 if (error.second > 1) log << " (" << error.second << " times)";
993 log << Endl;
994 }
995 Log() << kFATAL << "How am I supposed to train a NaN or +-inf?!" << Endl;
996 }
997
998 // for output format, get the maximum class name length
999 Int_t maxL = dsi.GetClassNameMaxLength();
1000
1001 Log() << kHEADER << Form("[%s] : ",dsi.GetName()) << "Number of events in input trees" << Endl;
1002 Log() << kDEBUG << "(after possible flattening of arrays):" << Endl;
1003
1004
1005 for (UInt_t cl = 0; cl < dsi.GetNClasses(); cl++) {
1006 Log() << kDEBUG //<< Form("[%s] : ",dsi.GetName())
1007 << " "
1008 << setiosflags(ios::left) << std::setw(maxL) << dsi.GetClassInfo(cl)->GetName()
1009 << " -- number of events : "
1010 << std::setw(5) << eventCounts[cl].nEvBeforeCut
1011 << " / sum of weights: " << std::setw(5) << eventCounts[cl].nWeEvBeforeCut << Endl;
1012 }
1013
1014 for (UInt_t cl = 0; cl < dsi.GetNClasses(); cl++) {
1015 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1016 << " " << std::setw(maxL) << dsi.GetClassInfo(cl)->GetName()
1017 <<" tree -- total number of entries: "
1018 << std::setw(5) << dataInput.GetEntries(dsi.GetClassInfo(cl)->GetName()) << Endl;
1019 }
1020
1021 if (fScaleWithPreselEff)
1022 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1023 << "\tPreselection: (will affect number of requested training and testing events)" << Endl;
1024 else
1025 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1026 << "\tPreselection: (will NOT affect number of requested training and testing events)" << Endl;
1027
1028 if (dsi.HasCuts()) {
1029 for (UInt_t cl = 0; cl< dsi.GetNClasses(); cl++) {
1030 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " " << setiosflags(ios::left) << std::setw(maxL) << dsi.GetClassInfo(cl)->GetName()
1031 << " requirement: \"" << dsi.GetClassInfo(cl)->GetCut() << "\"" << Endl;
1032 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " "
1033 << setiosflags(ios::left) << std::setw(maxL) << dsi.GetClassInfo(cl)->GetName()
1034 << " -- number of events passed: "
1035 << std::setw(5) << eventCounts[cl].nEvAfterCut
1036 << " / sum of weights: " << std::setw(5) << eventCounts[cl].nWeEvAfterCut << Endl;
1037 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " "
1038 << setiosflags(ios::left) << std::setw(maxL) << dsi.GetClassInfo(cl)->GetName()
1039 << " -- efficiency : "
1040 << std::setw(6) << eventCounts[cl].nWeEvAfterCut/eventCounts[cl].nWeEvBeforeCut << Endl;
1041 }
1042 }
1043 else Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1044 << " No preselection cuts applied on event classes" << Endl;
1045
1046 //delete[] varIsArray;
1047
1048}
1049
1050////////////////////////////////////////////////////////////////////////////////
1051/// Select and distribute unassigned events to kTraining and kTesting
1052
1057 const TString& splitMode,
1058 const TString& mixMode,
1059 const TString& normMode,
1061{
1063
1064 // ==== splitting of undefined events to kTraining and kTesting
1065
1066 // if splitMode contains "RANDOM", then shuffle the undefined events
1067 if (splitMode.Contains( "RANDOM" ) /*&& !emptyUndefined*/ ) {
1068 // random shuffle the undefined events of each class
1069 for( UInt_t cls = 0; cls < dsi.GetNClasses(); ++cls ){
1071 if( ! unspecifiedEvents.empty() ) {
1072 Log() << kDEBUG << "randomly shuffling "
1073 << unspecifiedEvents.size()
1074 << " events of class " << cls
1075 << " which are not yet associated to testing or training" << Endl;
1076 std::shuffle(unspecifiedEvents.begin(), unspecifiedEvents.end(), rndm);
1077 }
1078 }
1079 }
1080
1081 // check for each class the number of training and testing events, the requested number and the available number
1082 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "SPLITTING ========" << Endl;
1083 for( UInt_t cls = 0; cls < dsi.GetNClasses(); ++cls ){
1084 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "---- class " << cls << Endl;
1085 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "check number of training/testing events, requested and available number of events and for class " << cls << Endl;
1086
1087 // check if enough or too many events are already in the training/testing eventvectors of the class cls
1091
1095
1097 if (fScaleWithPreselEff) {
1098 presel_scale = eventCounts[cls].cutScaling();
1099 if (presel_scale < 1)
1100 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " you have opted for scaling the number of requested training/testing events\n to be scaled by the preselection efficiency"<< Endl;
1101 }else{
1102 presel_scale = 1.; // this scaling was too confusing to most people, including me! Sorry... (Helge)
1103 if (eventCounts[cls].cutScaling() < 1)
1104 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " you have opted for interpreting the requested number of training/testing events\n to be the number of events AFTER your preselection cuts" << Endl;
1105
1106 }
1107
1108 // If TrainTestSplit_<class> is set, set number of requested training events to split*num_all_events
1109 // Requested number of testing events is set to zero and therefore takes all other events
1110 // The option TrainTestSplit_<class> overrides nTrain_<class> or nTest_<class>
1111 if(eventCounts[cls].TrainTestSplitRequested < 1.0 && eventCounts[cls].TrainTestSplitRequested > 0.0){
1112 eventCounts[cls].nTrainingEventsRequested = Int_t(eventCounts[cls].TrainTestSplitRequested*(availableTraining+availableTesting+availableUndefined));
1113 eventCounts[cls].nTestingEventsRequested = Int_t(0);
1114 }
1115 else if(eventCounts[cls].TrainTestSplitRequested != 0.0) Log() << kFATAL << Form("The option TrainTestSplit_<class> has to be in range (0, 1] but is set to %f.",eventCounts[cls].TrainTestSplitRequested) << Endl;
1116 Int_t requestedTraining = Int_t(eventCounts[cls].nTrainingEventsRequested * presel_scale);
1117 Int_t requestedTesting = Int_t(eventCounts[cls].nTestingEventsRequested * presel_scale);
1118
1119 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "events in training trees : " << availableTraining << Endl;
1120 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "events in testing trees : " << availableTesting << Endl;
1121 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "events in unspecified trees : " << availableUndefined << Endl;
1122 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "requested for training : " << requestedTraining << Endl;
1123
1124 if(presel_scale<1)
1125 Log() << " ( " << eventCounts[cls].nTrainingEventsRequested
1126 << " * " << presel_scale << " preselection efficiency)" << Endl;
1127 else
1128 Log() << Endl;
1129 Log() << kDEBUG << "requested for testing : " << requestedTesting;
1130 if(presel_scale<1)
1131 Log() << " ( " << eventCounts[cls].nTestingEventsRequested
1132 << " * " << presel_scale << " preselection efficiency)" << Endl;
1133 else
1134 Log() << Endl;
1135
1136 // nomenclature r = available training
1137 // s = available testing
1138 // u = available undefined
1139 // R = requested training
1140 // S = requested testing
1141 // nR = to be used to select training events
1142 // nS = to be used to select test events
1143 // we have the constraint: nR + nS < r+s+u,
1144 // since we can not use more events than we have
1145 // free events: Nfree = u-Thet(R-r)-Thet(S-s)
1146 // nomenclature: Thet(x) = x, if x>0 else 0
1147 // nR = max(R,r) + 0.5 * Nfree
1148 // nS = max(S,s) + 0.5 * Nfree
1149 // nR +nS = R+S + u-R+r-S+s = u+r+s= ok! for R>r
1150 // nR +nS = r+S + u-S+s = u+r+s= ok! for r>R
1151
1152 // three different cases might occur here
1153 //
1154 // Case a
1155 // requestedTraining and requestedTesting >0
1156 // free events: Nfree = u-Thet(R-r)-Thet(S-s)
1157 // nR = Max(R,r) + 0.5 * Nfree
1158 // nS = Max(S,s) + 0.5 * Nfree
1159 //
1160 // Case b
1161 // exactly one of requestedTraining or requestedTesting >0
1162 // assume training R >0
1163 // nR = max(R,r)
1164 // nS = s+u+r-nR
1165 // and s=nS
1166 //
1167 // Case c
1168 // requestedTraining=0, requestedTesting=0
1169 // Nfree = u-|r-s|
1170 // if NFree >=0
1171 // R = Max(r,s) + 0.5 * Nfree = S
1172 // else if r>s
1173 // R = r; S=s+u
1174 // else
1175 // R = r+u; S=s
1176 //
1177 // Next steps:
1178 // Determination of Event numbers R,S, nR, nS
1179 // distribute undefined events according to nR, nS
1180 // finally determine actual sub samples from nR and nS to be used in training / testing
1181 //
1182
1185
1186 if( (requestedTraining == 0) && (requestedTesting == 0)){
1187
1188 // Case C: balance the number of training and testing events
1189
1191 // enough unspecified are available to equal training and testing
1193 } else {
1194 // all unspecified are assigned to the smaller of training / testing
1199 else
1201 }
1204 }
1205
1206 else if (requestedTesting == 0){
1207 // case B
1210 Log() << kFATAL << Form("Dataset[%s] : ",dsi.GetName())<< "More events requested for training ("
1211 << requestedTraining << ") than available ("
1212 << allAvailable << ")!" << Endl;
1213 }
1216 }
1217
1218 else if (requestedTraining == 0){ // case B)
1221 Log() << kFATAL << Form("Dataset[%s] : ",dsi.GetName())<< "More events requested for testing ("
1222 << requestedTesting << ") than available ("
1223 << allAvailable << ")!" << Endl;
1224 }
1227 }
1228
1229 else {
1230 // Case A
1231 // requestedTraining R and requestedTesting S >0
1232 // free events: Nfree = u-Thet(R-r)-Thet(S-s)
1233 // nR = Max(R,r) + 0.5 * Nfree
1234 // nS = Max(S,s) + 0.5 * Nfree
1237
1239 if (NFree <0) NFree = 0;
1242 }
1243
1244 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "determined event sample size to select training sample from="<<useForTraining<<Endl;
1245 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "determined event sample size to select test sample from="<<useForTesting<<Endl;
1246
1247
1248
1249 // associate undefined events
1250 if( splitMode == "ALTERNATE" ){
1251 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "split 'ALTERNATE'" << Endl;
1253 for( EventVector::iterator it = eventVectorUndefined.begin(), itEnd = eventVectorUndefined.end(); it != itEnd; ){
1254 ++nTraining;
1256 eventVectorTraining.insert( eventVectorTraining.end(), (*it) );
1257 ++it;
1258 }
1259 if( it != itEnd ){
1260 eventVectorTesting.insert( eventVectorTesting.end(), (*it) );
1261 ++it;
1262 }
1263 }
1264 } else {
1265 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "split '" << splitMode << "'" << Endl;
1266
1267 // test if enough events are available
1268 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "availableundefined : " << availableUndefined << Endl;
1269 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "useForTraining : " << useForTraining << Endl;
1270 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "useForTesting : " << useForTesting << Endl;
1271 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "availableTraining : " << availableTraining << Endl;
1272 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "availableTesting : " << availableTesting << Endl;
1273
1277 Log() << kFATAL << Form("Dataset[%s] : ",dsi.GetName())<< "More events requested than available!" << Endl;
1278 }
1279
1280 // select the events
1284 }
1287 }
1288 }
1289 eventVectorUndefined.clear();
1290
1291 // finally shorten the event vectors to the requested size by removing random events
1292 if (splitMode.Contains( "RANDOM" )){
1295 std::vector<UInt_t> indicesTraining( sizeTraining );
1296 // make indices
1298 // shuffle indices
1299 std::shuffle(indicesTraining.begin(), indicesTraining.end(), rndm);
1300 // erase indices of not needed events
1302 // delete all events with the given indices
1303 for( std::vector<UInt_t>::iterator it = indicesTraining.begin(), itEnd = indicesTraining.end(); it != itEnd; ++it ){
1304 delete eventVectorTraining.at( (*it) ); // delete event
1305 eventVectorTraining.at( (*it) ) = NULL; // set pointer to NULL
1306 }
1307 // now remove and erase all events with pointer==NULL
1309 }
1310
1313 std::vector<UInt_t> indicesTesting( sizeTesting );
1314 // make indices
1316 // shuffle indices
1317 std::shuffle(indicesTesting.begin(), indicesTesting.end(), rndm);
1318 // erase indices of not needed events
1320 // delete all events with the given indices
1321 for( std::vector<UInt_t>::iterator it = indicesTesting.begin(), itEnd = indicesTesting.end(); it != itEnd; ++it ){
1322 delete eventVectorTesting.at( (*it) ); // delete event
1323 eventVectorTesting.at( (*it) ) = NULL; // set pointer to NULL
1324 }
1325 // now remove and erase all events with pointer==NULL
1327 }
1328 }
1329 else { // erase at end if size larger than requested
1331 Log() << kWARNING << Form("Dataset[%s] : ",dsi.GetName())<< "DataSetFactory/requested number of training samples larger than size of eventVectorTraining.\n"
1332 << "There is probably an issue. Please contact the TMVA developers." << Endl;
1333 else if (eventVectorTraining.size() > UInt_t(requestedTraining)) {
1336 }
1338 Log() << kWARNING << Form("Dataset[%s] : ",dsi.GetName())<< "DataSetFactory/requested number of testing samples larger than size of eventVectorTesting.\n"
1339 << "There is probably an issue. Please contact the TMVA developers." << Endl;
1340 else if ( eventVectorTesting.size() > UInt_t(requestedTesting) ) {
1343 }
1344 }
1345 }
1346
1348
1349 Int_t trainingSize = 0;
1350 Int_t testingSize = 0;
1351
1352 // sum up number of training and testing events
1353 for( UInt_t cls = 0; cls < dsi.GetNClasses(); ++cls ){
1356 }
1357
1358 // --- collect all training (testing) events into the training (testing) eventvector
1359
1360 // create event vectors reserve enough space
1363
1365 testingEventVector->reserve( testingSize );
1366
1367
1368 // collect the events
1369
1370 // mixing of kTraining and kTesting data sets
1371 Log() << kDEBUG << " MIXING ============= " << Endl;
1372
1373 if( mixMode == "ALTERNATE" ){
1374 // Inform user if he tries to use alternate mixmode for
1375 // event classes with different number of events, this works but the alternation stops at the last event of the smaller class
1376 for( UInt_t cls = 1; cls < dsi.GetNClasses(); ++cls ){
1378 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "Training sample: You are trying to mix events in alternate mode although the classes have different event numbers. This works but the alternation stops at the last event of the smaller class."<<Endl;
1379 }
1381 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "Testing sample: You are trying to mix events in alternate mode although the classes have different event numbers. This works but the alternation stops at the last event of the smaller class."<<Endl;
1382 }
1383 }
1384 typedef EventVector::iterator EvtVecIt;
1386
1387 // insert first class
1388 Log() << kDEBUG << "insert class 0 into training and test vector" << Endl;
1391
1392 // insert other classes
1394 for( UInt_t cls = 1; cls < dsi.GetNClasses(); ++cls ){
1395 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "insert class " << cls << Endl;
1396 // training vector
1397 itTarget = trainingEventVector->begin() - 1; // start one before begin
1398 // loop over source
1400 // if( std::distance( itTarget, trainingEventVector->end()) < Int_t(cls+1) ) {
1401 if( (trainingEventVector->end() - itTarget) < Int_t(cls+1) ) {
1403 trainingEventVector->insert( itTarget, itEvent, itEventEnd ); // fill in the rest without mixing
1404 break;
1405 }else{
1406 itTarget += cls+1;
1407 trainingEventVector->insert( itTarget, (*itEvent) ); // fill event
1408 }
1409 }
1410 // testing vector
1412 // loop over source
1414 // if( std::distance( itTarget, testingEventVector->end()) < Int_t(cls+1) ) {
1415 if( ( testingEventVector->end() - itTarget ) < Int_t(cls+1) ) {
1417 testingEventVector->insert( itTarget, itEvent, itEventEnd ); // fill in the rest without mixing
1418 break;
1419 }else{
1420 itTarget += cls+1;
1421 testingEventVector->insert( itTarget, (*itEvent) ); // fill event
1422 }
1423 }
1424 }
1425 }else{
1426 for( UInt_t cls = 0; cls < dsi.GetNClasses(); ++cls ){
1429 }
1430 }
1431 // delete the tmpEventVector (but not the events therein)
1434
1436
1437 if (mixMode == "RANDOM") {
1438 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "shuffling events"<<Endl;
1439
1441 std::shuffle(testingEventVector->begin(), testingEventVector->end(), rndm);
1442 }
1443
1444 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "trainingEventVector " << trainingEventVector->size() << Endl;
1445 Log() << kDEBUG << Form("Dataset[%s] : ",dsi.GetName())<< "testingEventVector " << testingEventVector->size() << Endl;
1446
1447 // create dataset
1448 DataSet* ds = new DataSet(dsi);
1449
1450 // Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "Create internal training tree" << Endl;
1451 ds->SetEventCollection(trainingEventVector, Types::kTraining );
1452 // Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "Create internal testing tree" << Endl;
1453 ds->SetEventCollection(testingEventVector, Types::kTesting );
1454
1455
1456 if (ds->GetNTrainingEvents() < 1){
1457 Log() << kFATAL << "Dataset " << std::string(dsi.GetName()) << " does not have any training events, I better stop here and let you fix that one first " << Endl;
1458 }
1459
1460 if (ds->GetNTestEvents() < 1) {
1461 Log() << kERROR << "Dataset " << std::string(dsi.GetName()) << " does not have any testing events, guess that will cause problems later..but for now, I continue " << Endl;
1462 }
1463
1464 delete trainingEventVector;
1465 delete testingEventVector;
1466 return ds;
1467
1468}
1469
1470////////////////////////////////////////////////////////////////////////////////
1471/// renormalisation of the TRAINING event weights
1472/// - none (kind of obvious) .. use the weights as supplied by the
1473/// user.. (we store however the relative weight for later use)
1474/// - numEvents
1475/// - equalNumEvents reweight the training events such that the sum of all
1476/// backgr. (class > 0) weights equal that of the signal (class 0)
1477
1478void
1482 const TString& normMode )
1483{
1484
1485
1486 // print rescaling info
1487 // ---------------------------------
1488 // compute sums of weights
1491
1492 NumberPerClass trainingSizePerClass( dsi.GetNClasses() );
1493 NumberPerClass testingSizePerClass( dsi.GetNClasses() );
1494
1496 Double_t trainingSumBackgrWeights = 0; // Backgr. includes all classes that are not signal
1498 Double_t testingSumBackgrWeights = 0; // Backgr. includes all classes that are not signal
1499
1500
1501
1502 for( UInt_t cls = 0, clsEnd = dsi.GetNClasses(); cls < clsEnd; ++cls ){
1505
1506 // the functional solution
1507 // sum up the weights in Double_t although the individual weights are Float_t to prevent rounding issues in addition of floating points
1508 //
1509 // accumulate --> does what the name says
1510 // begin() and end() denote the range of the vector to be accumulated
1511 // Double_t(0) tells accumulate the type and the starting value
1512 // compose_binary creates a BinaryFunction of ...
1513 // std::plus<Double_t>() knows how to sum up two doubles
1514 // null<Double_t>() leaves the first argument (the running sum) unchanged and returns it
1515 //
1516 // all together sums up all the event-weights of the events in the vector and returns it
1518 std::accumulate(tmpEventVector[Types::kTraining].at(cls).begin(),
1520 Double_t(0), [](Double_t w, const TMVA::Event *E) { return w + E->GetOriginalWeight(); });
1521
1523 std::accumulate(tmpEventVector[Types::kTesting].at(cls).begin(),
1525 Double_t(0), [](Double_t w, const TMVA::Event *E) { return w + E->GetOriginalWeight(); });
1526
1527 if ( cls == dsi.GetSignalClassIndex()){
1530 }else{
1533 }
1534 }
1535
1536 // ---------------------------------
1537 // compute renormalization factors
1538
1539 ValuePerClass renormFactor( dsi.GetNClasses() );
1540
1541
1542 // for information purposes
1543 dsi.SetNormalization( normMode );
1544 // !! these will be overwritten later by the 'rescaled' ones if
1545 // NormMode != None !!!
1546 dsi.SetTrainingSumSignalWeights(trainingSumSignalWeights);
1547 dsi.SetTrainingSumBackgrWeights(trainingSumBackgrWeights);
1548 dsi.SetTestingSumSignalWeights(testingSumSignalWeights);
1549 dsi.SetTestingSumBackgrWeights(testingSumBackgrWeights);
1550
1551
1552 if (normMode == "NONE") {
1553 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "No weight renormalisation applied: use original global and event weights" << Endl;
1554 return;
1555 }
1556 //changed by Helge 27.5.2013 What on earth was done here before? I still remember the idea behind this which apparently was
1557 //NOT understood by the 'programmer' :) .. the idea was to have SAME amount of effective TRAINING data for signal and background.
1558 // Testing events are totally irrelevant for this and might actually skew the whole normalisation!!
1559 else if (normMode == "NUMEVENTS") {
1560 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1561 << "\tWeight renormalisation mode: \"NumEvents\": renormalises all event classes " << Endl;
1562 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1563 << " such that the effective (weighted) number of events in each class equals the respective " << Endl;
1564 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1565 << " number of events (entries) that you demanded in PrepareTrainingAndTestTree(\"\",\"nTrain_Signal=.. )" << Endl;
1566 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1567 << " ... i.e. such that Sum[i=1..N_j]{w_i} = N_j, j=0,1,2..." << Endl;
1568 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1569 << " ... (note that N_j is the sum of TRAINING events (nTrain_j...with j=Signal,Background.." << Endl;
1570 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1571 << " ..... Testing events are not renormalised nor included in the renormalisation factor! )"<< Endl;
1572
1573 for( UInt_t cls = 0, clsEnd = dsi.GetNClasses(); cls < clsEnd; ++cls ){
1574 // renormFactor.at(cls) = ( (trainingSizePerClass.at(cls) + testingSizePerClass.at(cls))/
1575 // (trainingSumWeightsPerClass.at(cls) + testingSumWeightsPerClass.at(cls)) );
1576 //changed by Helge 27.5.2013
1579 }
1580 }
1581 else if (normMode == "EQUALNUMEVENTS") {
1582 //changed by Helge 27.5.2013 What on earth was done here before? I still remember the idea behind this which apparently was
1583 //NOT understood by the 'programmer' :) .. the idea was to have SAME amount of effective TRAINING data for signal and background.
1584 //done here was something like having each data source normalized to its number of entries and this even for training+testing together.
1585 // what should this have been good for ???
1586
1587 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "Weight renormalisation mode: \"EqualNumEvents\": renormalises all event classes ..." << Endl;
1588 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " such that the effective (weighted) number of events in each class is the same " << Endl;
1589 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " (and equals the number of events (entries) given for class=0 )" << Endl;
1590 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "... i.e. such that Sum[i=1..N_j]{w_i} = N_classA, j=classA, classB, ..." << Endl;
1591 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << "... (note that N_j is the sum of TRAINING events" << Endl;
1592 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << " ..... Testing events are not renormalised nor included in the renormalisation factor!)" << Endl;
1593
1594 // normalize to size of first class
1596 for (UInt_t cls = 0, clsEnd = dsi.GetNClasses(); cls < clsEnd; ++cls ) {
1599 }
1600 }
1601 else {
1602 Log() << kFATAL << Form("Dataset[%s] : ",dsi.GetName())<< "<PrepareForTrainingAndTesting> Unknown NormMode: " << normMode << Endl;
1603 }
1604
1605 // ---------------------------------
1606 // now apply the normalization factors
1607 Int_t maxL = dsi.GetClassNameMaxLength();
1608 for (UInt_t cls = 0, clsEnd = dsi.GetNClasses(); cls<clsEnd; ++cls) {
1609 Log() << kDEBUG //<< Form("Dataset[%s] : ",dsi.GetName())
1610 << "--> Rescale " << setiosflags(ios::left) << std::setw(maxL)
1611 << dsi.GetClassInfo(cls)->GetName() << " event weights by factor: " << renormFactor.at(cls) << Endl;
1612 for (EventVector::iterator it = tmpEventVector[Types::kTraining].at(cls).begin(),
1613 itEnd = tmpEventVector[Types::kTraining].at(cls).end(); it != itEnd; ++it){
1614 (*it)->SetWeight ((*it)->GetWeight() * renormFactor.at(cls));
1615 }
1616
1617 }
1618
1619
1620 // print out the result
1621 // (same code as before --> this can be done nicer )
1622 //
1623
1624 Log() << kINFO //<< Form("Dataset[%s] : ",dsi.GetName())
1625 << "Number of training and testing events" << Endl;
1626 Log() << kDEBUG << "\tafter rescaling:" << Endl;
1627 Log() << kINFO //<< Form("Dataset[%s] : ",dsi.GetName())
1628 << "---------------------------------------------------------------------------" << Endl;
1629
1631 trainingSumBackgrWeights = 0; // Backgr. includes all classes that are not signal
1633 testingSumBackgrWeights = 0; // Backgr. includes all classes that are not signal
1634
1635 for( UInt_t cls = 0, clsEnd = dsi.GetNClasses(); cls < clsEnd; ++cls ){
1637 std::accumulate(tmpEventVector[Types::kTraining].at(cls).begin(),
1639 Double_t(0), [](Double_t w, const TMVA::Event *E) { return w + E->GetOriginalWeight(); });
1640
1642 std::accumulate(tmpEventVector[Types::kTesting].at(cls).begin(),
1644 Double_t(0), [](Double_t w, const TMVA::Event *E) { return w + E->GetOriginalWeight(); });
1645
1646 if ( cls == dsi.GetSignalClassIndex()){
1649 }else{
1652 }
1653
1654 // output statistics
1655
1656 Log() << kINFO //<< Form("Dataset[%s] : ",dsi.GetName())
1657 << setiosflags(ios::left) << std::setw(maxL)
1658 << dsi.GetClassInfo(cls)->GetName() << " -- "
1659 << "training events : " << trainingSizePerClass.at(cls) << Endl;
1660 Log() << kDEBUG << "\t(sum of weights: " << trainingSumWeightsPerClass.at(cls) << ")"
1661 << " - requested were " << eventCounts[cls].nTrainingEventsRequested << " events" << Endl;
1662 Log() << kINFO //<< Form("Dataset[%s] : ",dsi.GetName())
1663 << setiosflags(ios::left) << std::setw(maxL)
1664 << dsi.GetClassInfo(cls)->GetName() << " -- "
1665 << "testing events : " << testingSizePerClass.at(cls) << Endl;
1666 Log() << kDEBUG << "\t(sum of weights: " << testingSumWeightsPerClass.at(cls) << ")"
1667 << " - requested were " << eventCounts[cls].nTestingEventsRequested << " events" << Endl;
1668 Log() << kINFO //<< Form("Dataset[%s] : ",dsi.GetName())
1669 << setiosflags(ios::left) << std::setw(maxL)
1670 << dsi.GetClassInfo(cls)->GetName() << " -- "
1671 << "training and testing events: "
1673 Log() << kDEBUG << "\t(sum of weights: "
1675 if(eventCounts[cls].nEvAfterCut<eventCounts[cls].nEvBeforeCut) {
1676 Log() << kINFO << Form("Dataset[%s] : ",dsi.GetName()) << setiosflags(ios::left) << std::setw(maxL)
1677 << dsi.GetClassInfo(cls)->GetName() << " -- "
1678 << "due to the preselection a scaling factor has been applied to the numbers of requested events: "
1679 << eventCounts[cls].cutScaling() << Endl;
1680 }
1681 }
1682 Log() << kINFO << Endl;
1683
1684 // for information purposes
1685 dsi.SetTrainingSumSignalWeights(trainingSumSignalWeights);
1686 dsi.SetTrainingSumBackgrWeights(trainingSumBackgrWeights);
1687 dsi.SetTestingSumSignalWeights(testingSumSignalWeights);
1688 dsi.SetTestingSumBackgrWeights(testingSumBackgrWeights);
1689
1690
1691}
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
TMatrixT< Double_t > TMatrixD
Definition TMatrixDfwd.h:23
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2570
const_iterator begin() const
const_iterator end() const
A specialized string object used for TTree selections.
Definition TCut.h:25
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
Class that contains all the data information.
DataSet * BuildInitialDataSet(DataSetInfo &, TMVA::DataInputHandler &)
if no entries, than create a DataSet with one Event which uses dynamic variables (pointers to variabl...
DataSetFactory()
constructor
std::map< Types::ETreeType, EventVectorOfClasses > EventVectorOfClassesOfTreeType
void ChangeToNewTree(TreeInfo &, const DataSetInfo &)
While the data gets copied into the local training and testing trees, the input tree can change (for ...
void BuildEventVector(DataSetInfo &dsi, DataInputHandler &dataInput, EventVectorOfClassesOfTreeType &eventsmap, EvtStatsPerClass &eventCounts)
build empty event vectors distributes events between kTraining/kTesting/kMaxTreeType
DataSet * CreateDataSet(DataSetInfo &, DataInputHandler &)
steering the creation of a new dataset
DataSet * MixEvents(DataSetInfo &dsi, EventVectorOfClassesOfTreeType &eventsmap, EvtStatsPerClass &eventCounts, const TString &splitMode, const TString &mixMode, const TString &normMode, UInt_t splitSeed)
Select and distribute unassigned events to kTraining and kTesting.
std::vector< int > NumberPerClass
std::vector< EventVector > EventVectorOfClasses
void InitOptions(DataSetInfo &dsi, EvtStatsPerClass &eventsmap, TString &normMode, UInt_t &splitSeed, TString &splitMode, TString &mixMode)
the dataset splitting
void CalcMinMax(DataSet *, DataSetInfo &dsi)
compute covariance matrix
std::vector< Double_t > ValuePerClass
DataSet * BuildDynamicDataSet(DataSetInfo &)
std::vector< EventStats > EvtStatsPerClass
Bool_t CheckTTreeFormula(TTreeFormula *ttf, const TString &expression, Bool_t &hasDollar)
checks a TTreeFormula for problems
void RenormEvents(DataSetInfo &dsi, EventVectorOfClassesOfTreeType &eventsmap, const EvtStatsPerClass &eventCounts, const TString &normMode)
renormalisation of the TRAINING event weights
TMatrixD * CalcCorrelationMatrix(DataSet *, const UInt_t classNumber)
computes correlation matrix for variables "theVars" in tree; "theType" defines the required event "ty...
TMatrixD * CalcCovarianceMatrix(DataSet *, const UInt_t classNumber)
compute covariance matrix
std::vector< Event * > EventVector
Class that contains all the data information.
Definition DataSetInfo.h:62
Class that contains all the data information.
Definition DataSet.h:58
ostringstream derivative to redirect and format output
Definition MsgLogger.h:57
@ kMaxTreeType
also used as temporary storage for trees not yet assigned for testing;training...
Definition Types.h:145
@ kTraining
Definition Types.h:143
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
Basic string class.
Definition TString.h:138
const char * Data() const
Definition TString.h:386
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2459
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:643
Used to pass a selection expression to the Tree drawing routine.
T EvalInstance(Int_t i=0, const char *stringStack[]=nullptr)
Evaluate this treeformula.
void SetQuickLoad(bool quick)
virtual Int_t GetNdata()
Return number of available instances in the formula.
A TTree represents a columnar dataset.
Definition TTree.h:89
create variable transformations
Int_t LargestCommonDivider(Int_t a, Int_t b)
MsgLogger & Endl(MsgLogger &ml)
Definition MsgLogger.h:148
Bool_t IsNaN(Double_t x)
Definition TMath.h:905
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Int_t Finite(Double_t x)
Check if it is finite with a mask in order to be consistent in presence of fast math.
Definition TMath.h:783
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122
static const char * what
Definition stlLoader.cc:5