107 if (fModule)
delete fModule;
125 DeclareOptionRef(fnkNN = 20,
"nkNN",
"Number of k-nearest neighbors");
126 DeclareOptionRef(fBalanceDepth = 6,
"BalanceDepth",
"Binary tree balance depth");
127 DeclareOptionRef(fScaleFrac = 0.80,
"ScaleFrac",
"Fraction of events used to compute variable width");
128 DeclareOptionRef(fSigmaFact = 1.0,
"SigmaFact",
"Scale factor for sigma in Gaussian kernel");
129 DeclareOptionRef(fKernel =
"Gaus",
"Kernel",
"Use polynomial (=Poln) or Gaussian (=Gaus) kernel");
130 DeclareOptionRef(fTrim =
kFALSE,
"Trim",
"Use equal number of signal and background events");
131 DeclareOptionRef(fUseKernel =
kFALSE,
"UseKernel",
"Use polynomial kernel weight");
132 DeclareOptionRef(fUseWeight =
kTRUE,
"UseWeight",
"Use weight to count kNN events");
133 DeclareOptionRef(fUseLDA =
kFALSE,
"UseLDA",
"Use local linear discriminant - experimental feature");
141 DeclareOptionRef(fTreeOptDepth = 6,
"TreeOptDepth",
"Binary tree optimisation depth");
151 Log() << kWARNING <<
"kNN must be a positive integer: set kNN = " << fnkNN <<
Endl;
153 if (fScaleFrac < 0.0) {
155 Log() << kWARNING <<
"ScaleFrac can not be negative: set ScaleFrac = " << fScaleFrac <<
Endl;
157 if (fScaleFrac > 1.0) {
160 if (!(fBalanceDepth > 0)) {
162 Log() << kWARNING <<
"Optimize must be a positive integer: set Optimize = " << fBalanceDepth <<
Endl;
167 <<
" kNN = \n" << fnkNN
168 <<
" UseKernel = \n" << fUseKernel
169 <<
" SigmaFact = \n" << fSigmaFact
170 <<
" ScaleFrac = \n" << fScaleFrac
171 <<
" Kernel = \n" << fKernel
172 <<
" Trim = \n" << fTrim
173 <<
" Optimize = " << fBalanceDepth <<
Endl;
205 Log() << kFATAL <<
"ModulekNN is not created" <<
Endl;
211 if (fScaleFrac > 0.0) {
218 Log() << kINFO <<
"Creating kd-tree with " << fEvent.size() <<
" events" <<
Endl;
220 for (kNN::EventVec::const_iterator
event = fEvent.begin();
event != fEvent.end(); ++
event) {
221 fModule->Add(*
event);
225 fModule->Fill(
static_cast<UInt_t>(fBalanceDepth),
226 static_cast<UInt_t>(100.0*fScaleFrac),
235 Log() << kHEADER <<
"<Train> start..." <<
Endl;
237 if (IsNormalised()) {
238 Log() << kINFO <<
"Input events are normalized - setting ScaleFrac to 0" <<
Endl;
242 if (!fEvent.empty()) {
243 Log() << kINFO <<
"Erasing " << fEvent.size() <<
" previously stored events" <<
Endl;
246 if (GetNVariables() < 1)
247 Log() << kFATAL <<
"MethodKNN::Train() - mismatched or wrong number of event variables" <<
Endl;
250 Log() << kINFO <<
"Reading " << GetNEvents() <<
" events" <<
Endl;
252 for (
UInt_t ievt = 0; ievt < GetNEvents(); ++ievt) {
254 const Event* evt_ = GetEvent(ievt);
258 if (IgnoreEventsWithNegWeightsInTraining() && weight <= 0)
continue;
261 for (
UInt_t ivar = 0; ivar < evt_ -> GetNVariables(); ++ivar) vvec[ivar] = evt_->
GetValue(ivar);
265 if (DataInfo().IsSignal(evt_)) {
266 fSumOfWeightsS += weight;
270 fSumOfWeightsB += weight;
277 kNN::Event event_knn(vvec, weight, event_type);
279 fEvent.push_back(event_knn);
283 <<
"Number of signal events " << fSumOfWeightsS <<
Endl
284 <<
"Number of background events " << fSumOfWeightsB <<
Endl;
297 NoErrorCalc(err, errUpper);
302 const Event *ev = GetEvent();
303 const Int_t nvar = GetNVariables();
309 for (
Int_t ivar = 0; ivar < nvar; ++ivar) {
317 fModule->Find(event_knn, knn + 2);
319 const kNN::List &rlist = fModule->GetkNNList();
320 if (rlist.size() != knn + 2) {
321 Log() << kFATAL <<
"kNN result list is empty" <<
Endl;
330 Bool_t use_gaus =
false, use_poln =
false;
332 if (fKernel ==
"Gaus") use_gaus =
true;
333 else if (fKernel ==
"Poln") use_poln =
true;
343 if (!(kradius > 0.0)) {
344 Log() << kFATAL <<
"kNN radius is not positive" <<
Endl;
354 std::vector<Double_t> rms_vec;
358 if (rms_vec.empty() || rms_vec.size() != event_knn.
GetNVar()) {
359 Log() << kFATAL <<
"Failed to compute RMS vector" <<
Endl;
365 Double_t weight_all = 0, weight_sig = 0;
367 for (kNN::List::const_iterator lit = rlist.begin(); lit != rlist.end(); ++lit) {
374 if (lit->second < 0.0) {
375 Log() << kFATAL <<
"A neighbor has negative distance to query event" <<
Endl;
377 else if (!(lit->second > 0.0)) {
378 Log() << kVERBOSE <<
"A neighbor has zero distance to query event" <<
Endl;
386 if (fUseWeight) weight_all += evweight;
389 if (node.
GetEvent().GetType() == 1) {
390 if (fUseWeight) weight_sig += evweight;
393 else if (node.
GetEvent().GetType() == 2) {
396 Log() << kFATAL <<
"Unknown type for training event" <<
Endl;
402 if (count_all >= knn) {
408 if (!(count_all > 0)) {
409 Log() << kFATAL <<
"Size kNN result list is not positive" <<
Endl;
414 if (count_all < knn) {
415 Log() << kDEBUG <<
"count_all and kNN have different size: " << count_all <<
" < " << knn <<
Endl;
419 if (!(weight_all > 0.0)) {
420 Log() << kFATAL <<
"kNN result total weight is not positive" <<
Endl;
424 return weight_sig/weight_all;
433 if( fRegressionReturnVal == 0 )
434 fRegressionReturnVal =
new std::vector<Float_t>;
436 fRegressionReturnVal->clear();
441 const Event *evt = GetEvent();
442 const Int_t nvar = GetNVariables();
444 std::vector<float> reg_vec;
448 for (
Int_t ivar = 0; ivar < nvar; ++ivar) {
456 fModule->Find(event_knn, knn + 2);
458 const kNN::List &rlist = fModule->GetkNNList();
459 if (rlist.size() != knn + 2) {
460 Log() << kFATAL <<
"kNN result list is empty" <<
Endl;
461 return *fRegressionReturnVal;
468 for (kNN::List::const_iterator lit = rlist.begin(); lit != rlist.end(); ++lit) {
475 if (reg_vec.empty()) {
479 for(
UInt_t ivar = 0; ivar < tvec.size(); ++ivar) {
480 if (fUseWeight) reg_vec[ivar] += tvec[ivar]*weight;
481 else reg_vec[ivar] += tvec[ivar];
484 if (fUseWeight) weight_all += weight;
490 if (count_all == knn) {
496 if (!(weight_all > 0.0)) {
497 Log() << kFATAL <<
"Total weight sum is not positive: " << weight_all <<
Endl;
498 return *fRegressionReturnVal;
501 for (
UInt_t ivar = 0; ivar < reg_vec.size(); ++ivar) {
502 reg_vec[ivar] /= weight_all;
506 fRegressionReturnVal->insert(fRegressionReturnVal->begin(), reg_vec.begin(), reg_vec.end());
508 return *fRegressionReturnVal;
525 if (fEvent.size()>0)
gTools().
AddAttr(wght,
"NVar",fEvent.begin()->GetNVar());
526 if (fEvent.size()>0)
gTools().
AddAttr(wght,
"NTgt",fEvent.begin()->GetNTgt());
528 for (kNN::EventVec::const_iterator
event = fEvent.begin();
event != fEvent.end(); ++
event) {
530 std::stringstream s(
"");
532 for (
UInt_t ivar = 0; ivar <
event->GetNVar(); ++ivar) {
533 if (ivar>0) s <<
" ";
534 s << std::scientific <<
event->GetVar(ivar);
537 for (
UInt_t itgt = 0; itgt <
event->GetNTgt(); ++itgt) {
538 s <<
" " << std::scientific <<
event->GetTgt(itgt);
551 UInt_t nvar = 0, ntgt = 0;
566 std::stringstream s(
gTools().GetContent(ch) );
568 for(
UInt_t ivar=0; ivar<nvar; ivar++)
571 for(
UInt_t itgt=0; itgt<ntgt; itgt++)
576 kNN::Event event_knn(vvec, evtWeight, evtType, tvec);
577 fEvent.push_back(event_knn);
589 Log() << kINFO <<
"Starting ReadWeightsFromStream(std::istream& is) function..." <<
Endl;
591 if (!fEvent.empty()) {
592 Log() << kINFO <<
"Erasing " << fEvent.size() <<
" previously stored events" <<
Endl;
600 std::getline(is,
line);
602 if (
line.empty() ||
line.find(
"#") != std::string::npos) {
607 std::string::size_type pos=0;
608 while( (pos=
line.find(
',',pos)) != std::string::npos ) { count++; pos++; }
613 if (count < 3 || nvar != count - 2) {
614 Log() << kFATAL <<
"Missing comma delimeter(s)" <<
Endl;
624 std::string::size_type prev = 0;
626 for (std::string::size_type ipos = 0; ipos <
line.size(); ++ipos) {
627 if (
line[ipos] !=
',' && ipos + 1 !=
line.size()) {
631 if (!(ipos > prev)) {
632 Log() << kFATAL <<
"Wrong substring limits" <<
Endl;
635 std::string vstring =
line.substr(prev, ipos - prev);
636 if (ipos + 1 ==
line.size()) {
637 vstring =
line.substr(prev, ipos - prev + 1);
640 if (vstring.empty()) {
641 Log() << kFATAL <<
"Failed to parse string" <<
Endl;
647 else if (vcount == 1) {
648 type = std::atoi(vstring.c_str());
650 else if (vcount == 2) {
651 weight = std::atof(vstring.c_str());
653 else if (vcount - 3 < vvec.size()) {
654 vvec[vcount - 3] = std::atof(vstring.c_str());
657 Log() << kFATAL <<
"Wrong variable count" <<
Endl;
667 Log() << kINFO <<
"Read " << fEvent.size() <<
" events from text file" <<
Endl;
678 Log() << kINFO <<
"Starting WriteWeightsToStream(TFile &rf) function..." <<
Endl;
680 if (fEvent.empty()) {
681 Log() << kWARNING <<
"MethodKNN contains no events " <<
Endl;
691 for (kNN::EventVec::const_iterator it = fEvent.begin(); it != fEvent.end(); ++it) {
702 Log() << kINFO <<
"Wrote " <<
size <<
"MB and " << fEvent.size()
703 <<
" events to ROOT file" <<
Endl;
714 Log() << kINFO <<
"Starting ReadWeightsFromStream(TFile &rf) function..." <<
Endl;
716 if (!fEvent.empty()) {
717 Log() << kINFO <<
"Erasing " << fEvent.size() <<
" previously stored events" <<
Endl;
724 Log() << kFATAL <<
"Failed to find knn tree" <<
Endl;
734 for (
Int_t i = 0; i < nevent; ++i) {
736 fEvent.push_back(*
event);
742 Log() << kINFO <<
"Read " <<
size <<
"MB and " << fEvent.size()
743 <<
" events from ROOT file" <<
Endl;
756 fout <<
" // not implemented for class: \"" << className <<
"\"" << std::endl;
757 fout <<
"};" << std::endl;
771 Log() <<
"The k-nearest neighbor (k-NN) algorithm is a multi-dimensional classification" <<
Endl
772 <<
"and regression algorithm. Similarly to other TMVA algorithms, k-NN uses a set of" <<
Endl
773 <<
"training events for which a classification category/regression target is known. " <<
Endl
774 <<
"The k-NN method compares a test event to all training events using a distance " <<
Endl
775 <<
"function, which is an Euclidean distance in a space defined by the input variables. "<<
Endl
776 <<
"The k-NN method, as implemented in TMVA, uses a kd-tree algorithm to perform a" <<
Endl
777 <<
"quick search for the k events with shortest distance to the test event. The method" <<
Endl
778 <<
"returns a fraction of signal events among the k neighbors. It is recommended" <<
Endl
779 <<
"that a histogram which stores the k-NN decision variable is binned with k+1 bins" <<
Endl
780 <<
"between 0 and 1." <<
Endl;
783 Log() <<
gTools().
Color(
"bold") <<
"--- Performance tuning via configuration options: "
786 Log() <<
"The k-NN method estimates a density of signal and background events in a "<<
Endl
787 <<
"neighborhood around the test event. The method assumes that the density of the " <<
Endl
788 <<
"signal and background events is uniform and constant within the neighborhood. " <<
Endl
789 <<
"k is an adjustable parameter and it determines an average size of the " <<
Endl
790 <<
"neighborhood. Small k values (less than 10) are sensitive to statistical " <<
Endl
791 <<
"fluctuations and large (greater than 100) values might not sufficiently capture " <<
Endl
792 <<
"local differences between events in the training set. The speed of the k-NN" <<
Endl
793 <<
"method also increases with larger values of k. " <<
Endl;
795 Log() <<
"The k-NN method assigns equal weight to all input variables. Different scales " <<
Endl
796 <<
"among the input variables is compensated using ScaleFrac parameter: the input " <<
Endl
797 <<
"variables are scaled so that the widths for central ScaleFrac*100% events are " <<
Endl
798 <<
"equal among all the input variables." <<
Endl;
801 Log() <<
gTools().
Color(
"bold") <<
"--- Additional configuration options: "
804 Log() <<
"The method inclues an option to use a Gaussian kernel to smooth out the k-NN" <<
Endl
805 <<
"response. The kernel re-weights events using a distance to the test event." <<
Endl;
815 if (!(avalue < 1.0)) {
819 const Double_t prod = 1.0 - avalue * avalue * avalue;
821 return (prod * prod * prod);
831 Log() << kFATAL <<
"Mismatched vectors in Gaussian kernel function" <<
Endl;
838 double sum_exp = 0.0;
840 for(
unsigned int ivar = 0; ivar < event_knn.
GetNVar(); ++ivar) {
842 const Double_t diff_ =
event.GetVar(ivar) - event_knn.
GetVar(ivar);
844 if (!(sigm_ > 0.0)) {
845 Log() << kFATAL <<
"Bad sigma value = " << sigm_ <<
Endl;
849 sum_exp += diff_*diff_/(2.0*sigm_*sigm_);
857 return std::exp(-sum_exp);
871 for (kNN::List::const_iterator lit = rlist.begin(); lit != rlist.end(); ++lit)
873 if (!(lit->second > 0.0))
continue;
875 if (kradius < lit->second || kradius < 0.0) kradius = lit->second;
878 if (kcount >= knn)
break;
891 std::vector<Double_t> rvec;
895 for (kNN::List::const_iterator lit = rlist.begin(); lit != rlist.end(); ++lit)
897 if (!(lit->second > 0.0))
continue;
900 const kNN::Event &event_ = node_-> GetEvent();
903 rvec.insert(rvec.end(), event_.
GetNVar(), 0.0);
905 else if (rvec.size() != event_.
GetNVar()) {
906 Log() << kFATAL <<
"Wrong number of variables, should never happen!" <<
Endl;
911 for(
unsigned int ivar = 0; ivar < event_.
GetNVar(); ++ivar) {
913 rvec[ivar] += diff_*diff_;
917 if (kcount >= knn)
break;
921 Log() << kFATAL <<
"Bad event kcount = " << kcount <<
Endl;
926 for(
unsigned int ivar = 0; ivar < rvec.size(); ++ivar) {
927 if (!(rvec[ivar] > 0.0)) {
928 Log() << kFATAL <<
"Bad RMS value = " << rvec[ivar] <<
Endl;
933 rvec[ivar] = std::abs(fSigmaFact)*std::sqrt(rvec[ivar]/kcount);
945 for (kNN::List::const_iterator lit = rlist.begin(); lit != rlist.end(); ++lit) {
951 if (node.
GetEvent().GetType() == 1) {
952 sig_vec.push_back(tvec);
954 else if (node.
GetEvent().GetType() == 2) {
955 bac_vec.push_back(tvec);
958 Log() << kFATAL <<
"Unknown type for training event" <<
Endl;
962 fLDA.Initialize(sig_vec, bac_vec);
964 return fLDA.GetProb(event_knn.
GetVars(), 1);
#define REGISTER_METHOD(CLASS)
for example
std::vector< std::vector< Float_t > > LDAEvents
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
short Short_t
Signed Short integer 2 bytes (short)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Int_t WriteTObject(const TObject *obj, const char *name=nullptr, Option_t *option="", Int_t bufsize=0) override
Write object obj to this directory.
TObject * Get(const char *namecycle) override
Return pointer to object identified by namecycle.
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Class that contains all the data information.
Float_t GetValue(UInt_t ivar) const
return value of i'th variable
std::vector< Float_t > & GetTargets()
Double_t GetWeight() const
return the event weight - depending on whether the flag IgnoreNegWeightsInTraining is or not.
Virtual base Class for all MVA method.
virtual void DeclareCompatibilityOptions()
options that are used ONLY for the READER to ensure backward compatibility they are hence without any...
Analysis of k-nearest neighbor.
void MakeKNN(void)
create kNN
virtual ~MethodKNN(void)
destructor
const std::vector< Double_t > getRMS(const kNN::List &rlist, const kNN::Event &event_knn) const
Get polynomial kernel radius.
const Ranking * CreateRanking() override
no ranking available
void DeclareOptions() override
MethodKNN options.
MethodKNN(const TString &jobName, const TString &methodTitle, DataSetInfo &theData, const TString &theOption="KNN")
standard constructor
Double_t getKernelRadius(const kNN::List &rlist) const
Get polynomial kernel radius.
void Train(void) override
kNN training
double getLDAValue(const kNN::List &rlist, const kNN::Event &event_knn)
void ProcessOptions() override
process the options specified by the user
Double_t PolnKernel(Double_t value) const
polynomial kernel
void DeclareCompatibilityOptions() override
options that are used ONLY for the READER to ensure backward compatibility
void ReadWeightsFromStream(std::istream &istr) override
read the weights
void GetHelpMessage() const override
get help message text
void MakeClassSpecific(std::ostream &, const TString &) const override
write specific classifier response
Double_t GetMvaValue(Double_t *err=nullptr, Double_t *errUpper=nullptr) override
Compute classifier response.
Bool_t HasAnalysisType(Types::EAnalysisType type, UInt_t numberClasses, UInt_t numberTargets) override
FDA can handle classification with 2 classes and regression with one regression-target.
void Init(void) override
Initialization.
void WriteWeightsToStream(TFile &rf) const
save weights to ROOT file
Double_t GausKernel(const kNN::Event &event_knn, const kNN::Event &event, const std::vector< Double_t > &svec) const
Gaussian kernel.
void ReadWeightsFromXML(void *wghtnode) override
const std::vector< Float_t > & GetRegressionValues() override
Return vector of averages for target values of k-nearest neighbors.
void AddWeightsXMLTo(void *parent) const override
write weights to XML
Ranking for variables in method (implementation)
Singleton class for Global types used by TMVA.
void SetTargets(const VarVec &tvec)
VarType GetVar(UInt_t i) const
const VarVec & GetVars() const
This file contains binary tree and global function template that searches tree for k-nearest neigbors...
Double_t GetWeight() const
const T & GetEvent() const
std::vector< VarType > VarVec
virtual void Clear(Option_t *="")
A TTree represents a columnar dataset.
virtual Int_t Fill()
Fill all branches.
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr, bool suppressMissingBranchError)
virtual Int_t GetEntry(Long64_t entry, Int_t getall=0)
Read all branches of entry and return total number of bytes read.
virtual void SetDirectory(TDirectory *dir)
Change the tree's directory.
virtual Long64_t GetEntries() const
TBranch * Branch(const char *name, T *obj, Int_t bufsize=32000, Int_t splitlevel=99)
Add a new branch, and infer the data type from the type of obj being passed.
create variable transformations
MsgLogger & Endl(MsgLogger &ml)
Double_t Sqrt(Double_t x)
Returns the square root of x.
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.