Logo ROOT   6.14/05
Reference Guide
LossFunction.cxx
Go to the documentation of this file.
1 // @(#)root/tmva $Id$
2 // Author: Andreas Hoecker, Peter Speckmayer, Joerg Stelzer, Helge Voss, Jan Therhaag
3 
4 /**********************************************************************************
5  * Project: TMVA - a Root-integrated toolkit for multivariate data analysis *
6  * Package: TMVA *
7  * Class : LossFunction *
8  * Web : http://tmva.sourceforge.net *
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> - CERN, Switzerland *
17  * Jan Therhaag <Jan.Therhaag@cern.ch> - U of Bonn, Germany *
18  * Helge Voss <Helge.Voss@cern.ch> - MPI-K Heidelberg, 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://mva.sourceforge.net/license.txt) *
29  **********************************************************************************/
30 
31 /*! \class TMVA::HuberLossFunction
32 \ingroup TMVA
33 
34 Huber Loss Function.
35 
36 */
37 
38 #include "TMVA/LossFunction.h"
39 #include "TMVA/Config.h"
40 
41 #include "TMVA/MsgLogger.h"
42 
43 #include "Rtypes.h"
44 #include "TMath.h"
45 #include <iostream>
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 /// huber constructor
49 
51  fTransitionPoint = -9999;
52  fSumOfWeights = -9999;
53  fQuantile = 0.7; // the quantile value determines the bulk of the data, e.g. 0.7 defines
54  // the core as the first 70% and the tails as the last 30%
55 }
56 
58  fSumOfWeights = -9999;
59  fTransitionPoint = -9999;
60  fQuantile = quantile;
61 }
62 
63 ////////////////////////////////////////////////////////////////////////////////
64 /// huber destructor
65 
67 
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 /// figure out the residual that determines the separation between the
72 /// "core" and the "tails" of the residuals distribution
73 
74 void TMVA::HuberLossFunction::Init(std::vector<LossFunctionEventInfo>& evs){
75 
76  // Calculate the residual that separates the core and the tails
77  SetSumOfWeights(evs);
78  SetTransitionPoint(evs);
79 }
80 
81 ////////////////////////////////////////////////////////////////////////////////
82 /// huber, calculate the sum of weights for the events in the vector
83 
84 // Multithreaded version of HuberLossFunction::CalculateSumOfWeights
85 #ifdef R__USE_IMT
86 Double_t TMVA::HuberLossFunction::CalculateSumOfWeights(std::vector<LossFunctionEventInfo>& evs){
87 
88  UInt_t nPartitions = fNumPoolThreads;
89  auto seeds = ROOT::TSeqU(nPartitions);
90  auto redfunc = [](std::vector<Double_t> a) -> Double_t { return std::accumulate(a.begin(), a.end(), 0); };
91 
92  // need a lambda function to pass to TThreadExecutor::MapReduce
93  auto f = [&evs, &nPartitions](UInt_t partition = 0) -> Double_t{
94  Double_t sumOfWeightsN = 0;
95 
96  Int_t start = 1.0*partition/nPartitions*evs.size();
97  Int_t end = (partition+1.0)/nPartitions*evs.size();
98 
99  for(Int_t i=start; i<end; i++)
100  {
101  sumOfWeightsN+=evs[i].weight;
102  }
103 
104  return sumOfWeightsN;
105  };
106 
107  auto sumOfWeightsN = TMVA::Config::Instance().GetThreadExecutor().MapReduce(f, seeds, redfunc, nPartitions);
108  return sumOfWeightsN;
109 }
110 // Standard version of HuberLossFunction::CalculateSumOfWeights
111 #else
112 Double_t TMVA::HuberLossFunction::CalculateSumOfWeights(std::vector<LossFunctionEventInfo>& evs){
113 
114  // Calculate the sum of the weights
115  Double_t sumOfWeights = 0;
116  for(UInt_t i = 0; i<evs.size(); i++)
117  sumOfWeights+=evs[i].weight;
118 
119  return sumOfWeights;
120 }
121 #endif
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 /// huber, determine the quantile for a given input
125 
126 Double_t TMVA::HuberLossFunction::CalculateQuantile(std::vector<LossFunctionEventInfo>& evs, Double_t whichQuantile, Double_t sumOfWeights, bool abs){
127 
128  // use a lambda function to tell the vector how to sort the LossFunctionEventInfo data structures
129  // (sort them in ascending order of residual magnitude) if abs is true
130  // otherwise sort them in ascending order of residual
131  if(abs)
132  std::sort(evs.begin(), evs.end(), [](LossFunctionEventInfo a, LossFunctionEventInfo b){
133  return TMath::Abs(a.trueValue-a.predictedValue) < TMath::Abs(b.trueValue-b.predictedValue); });
134  else
135  std::sort(evs.begin(), evs.end(), [](LossFunctionEventInfo a, LossFunctionEventInfo b){
136  return (a.trueValue-a.predictedValue) < (b.trueValue-b.predictedValue); });
137  UInt_t i = 0;
138  Double_t temp = 0.0;
139  while(i<evs.size()-1 && temp <= sumOfWeights*whichQuantile){
140  temp += evs[i].weight;
141  i++;
142  }
143  // edge cases
144  // Output warning for low return values
145  if(whichQuantile == 0) i=0; // assume 0th quantile to mean the 0th entry in the ordered series
146 
147  // usual returns
148  if(abs) return TMath::Abs(evs[i].trueValue-evs[i].predictedValue);
149  else return evs[i].trueValue-evs[i].predictedValue;
150 }
151 
152 ////////////////////////////////////////////////////////////////////////////////
153 /// huber, determine the transition point using the values for fQuantile and fSumOfWeights
154 /// which presumably have already been set
155 
156 void TMVA::HuberLossFunction::SetTransitionPoint(std::vector<LossFunctionEventInfo>& evs){
158 
159  // if the transition point corresponding to the quantile is 0 then the loss function will not function
160  // the quantile was chosen too low. Let's use the first nonzero residual as the transition point instead.
161  if(fTransitionPoint == 0){
162  // evs should already be sorted according to the magnitude of the residuals, since CalculateQuantile does this
163  for(UInt_t i=0; i<evs.size(); i++){
164  Double_t residual = TMath::Abs(evs[i].trueValue - evs[i].predictedValue);
165  if(residual != 0){
166  fTransitionPoint = residual;
167  break;
168  }
169  }
170  }
171 
172  // Let the user know that the transition point is zero and the loss function won't work properly
173  if(fTransitionPoint == 0){
174  //std::cout << "The residual transition point for the Huber loss function corresponding to quantile, " << fQuantile << ", is zero."
175  //<< " This implies that all of the residuals are zero and the events have been predicted perfectly. Perhaps the regression is too complex"
176  //<< " for the amount of data." << std::endl;
177  }
178 }
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// huber, set the sum of weights given a collection of events
182 
183 void TMVA::HuberLossFunction::SetSumOfWeights(std::vector<LossFunctionEventInfo>& evs){
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// huber, determine the loss for a single event
189 
191  // If the huber loss function is uninitialized then assume a group of one
192  // and initialize the transition point and weights for this single event
193  if(fSumOfWeights == -9999){
194  std::vector<LossFunctionEventInfo> evs;
195  evs.push_back(e);
196 
197  SetSumOfWeights(evs);
198  SetTransitionPoint(evs);
199  }
200 
201  Double_t residual = TMath::Abs(e.trueValue - e.predictedValue);
202  Double_t loss = 0;
203  // Quadratic loss in terms of the residual for small residuals
204  if(residual <= fTransitionPoint) loss = 0.5*residual*residual;
205  // Linear loss for large residuals, so that the tails don't dominate the net loss calculation
206  else loss = fQuantile*residual - 0.5*fQuantile*fQuantile;
207  return e.weight*loss;
208 }
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 /// huber, determine the net loss for a collection of events
212 
213 Double_t TMVA::HuberLossFunction::CalculateNetLoss(std::vector<LossFunctionEventInfo>& evs){
214  // Initialize the Huber Loss Function so that we can calculate the loss.
215  // The loss for each event depends on the other events in the group
216  // that define the cutoff quantile (fTransitionPoint).
217  SetSumOfWeights(evs);
218  SetTransitionPoint(evs);
219 
220  Double_t netloss = 0;
221  for(UInt_t i=0; i<evs.size(); i++)
222  netloss+=CalculateLoss(evs[i]);
223  return netloss;
224  // should get a function to return the average loss as well
225  // return netloss/fSumOfWeights
226 }
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 /// huber, determine the mean loss for a collection of events
230 
231 Double_t TMVA::HuberLossFunction::CalculateMeanLoss(std::vector<LossFunctionEventInfo>& evs){
232  // Initialize the Huber Loss Function so that we can calculate the loss.
233  // The loss for each event depends on the other events in the group
234  // that define the cutoff quantile (fTransitionPoint).
235  SetSumOfWeights(evs);
236  SetTransitionPoint(evs);
237 
238  Double_t netloss = 0;
239  for(UInt_t i=0; i<evs.size(); i++)
240  netloss+=CalculateLoss(evs[i]);
241  return netloss/fSumOfWeights;
242 }
243 
244 /*! \class TMVA::HuberLossFunctionBDT
245 \ingroup TMVA
246 
247 Huber BDT Loss Function.
248 
249 */
250 
252 }
253 
254 ////////////////////////////////////////////////////////////////////////////////
255 /// huber BDT, initialize the targets and prepare for the regression
256 
257 void TMVA::HuberLossFunctionBDT::Init(std::map<const TMVA::Event*, LossFunctionEventInfo>& evinfomap, std::vector<double>& boostWeights){
258 // Run this once before building the forest. Set initial prediction to weightedMedian.
259 
260  std::vector<LossFunctionEventInfo> evinfovec;
261  for (auto &e: evinfomap){
262  evinfovec.push_back(LossFunctionEventInfo(e.second.trueValue, e.second.predictedValue, e.first->GetWeight()));
263  }
264 
265  // Calculates fSumOfWeights and fTransitionPoint with the current residuals
266  SetSumOfWeights(evinfovec);
267  Double_t weightedMedian = CalculateQuantile(evinfovec, 0.5, fSumOfWeights, false);
268 
269  //Store the weighted median as a first boosweight for later use
270  boostWeights.push_back(weightedMedian);
271  for (auto &e: evinfomap ) {
272  // set the initial prediction for all events to the median
273  e.second.predictedValue += weightedMedian;
274  }
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 /// huber BDT, set the targets for a collection of events
279 
280 // Multithreaded version of HuberLossFunctionBDT::SetTargets
281 #ifdef R__USE_IMT
282 void TMVA::HuberLossFunctionBDT::SetTargets(std::vector<const TMVA::Event*>& evs, std::map< const TMVA::Event*, LossFunctionEventInfo >& evinfomap){
283 
284  UInt_t nPartitions = fNumPoolThreads;
285  std::vector<LossFunctionEventInfo> eventvec(evs.size());
286 
287  auto seedscopy = ROOT::TSeqU(nPartitions);
288 
289  // first we need to copy the events from evs into eventvec since we require a vector of LossFunctionEventInfo
290  // for SetSumOfWeights and SetTransitionPoint. We use TThreadExecutor to implement the copy in parallel
291  // need a lambda function to pass to TThreadExecutor::Map
292  auto fcopy = [&eventvec, &evs, &evinfomap, &nPartitions](UInt_t partition = 0) -> Int_t{
293 
294  Int_t start = 1.0*partition/nPartitions*evs.size();
295  Int_t end = (partition+1.0)/nPartitions*evs.size();
296 
297  for(Int_t i=start; i<end; ++i)
298  eventvec[i] = LossFunctionEventInfo(evinfomap[evs[i]].trueValue, evinfomap[evs[i]].predictedValue, evs[i]->GetWeight());
299 
300  return 0;
301  };
302 
303  TMVA::Config::Instance().GetThreadExecutor().Map(fcopy, seedscopy);
304 
305  // Recalculate the residual that separates the "core" of the data and the "tails"
306  // This residual is the quantile given by fQuantile, defaulted to 0.7
307  // the quantile corresponding to 0.5 would be the usual median
308  SetSumOfWeights(eventvec); // This was already set in init, but may change if there is subsampling for each tree
309  SetTransitionPoint(eventvec);
310 
311  auto seeds = ROOT::TSeqU(nPartitions);
312 
313  // ok now set the targets in parallel
314  // need a lambda function to pass to TThreadExecutor::Map
315  auto f = [this, &evs, &evinfomap, &nPartitions](UInt_t partition = 0) -> Int_t{
316 
317  Int_t start = 1.0*partition/nPartitions*evs.size();
318  Int_t end = (partition+1.0)/nPartitions*evs.size();
319 
320  for(Int_t i=start; i<end; ++i)
321  const_cast<TMVA::Event*>(evs[i])->SetTarget(0,Target(evinfomap[evs[i]]));
322 
323  return 0;
324  };
325 
327 }
328 
329 // Standard version of HuberLossFunctionBDT::SetTargets
330 #else
331 void TMVA::HuberLossFunctionBDT::SetTargets(std::vector<const TMVA::Event*>& evs, std::map< const TMVA::Event*, LossFunctionEventInfo >& evinfomap){
332 
333  std::vector<LossFunctionEventInfo> eventvec;
334  for (std::vector<const TMVA::Event*>::const_iterator e=evs.begin(); e!=evs.end();e++){
335  eventvec.push_back(LossFunctionEventInfo(evinfomap[*e].trueValue, evinfomap[*e].predictedValue, (*e)->GetWeight()));
336  }
337 
338  // Recalculate the residual that separates the "core" of the data and the "tails"
339  // This residual is the quantile given by fQuantile, defaulted to 0.7
340  // the quantile corresponding to 0.5 would be the usual median
341  SetSumOfWeights(eventvec); // This was already set in init, but may change if there is subsampling for each tree
342  SetTransitionPoint(eventvec);
343 
344  for (std::vector<const TMVA::Event*>::const_iterator e=evs.begin(); e!=evs.end();e++) {
345  const_cast<TMVA::Event*>(*e)->SetTarget(0,Target(evinfomap[*e]));
346  }
347 }
348 #endif
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// huber BDT, set the target for a single event
352 
354  Double_t residual = e.trueValue - e.predictedValue;
355  // The weight/target relationships are taken care of in the tmva decision tree operations so we don't need to worry about that here
356  if(TMath::Abs(residual) <= fTransitionPoint) return residual;
357  else return fTransitionPoint*(residual<0?-1.0:1.0);
358 }
359 
360 ////////////////////////////////////////////////////////////////////////////////
361 /// huber BDT, determine the fit value for the terminal node based upon the
362 /// events in the terminal node
363 
364 Double_t TMVA::HuberLossFunctionBDT::Fit(std::vector<LossFunctionEventInfo>& evs){
365 // The fit in the terminal node for huber is basically the median of the residuals.
366 // Then you add the average difference from the median to that.
367 // The tails are discounted. If a residual is in the tails then we just use the
368 // cutoff residual that sets the "core" and the "tails" instead of the large residual.
369 // So we get something between least squares (mean as fit) and absolute deviation (median as fit).
370  Double_t sumOfWeights = CalculateSumOfWeights(evs);
371  Double_t shift=0,diff= 0;
372  Double_t residualMedian = CalculateQuantile(evs,0.5,sumOfWeights, false);
373  for(UInt_t j=0;j<evs.size();j++){
374  Double_t residual = evs[j].trueValue - evs[j].predictedValue;
375  diff = residual-residualMedian;
376  // if we are using weights then I'm not sure why this isn't weighted
377  shift+=1.0/evs.size()*((diff<0)?-1.0:1.0)*TMath::Min(fTransitionPoint,fabs(diff));
378  // I think this should be
379  // shift+=evs[j].weight/sumOfWeights*((diff<0)?-1.0:1.0)*TMath::Min(fTransitionPoint,fabs(diff));
380  // not sure why it was originally coded like this
381  }
382  return (residualMedian + shift);
383 
384 }
385 
386 /*! \class TMVA::LeastSquaresLossFunction
387 \ingroup TMVA
388 
389 Least Squares Loss Function.
390 
391 */
392 
393 // Constructor and destructor are in header file. They don't do anything.
394 
395 ////////////////////////////////////////////////////////////////////////////////
396 /// least squares , determine the loss for a single event
397 
399  Double_t residual = (e.trueValue - e.predictedValue);
400  Double_t loss = 0;
401  loss = residual*residual;
402  return e.weight*loss;
403 }
404 
405 ////////////////////////////////////////////////////////////////////////////////
406 /// least squares , determine the net loss for a collection of events
407 
408 Double_t TMVA::LeastSquaresLossFunction::CalculateNetLoss(std::vector<LossFunctionEventInfo>& evs){
409  Double_t netloss = 0;
410  for(UInt_t i=0; i<evs.size(); i++)
411  netloss+=CalculateLoss(evs[i]);
412  return netloss;
413  // should get a function to return the average loss as well
414  // return netloss/fSumOfWeights
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// least squares , determine the mean loss for a collection of events
419 
420 Double_t TMVA::LeastSquaresLossFunction::CalculateMeanLoss(std::vector<LossFunctionEventInfo>& evs){
421  Double_t netloss = 0;
422  Double_t sumOfWeights = 0;
423  for(UInt_t i=0; i<evs.size(); i++){
424  sumOfWeights+=evs[i].weight;
425  netloss+=CalculateLoss(evs[i]);
426  }
427  // return the weighted mean
428  return netloss/sumOfWeights;
429 }
430 
431 /*! \class TMVA::LeastSquaresLossFunctionBDT
432 \ingroup TMVA
433 
434 Least Squares BDT Loss Function.
435 
436 */
437 
438 // Constructor and destructor defined in header. They don't do anything.
439 
440 ////////////////////////////////////////////////////////////////////////////////
441 /// least squares BDT, initialize the targets and prepare for the regression
442 
443 void TMVA::LeastSquaresLossFunctionBDT::Init(std::map<const TMVA::Event*, LossFunctionEventInfo>& evinfomap, std::vector<double>& boostWeights){
444 // Run this once before building the forest. Set initial prediction to the weightedMean
445 
446  std::vector<LossFunctionEventInfo> evinfovec;
447  for (auto &e: evinfomap){
448  evinfovec.push_back(LossFunctionEventInfo(e.second.trueValue, e.second.predictedValue, e.first->GetWeight()));
449  }
450 
451  // Initial prediction for least squares is the weighted mean
452  Double_t weightedMean = Fit(evinfovec);
453 
454  //Store the weighted median as a first boosweight for later use
455  boostWeights.push_back(weightedMean);
456  for (auto &e: evinfomap ) {
457  // set the initial prediction for all events to the median
458  e.second.predictedValue += weightedMean;
459  }
460 }
461 
462 ////////////////////////////////////////////////////////////////////////////////
463 /// least squares BDT, set the targets for a collection of events
464 
465 // Multithreaded version of LeastSquaresLossFunctionBDT::SetTargets
466 #ifdef R__USE_IMT
467 void TMVA::LeastSquaresLossFunctionBDT::SetTargets(std::vector<const TMVA::Event*>& evs, std::map< const TMVA::Event*, LossFunctionEventInfo >& evinfomap){
468 
469  UInt_t nPartitions = fNumPoolThreads;
470  auto seeds = ROOT::TSeqU(nPartitions);
471 
472  // need a lambda function to pass to TThreadExecutor::Map
473  auto f = [this, &evs, &evinfomap, &nPartitions](UInt_t partition = 0) -> Int_t{
474 
475  Int_t start = 1.0*partition/nPartitions*evs.size();
476  Int_t end = (partition+1.0)/nPartitions*evs.size();
477 
478  for(Int_t i=start; i<end; ++i)
479  const_cast<TMVA::Event*>(evs[i])->SetTarget(0,Target(evinfomap[evs[i]]));
480 
481  return 0;
482  };
483 
485 }
486 // Standard version of LeastSquaresLossFunctionBDT::SetTargets
487 #else
488 void TMVA::LeastSquaresLossFunctionBDT::SetTargets(std::vector<const TMVA::Event*>& evs, std::map< const TMVA::Event*, LossFunctionEventInfo >& evinfomap){
489 
490  for (std::vector<const TMVA::Event*>::const_iterator e=evs.begin(); e!=evs.end();e++) {
491  const_cast<TMVA::Event*>(*e)->SetTarget(0,Target(evinfomap[*e]));
492  }
493 }
494 #endif
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// least squares BDT, set the target for a single event
498 
500  Double_t residual = e.trueValue - e.predictedValue;
501  // The weight/target relationships are taken care of in the tmva decision tree operations. We don't need to worry about that here
502  // and we return the residual instead of the weight*residual.
503  return residual;
504 }
505 
506 ////////////////////////////////////////////////////////////////////////////////
507 /// huber BDT, determine the fit value for the terminal node based upon the
508 /// events in the terminal node
509 
510 Double_t TMVA::LeastSquaresLossFunctionBDT::Fit(std::vector<LossFunctionEventInfo>& evs){
511 // The fit in the terminal node for least squares is the weighted average of the residuals.
512  Double_t sumOfWeights = 0;
513  Double_t weightedResidualSum = 0;
514  for(UInt_t j=0;j<evs.size();j++){
515  sumOfWeights += evs[j].weight;
516  Double_t residual = evs[j].trueValue - evs[j].predictedValue;
517  weightedResidualSum += evs[j].weight*residual;
518  }
519  Double_t weightedMean = weightedResidualSum/sumOfWeights;
520 
521  // return the weighted mean
522  return weightedMean;
523 }
524 
525 /*! \class TMVA::AbsoluteDeviationLossFunction
526 \ingroup TMVA
527 
528 Absolute Deviation Loss Function.
529 
530 */
531 
532 // Constructors in the header. They don't do anything.
533 
534 ////////////////////////////////////////////////////////////////////////////////
535 /// absolute deviation, determine the loss for a single event
536 
538  Double_t residual = e.trueValue - e.predictedValue;
539  return e.weight*TMath::Abs(residual);
540 }
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 /// absolute deviation, determine the net loss for a collection of events
544 
545 Double_t TMVA::AbsoluteDeviationLossFunction::CalculateNetLoss(std::vector<LossFunctionEventInfo>& evs){
546 
547  Double_t netloss = 0;
548  for(UInt_t i=0; i<evs.size(); i++)
549  netloss+=CalculateLoss(evs[i]);
550  return netloss;
551 }
552 
553 ////////////////////////////////////////////////////////////////////////////////
554 /// absolute deviation, determine the mean loss for a collection of events
555 
556 Double_t TMVA::AbsoluteDeviationLossFunction::CalculateMeanLoss(std::vector<LossFunctionEventInfo>& evs){
557  Double_t sumOfWeights = 0;
558  Double_t netloss = 0;
559  for(UInt_t i=0; i<evs.size(); i++){
560  sumOfWeights+=evs[i].weight;
561  netloss+=CalculateLoss(evs[i]);
562  }
563  return netloss/sumOfWeights;
564 }
565 
566 /*! \class TMVA::AbsoluteDeviationLossFunctionBDT
567 \ingroup TMVA
568 
569 Absolute Deviation BDT Loss Function.
570 
571 */
572 
573 ////////////////////////////////////////////////////////////////////////////////
574 /// absolute deviation BDT, initialize the targets and prepare for the regression
575 
576 void TMVA::AbsoluteDeviationLossFunctionBDT::Init(std::map<const TMVA::Event*, LossFunctionEventInfo>& evinfomap, std::vector<double>& boostWeights){
577 // Run this once before building the forest. Set initial prediction to weightedMedian.
578 
579  std::vector<LossFunctionEventInfo> evinfovec;
580  for (auto &e: evinfomap){
581  evinfovec.push_back(LossFunctionEventInfo(e.second.trueValue, e.second.predictedValue, e.first->GetWeight()));
582  }
583 
584  Double_t weightedMedian = Fit(evinfovec);
585 
586  //Store the weighted median as a first boostweight for later use
587  boostWeights.push_back(weightedMedian);
588  for (auto &e: evinfomap ) {
589  // set the initial prediction for all events to the median
590  e.second.predictedValue += weightedMedian;
591  }
592 }
593 
594 ////////////////////////////////////////////////////////////////////////////////
595 /// absolute deviation BDT, set the targets for a collection of events
596 
597 // Multithreaded version of AbsoluteDeviationLossFunctionBDT::SetTargets
598 #ifdef R__USE_IMT
599 void TMVA::AbsoluteDeviationLossFunctionBDT::SetTargets(std::vector<const TMVA::Event*>& evs, std::map< const TMVA::Event*, LossFunctionEventInfo >& evinfomap){
600 
601  UInt_t nPartitions = fNumPoolThreads;
602  auto seeds = ROOT::TSeqU(nPartitions);
603 
604  // need a lambda function to pass to TThreadExecutor::Map
605  auto f = [this, &evs, &evinfomap, &nPartitions](UInt_t partition = 0) -> Int_t{
606 
607  Int_t start = 1.0*partition/nPartitions*evs.size();
608  Int_t end = (partition+1.0)/nPartitions*evs.size();
609 
610  for(Int_t i=start; i<end; ++i)
611  const_cast<TMVA::Event*>(evs[i])->SetTarget(0,Target(evinfomap[evs[i]]));
612 
613  return 0;
614  };
615 
617 }
618 // Standard version of AbsoluteDeviationLossFunctionBDT::SetTargets
619 #else
620 void TMVA::AbsoluteDeviationLossFunctionBDT::SetTargets(std::vector<const TMVA::Event*>& evs, std::map< const TMVA::Event*, LossFunctionEventInfo >& evinfomap){
621 
622  for (std::vector<const TMVA::Event*>::const_iterator e=evs.begin(); e!=evs.end();e++) {
623  const_cast<TMVA::Event*>(*e)->SetTarget(0,Target(evinfomap[*e]));
624  }
625 }
626 #endif
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 /// absolute deviation BDT, set the target for a single event
630 
632 // The target is the sign of the residual.
633  Double_t residual = e.trueValue - e.predictedValue;
634  // The weight/target relationships are taken care of in the tmva decision tree operations so we don't need to worry about that here
635  return (residual<0?-1.0:1.0);
636 }
637 
638 ////////////////////////////////////////////////////////////////////////////////
639 /// absolute deviation BDT, determine the fit value for the terminal node based upon the
640 /// events in the terminal node
641 
642 Double_t TMVA::AbsoluteDeviationLossFunctionBDT::Fit(std::vector<LossFunctionEventInfo>& evs){
643 // For Absolute Deviation, the fit in each terminal node is the weighted residual median.
644 
645  // use a lambda function to tell the vector how to sort the LossFunctionEventInfo data structures
646  // sort in ascending order of residual value
647  std::sort(evs.begin(), evs.end(), [](LossFunctionEventInfo a, LossFunctionEventInfo b){
648  return (a.trueValue-a.predictedValue) < (b.trueValue-b.predictedValue); });
649 
650  // calculate the sum of weights, used in the weighted median calculation
651  Double_t sumOfWeights = 0;
652  for(UInt_t j=0; j<evs.size(); j++)
653  sumOfWeights+=evs[j].weight;
654 
655  // get the index of the weighted median
656  UInt_t i = 0;
657  Double_t temp = 0.0;
658  while(i<evs.size() && temp <= sumOfWeights*0.5){
659  temp += evs[i].weight;
660  i++;
661  }
662  if (i >= evs.size()) return 0.; // prevent uncontrolled memory access in return value calculation
663 
664  // return the median residual
665  return evs[i].trueValue-evs[i].predictedValue;
666 }
Double_t CalculateMeanLoss(std::vector< LossFunctionEventInfo > &evs)
absolute deviation, determine the mean loss for a collection of events
static Config & Instance()
static function: returns TMVA instance
Definition: Config.cxx:109
Double_t CalculateLoss(LossFunctionEventInfo &e)
absolute deviation, determine the loss for a single event
void Init(std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap, std::vector< double > &boostWeights)
absolute deviation BDT, initialize the targets and prepare for the regression
#define f(i)
Definition: RSha256.hxx:104
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
int Int_t
Definition: RtypesCore.h:41
Double_t Fit(std::vector< LossFunctionEventInfo > &evs)
absolute deviation BDT, determine the fit value for the terminal node based upon the events in the te...
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
void SetTargets(std::vector< const TMVA::Event *> &evs, std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap)
absolute deviation BDT, set the targets for a collection of events
void SetTargets(std::vector< const TMVA::Event *> &evs, std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap)
huber BDT, set the targets for a collection of events
TSeq< unsigned int > TSeqU
Definition: TSeq.hxx:195
Double_t CalculateLoss(LossFunctionEventInfo &e)
least squares , determine the loss for a single event
Double_t Target(LossFunctionEventInfo &e)
absolute deviation BDT, set the target for a single event
Double_t Target(LossFunctionEventInfo &e)
huber BDT, set the target for a single event
void Init(std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap, std::vector< double > &boostWeights)
huber BDT, initialize the targets and prepare for the regression
ROOT::TThreadExecutor & GetThreadExecutor()
Definition: Config.h:82
VecExpr< UnaryOp< Fabs< T >, VecExpr< A, T, D >, T >, T, D > fabs(const VecExpr< A, T, D > &rhs)
auto * a
Definition: textangle.C:12
void SetTargets(std::vector< const TMVA::Event *> &evs, std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap)
least squares BDT, set the targets for a collection of events
Double_t Fit(std::vector< LossFunctionEventInfo > &evs)
huber BDT, determine the fit value for the terminal node based upon the events in the terminal node ...
Double_t CalculateSumOfWeights(std::vector< LossFunctionEventInfo > &evs)
huber, calculate the sum of weights for the events in the vector
HuberLossFunction()
huber constructor
Double_t CalculateNetLoss(std::vector< LossFunctionEventInfo > &evs)
least squares , determine the net loss for a collection of events
Double_t CalculateQuantile(std::vector< LossFunctionEventInfo > &evs, Double_t whichQuantile, Double_t sumOfWeights, bool abs)
huber, determine the quantile for a given input
unsigned int UInt_t
Definition: RtypesCore.h:42
void SetTarget(UInt_t itgt, Float_t value)
set the target value (dimension itgt) to value
Definition: Event.cxx:360
void Init(std::map< const TMVA::Event *, LossFunctionEventInfo > &evinfomap, std::vector< double > &boostWeights)
least squares BDT, initialize the targets and prepare for the regression
double Double_t
Definition: RtypesCore.h:55
TFitResultPtr Fit(FitObject *h1, TF1 *f1, Foption_t &option, const ROOT::Math::MinimizerOptions &moption, const char *goption, ROOT::Fit::DataRange &range)
Definition: HFitImpl.cxx:134
void Init(std::vector< LossFunctionEventInfo > &evs)
figure out the residual that determines the separation between the "core" and the "tails" of the resi...
void SetTransitionPoint(std::vector< LossFunctionEventInfo > &evs)
huber, determine the transition point using the values for fQuantile and fSumOfWeights which presumab...
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
Double_t CalculateNetLoss(std::vector< LossFunctionEventInfo > &evs)
huber, determine the net loss for a collection of events
~HuberLossFunction()
huber destructor
Double_t CalculateMeanLoss(std::vector< LossFunctionEventInfo > &evs)
huber, determine the mean loss for a collection of events
auto MapReduce(F func, unsigned nTimes, R redfunc) -> typename std::result_of< F()>::type
This method behaves just like Map, but an additional redfunc function must be provided.
void SetSumOfWeights(std::vector< LossFunctionEventInfo > &evs)
huber, set the sum of weights given a collection of events
Double_t CalculateMeanLoss(std::vector< LossFunctionEventInfo > &evs)
least squares , determine the mean loss for a collection of events
auto Map(F func, unsigned nTimes) -> std::vector< typename std::result_of< F()>::type >
Execute func (with no arguments) nTimes in parallel.
Double_t Fit(std::vector< LossFunctionEventInfo > &evs)
huber BDT, determine the fit value for the terminal node based upon the events in the terminal node ...
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
Double_t CalculateLoss(LossFunctionEventInfo &e)
huber, determine the loss for a single event
Double_t CalculateNetLoss(std::vector< LossFunctionEventInfo > &evs)
absolute deviation, determine the net loss for a collection of events
Double_t Target(LossFunctionEventInfo &e)
least squares BDT, set the target for a single event