Feature Selection Toolbox FST4
UTIA · Czech Academy of Sciences
Loading...
Searching...
No Matches
result_tracker_feature_stats.hpp
Go to the documentation of this file.
1#ifndef FSTRESULTTRACKERFEATURESTATS_H
2#define FSTRESULTTRACKERFEATURESTATS_H
3 /*
27=========================================================================
28Copyright and license:
29 * FST4 software (with the exception of any bundled or externally linked
30 third-party components) is Copyright (C) 2000-present Institute of
31 Information Theory and Automation of the Czech Academy of Sciences (UTIA).
32 * FST4 is free software: you can redistribute it and/or modify it under
33 the terms of the GNU Affero General Public License as published by the
34 Free Software Foundation, version 3. The full text of the license is in
35 the file LICENSE in the distribution root and at
36 https://www.gnu.org/licenses/agpl-3.0.html.
37 * FST4 is distributed in the hope that it will be useful, but WITHOUT ANY
38 WARRANTY; without even the implied warranty of MERCHANTABILITY or
39 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
40 License for more details.
41 * Closed-source use without the AGPL's copyleft obligations requires a
42 commercial license from UTIA; in case of interest write to
43 utia@utia.cas.cz. LICENSING.md in the distribution root explains both
44 options, the contributor license agreement that every contribution
45 requires, and the contacts (technical questions and pull requests:
46 somol@utia.cas.cz, with "FST" in the subject line).
47========================================================================== */
48
49#include <memory>
50#include <cassert>
51#ifdef FST_THREADED
52#include <mutex>
53#endif
54#include <iostream>
55#include <sstream>
56#include <list>
57#include <vector>
58#include <algorithm>
59#include <cstddef>
60#include "error.hpp"
61#include "global.hpp"
63
64/*============== Template parameter type naming conventions ==============
65--------- Numeric types: -------------------------------------------------
66DATATYPE - data sample values - usually real numbers (but may be integers
67 in text processing etc.)
68REALTYPE - must be real numbers - for representing intermediate results of
69 calculations like mean, covariance etc.
70IDXTYPE - index values for enumeration of data samples - (nonnegative) integers,
71 extent depends on numbers of samples in data
72DIMTYPE - index values for enumeration of features (dimensions), or classes (not
73 class sizes) - (nonnegative) integers, usually lower extent than IDXTYPE,
74 but be aware of expressions like _classes*_features*_features !
75 in linearized representations of feature matrices for all classes
76BINTYPE - feature selection marker type - represents ca. <10 different feature
77 states (selected, deselected, sel./desel. temporarily 1st nested loop, 2nd...)
78RETURNTYPE - criterion value: real value, but may be extended in future to support
79 multiple values
80--------- Class types: ---------------------------------------------------
81SUBSET - class of class type Subset
82CLASSIFIER - class implementing interface defined in abstract class Classifier
83EVALUATOR - class implementing interface defined in abstract class Sequential_Step
84DISTANCE - class implementing interface defined in abstract class Distance
85DATAACCESSOR - class implementing interface defined in abstract class Data_Accessor
86INTERVALCONTAINER - class of class type Data_Intervaller
87CONTAINER - STL container of class type Data_Interval
88========================================================================== */
89
90namespace FST {
91
108template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
109class Result_Tracker_Feature_Stats : public Clonable_Impl<Result_Tracker_Feature_Stats<RETURNTYPE,IDXTYPE,DIMTYPE,SUBSET>,Result_Tracker_Dupless<RETURNTYPE,IDXTYPE,DIMTYPE,SUBSET>,CLONE_INHERIT,CLONE_INHERIT,CLONE_DEEP> {
110public:
113 typedef typename parent::ResultRec ResultRec;
115 typedef std::shared_ptr<SUBSET> PSubset;
117 Result_Tracker_Feature_Stats(const IDXTYPE capacity_limit=0):parent_impl(capacity_limit), _n(0), _pair_itersize(0) {_itersize[0]=0; _itersize[1]=0; _itersize[2]=0; notify("Result_Tracker_Feature_Stats constructor.");}
118 Result_Tracker_Feature_Stats(const Result_Tracker_Feature_Stats& rtfs):parent_impl(rtfs), _n(0), _pair_itersize(0) {_itersize[0]=0; _itersize[1]=0; _itersize[2]=0; notify("Result_Tracker_Feature_Stats copy-constructor.");}
119 virtual ~Result_Tracker_Feature_Stats() {notify("Result_Tracker_Feature_Stats destructor.");}
120
138 bool compute_stats(std::ostream& os=std::cout);
141 bool print_stats(std::ostream& os=std::cout);
142
150 bool getFirstDAF(RETURNTYPE &value, DIMTYPE &feature, const unsigned int DAFidx=0) const;
153 bool getNextDAF(RETURNTYPE &value, DIMTYPE &feature, const unsigned int DAFidx=0) const;
154
155 // ---- opt-in pairwise (group) DAF statistics ----
177 bool compute_pair_stats(const DIMTYPE top_k, std::ostream& os=std::cout);
182 bool print_pair_stats(std::ostream& os=std::cout, const std::size_t top_pairs=0);
191 bool getFirstPairDAF(RETURNTYPE &daf0, RETURNTYPE &daf1, bool &daf1_valid, RETURNTYPE &synergy, DIMTYPE &f1, DIMTYPE &f2) const;
194 bool getNextPairDAF(RETURNTYPE &daf0, RETURNTYPE &daf1, bool &daf1_valid, RETURNTYPE &synergy, DIMTYPE &f1, DIMTYPE &f2) const;
195
196
197
198 virtual std::ostream& print(std::ostream& os) const override {os << "Result_Tracker_Feature_Stats(limit=" << parent::_capacity_limit << ") size " << parent::results.size(); return os;}
199
200protected:
201 DIMTYPE _n;
203 typedef struct {
204 RETURNTYPE freq_is;
205 RETURNTYPE freq_isnot;
206 RETURNTYPE mean_is;
207 RETURNTYPE mean_isnot;
208 RETURNTYPE stdev_is;
209 RETURNTYPE stdev_isnot;
213 RETURNTYPE daf[3];
214 bool daf_valid[3];
215 } FeatureStat;
216 std::vector<FeatureStat> _stats;
217
219 typedef struct {
220 RETURNTYPE freq;
221 RETURNTYPE mean;
222 RETURNTYPE stdev;
223 bool valid;
224 } SubSizeStat;
225 std::vector<SubSizeStat> _dstat;
226
227 typedef std::vector<DIMTYPE> ORDERTYPE;
229 mutable DIMTYPE _itersize[3];
230#ifdef FST_THREADED
231 mutable std::mutex _itersize_mutex;
232#endif
233
235 typedef struct {
236 DIMTYPE f1;
237 DIMTYPE f2;
238 RETURNTYPE freq_both;
239 RETURNTYPE freq_neither;
240 RETURNTYPE daf0;
241 RETURNTYPE daf1;
242 RETURNTYPE synergy;
243 bool valid;
245 } PairStat;
246 std::vector<PairStat> _pair_stats;
247 std::vector<DIMTYPE> _pair_features;
248 std::vector<std::size_t> _pair_order;
249 mutable std::size_t _pair_itersize;
251 static std::size_t pair_index(const std::size_t a, const std::size_t b, const std::size_t k) {assert(a<b && b<k); return a*k - a*(a+1)/2 + (b-a-1);}
252};
253
254
255
256template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
258{
259 if(parent::results.empty()) return false;
260
261 typename parent::CONSTRESULTSITER iter=parent::results.begin();
262 // get n from first recorded sub (assumes all others have the same n)
263 _n=iter->sub->get_n();
264 _stats.resize(_n);
265 for(DIMTYPE f=0;f<_n;f++) {
266 _stats[f].freq_is=_stats[f].freq_isnot=_stats[f].mean_is=_stats[f].mean_isnot=_stats[f].stdev_is=_stats[f].stdev_isnot=0;
267 _stats[f].daf_valid[0]=false;
268 _stats[f].daf_valid[1]=false;
269 _stats[f].daf_valid[2]=false;
270 }
271 _dstat.resize(_n+1);
272 for(DIMTYPE ss=1;ss<=_n;ss++) {
273 _dstat[ss].mean=_dstat[ss].stdev=_dstat[ss].freq=0;
274 _dstat[ss].valid=false;
275 }
276
277 if(parent::output_normal()) {std::ostringstream sos; sos << std::endl << "compute_stats() 1/4.." << std::endl << std::flush; syncout::print(os,sos);}
278 // gather initial stats
279 for(iter=parent::results.begin();iter!=parent::results.end();iter++)
280 {
281 assert(iter->sub->get_n()==_n);
282 DIMTYPE d=iter->sub->get_d();
283 assert(d>0 && d<=_n);
284 for(DIMTYPE f=0;f<_n;f++) {
285 if(iter->sub->selected_raw(f)) {
286 _stats[f].freq_is++;
287 _stats[f].mean_is+=iter->value;
288 } else {
289 _stats[f].freq_isnot++;
290 _stats[f].mean_isnot+=iter->value;
291 }
292 }
293 _dstat[d].mean+=iter->value;
294 _dstat[d].freq++;
295 }
296
297 // calculate mean values
298 for(DIMTYPE f=0;f<_n;f++)
299 {
300 if(_stats[f].freq_is>0) _stats[f].mean_is/=_stats[f].freq_is;
301 if(_stats[f].freq_isnot>0) _stats[f].mean_isnot/=_stats[f].freq_isnot;
302 }
303 for(DIMTYPE ss=1;ss<=_n;ss++) if(_dstat[ss].freq>0) {
304 _dstat[ss].mean/=_dstat[ss].freq;
305 }
306 if(parent::output_normal()) {std::ostringstream sos; sos << "compute_stats() 2/4.." << std::endl << std::flush; syncout::print(os,sos);}
307
308 // gather more stats
309 for(iter=parent::results.begin();iter!=parent::results.end();iter++)
310 {
311 assert(iter->sub->get_n()==_n);
312 DIMTYPE d=iter->sub->get_d();
313 assert(d>0 && d<=_n);
314 for(DIMTYPE f=0;f<_n;f++) {
315 if(iter->sub->selected_raw(f)) {
316 _stats[f].stdev_is+=(_stats[f].mean_is-iter->value)*(_stats[f].mean_is-iter->value);
317 } else {
318 _stats[f].stdev_isnot+=(_stats[f].mean_isnot-iter->value)*(_stats[f].mean_isnot-iter->value);
319 }
320 }
321 _dstat[d].stdev+=(_dstat[d].mean-iter->value)*(_dstat[d].mean-iter->value);
322 }
323
324 // calculate stddev values
325 for(DIMTYPE f=0;f<_n;f++)
326 {
327 if(_stats[f].freq_is>0) _stats[f].stdev_is=sqrt(_stats[f].stdev_is/_stats[f].freq_is);
328 // each guard must test the SAME frequency its line divides by: guarding the 'isnot'
329 // line with freq_is would leave stdev_isnot unnormalized, or divide it by zero
330 if(_stats[f].freq_isnot>0) _stats[f].stdev_isnot=sqrt(_stats[f].stdev_isnot/_stats[f].freq_isnot);
331 }
332 for(DIMTYPE ss=1;ss<=_n;ss++) if(_dstat[ss].freq>0) {
333 _dstat[ss].stdev=sqrt(_dstat[ss].stdev/_dstat[ss].freq);
334 _dstat[ss].valid=true;
335 }
336
337
338 if(parent::output_normal()) {std::ostringstream sos; sos << "compute_stats() 3/4.." << std::endl << std::flush; syncout::print(os,sos);}
339 // calculate DAF ranks
340 for(DIMTYPE f=0;f<_n;f++)
341 {
342 // DAF0 needs only both partitions to be non-empty, but it deliberately shares DAF1's
343 // validity test: a feature whose criterion values never vary at all carries no evidence,
344 // so ranking it alongside features that do would be misleading
345 if(_stats[f].freq_is>0 && _stats[f].freq_isnot>0 && (_stats[f].stdev_is>0 || _stats[f].stdev_isnot>0) )
346 {
347 RETURNTYPE freq=_stats[f].freq_is+_stats[f].freq_isnot;
348 //DAF1
349 _stats[f].daf[1]=(_stats[f].mean_is-_stats[f].mean_isnot)/( (_stats[f].freq_is/freq)*_stats[f].stdev_is + (_stats[f].freq_isnot/freq)*_stats[f].stdev_isnot );
350 _stats[f].daf_valid[1]=true;
351 //DAF0
352 _stats[f].daf[0]=_stats[f].mean_is-_stats[f].mean_isnot;
353 _stats[f].daf_valid[0]=true;
354 }
355 else _stats[f].daf_valid[1]=_stats[f].daf_valid[0]=false;
356 }
357 // DAF2: like DAF0, but every probe's value is first divided by the stdev of all probes of
358 // the SAME cardinality, which removes the systematic level difference between small and
359 // large subsets. Probes of a cardinality whose stdev is 0 contribute nothing, so a feature
360 // can end up with no usable probe on one side - its DAF2 is then 0 (but still marked
361 // valid, unlike DAF0/DAF1). mi1/mi2/cnt1/cnt2 are indexed by FEATURE, 0.._n-1.
362 std::vector<RETURNTYPE> mi1,mi2; mi1.resize(_n); mi2.resize(_n);
363 std::vector<IDXTYPE> cnt1,cnt2; cnt1.resize(_n); cnt2.resize(_n);
364 for(DIMTYPE f=0;f<_n;f++) {mi1[f]=mi2[f]=0; cnt1[f]=cnt2[f]=0;}
365 for(iter=parent::results.begin();iter!=parent::results.end();iter++)
366 {
367 assert(iter->sub->get_n()==_n);
368 DIMTYPE d=iter->sub->get_d();
369 assert(d>0 && d<=_n);
370
371 if(_dstat[d].stdev>0) {
372 for(DIMTYPE f=0;f<_n;f++) {
373 if(iter->sub->selected_raw(f)) {mi1[f]+=iter->value/_dstat[d].stdev; cnt1[f]++;}
374 else {mi2[f]+=iter->value/_dstat[d].stdev; cnt2[f]++;}
375 }
376 }
377 }
378 for(DIMTYPE f=0;f<_n;f++) {
379 if(cnt1[f]==0 || cnt2[f]==0) _stats[f].daf[2]=0; else
380 {
381 mi1[f]/=cnt1[f];
382 mi2[f]/=cnt2[f];
383 _stats[f].daf[2]=mi1[f]-mi2[f];
384 }
385 _stats[f].daf_valid[2]=true;
386 }
387
388 if(parent::output_normal()) {std::ostringstream sos; sos << "compute_stats() 4/4.." << std::endl << std::endl << std::flush; syncout::print(os,sos);}
389
390 // order features according to DAF0, DAF1 and DAF2
391 for(unsigned int DAFidx=0; DAFidx<3; DAFidx++)
392 {
393 _order[DAFidx].clear();
394 for(DIMTYPE f=0;f<_n;f++)
395 {
396 if(_stats[f].daf_valid[DAFidx]) {
397 typename ORDERTYPE::iterator iter=_order[DAFidx].begin();
398 while(iter!=_order[DAFidx].end() && _stats[f].daf[DAFidx]<_stats[*iter].daf[DAFidx]) iter++;
399 _order[DAFidx].insert(iter,f);
400 }
401 }
402 if(_order[DAFidx].size()<_n && parent::output_normal()) {std::ostringstream sos; sos << "WARNING: DAF"<<DAFidx<<" rank could not be computed for all features due to insufficient number of evaluated probe subsets." << std::endl << std::flush; syncout::print(os,sos);}
403 }
405 RETURNTYPE minfreq=_stats[0].freq_is; if(_stats[0].freq_isnot<_stats[0].freq_is) minfreq=_stats[0].freq_isnot;
406 for(DIMTYPE f=1;f<_n;f++) {
407 if(_stats[f].freq_isnot<minfreq) minfreq=_stats[f].freq_isnot;
408 if(_stats[f].freq_is<minfreq) minfreq=_stats[f].freq_is;
409 }
410 {
411 std::ostringstream sos;
412 sos << "Lowest feature evaluation frequency over all probes is "<<minfreq<<"." << std::endl;
413 if(minfreq<100) sos << "WARNING: To ensure reliable DAF estimates the minimum feature evaluation frequency should be at least in the order of hundreds. More probes may be needed." << std::endl;
414 sos << std::endl << std::flush;
415 syncout::print(os,sos);
416 }
417 }
418
419 return true;
420}
421
422template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
424{
425 std::ostringstream sos;
426 if(_n<1) {sos << "Result_Tracker_Feature_Stats:: Nothing to print out." << std::endl; syncout::print(os,sos); return false;}
427 {
428 sos << "Probe subset stats for each (valid) cardinality:"<< std::endl;
429 for(DIMTYPE ss=1;ss<=_n;ss++)
430 if(_dstat[ss].valid) sos << " d: "<< ss << " mean=" << _dstat[ss].mean << ", stddev=" << _dstat[ss].stdev << ", freq=" << _dstat[ss].freq << std::endl;
431 sos << std::endl << "Feature stats over all probe subsets:"<< std::endl;
432 for(DIMTYPE f=0;f<_n;f++) {
433 sos << " F:"<<f<< " daf0 = "; if(_stats[f].daf_valid[0]) sos << _stats[f].daf[0]; else sos << "n/a";
434 sos << ", daf1 = "; if(_stats[f].daf_valid[1]) sos << _stats[f].daf[1]; else sos << "n/a";
435 sos << ", daf2 = "; if(_stats[f].daf_valid[2]) sos << _stats[f].daf[2]; else sos << "n/a";
436 sos<<", freq "<<_stats[f].freq_is<<"|"<<_stats[f].freq_isnot<<", mean ";
437 if(_stats[f].freq_is>0) sos<<_stats[f].mean_is; else sos<< "n/a";
438 sos <<"|";
439 if(_stats[f].freq_isnot>0) sos<<_stats[f].mean_isnot; else sos<< "n/a";
440 sos<<", stdev ";
441 if(_stats[f].freq_is>0) sos<<_stats[f].stdev_is; else sos<<"n/a";
442 sos<<"|";
443 if(_stats[f].freq_isnot>0) sos<<_stats[f].stdev_isnot; else sos << "n/a";
444 sos<<std::endl;
445 }
446 sos<<std::endl;
447 }
448 syncout::print(os,sos);
449 return true;
450}
451
452template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
453bool Result_Tracker_Feature_Stats<RETURNTYPE, IDXTYPE, DIMTYPE, SUBSET>::getFirstDAF(RETURNTYPE &value, DIMTYPE &feature, const unsigned int DAFidx) const
454{
455 assert(DAFidx<3);
456#ifdef FST_THREADED
457 std::unique_lock<std::mutex> lock(_itersize_mutex);
458#endif
459 _itersize[DAFidx]=0;
460 if(!_order[DAFidx].empty()) {
461 feature=_order[DAFidx][0];
462 assert(feature<_n);
463 value=_stats[feature].daf[DAFidx];
464 _itersize[DAFidx]=1;
465 return true;
466 } else return false;
467}
468
469template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
470bool Result_Tracker_Feature_Stats<RETURNTYPE, IDXTYPE, DIMTYPE, SUBSET>::getNextDAF(RETURNTYPE &value, DIMTYPE &feature, const unsigned int DAFidx) const
471{
472 assert(DAFidx<3);
473#ifdef FST_THREADED
474 std::unique_lock<std::mutex> lock(_itersize_mutex);
475#endif
476 if(0<_itersize[DAFidx] && _itersize[DAFidx]<_order[DAFidx].size()) {
477 feature=_order[DAFidx][_itersize[DAFidx]];
478 assert(feature<_n);
479 value=_stats[feature].daf[DAFidx];
480 ++_itersize[DAFidx];
481 return true;
482 }
483 return false;
484}
485
486template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
488{
489 _pair_stats.clear(); _pair_features.clear(); _pair_order.clear(); _pair_itersize=0;
490 if(parent::results.empty() || _n<1 || _order[0].empty()) return false; // compute_stats() must have run first
491 if(top_k<2) return false;
492 const std::size_t K = std::min<std::size_t>(top_k, _order[0].size());
493 if(K<2) return false;
494
495 // the top-K DAF0-ranked features define the pair set; local index <-> global feature
496 _pair_features.resize(K);
497 for(std::size_t k=0;k<K;k++) _pair_features[k]=_order[0][k];
498
499 // accumulation pass: only the both-present cell needs per-probe work; the
500 // one-only and both-absent cells derive by inclusion-exclusion below
501 const std::size_t P=K*(K-1)/2;
502 std::vector<RETURNTYPE> both_freq(P,0), both_sum(P,0), both_sumsq(P,0);
503 std::vector<RETURNTYPE> f_freq(K,0), f_sum(K,0), f_sumsq(K,0);
504 RETURNTYPE t_freq=0, t_sum=0, t_sumsq=0;
505 std::vector<std::size_t> present; present.reserve(K);
506 for(typename parent::CONSTRESULTSITER iter=parent::results.begin();iter!=parent::results.end();iter++)
507 {
508 assert(iter->sub->get_n()==_n);
509 const RETURNTYPE v=iter->value;
510 t_freq+=1; t_sum+=v; t_sumsq+=v*v;
511 present.clear();
512 for(std::size_t k=0;k<K;k++) if(iter->sub->selected_raw(_pair_features[k])) present.push_back(k);
513 for(std::size_t i=0;i<present.size();i++) {
514 const std::size_t a=present[i];
515 f_freq[a]+=1; f_sum[a]+=v; f_sumsq[a]+=v*v;
516 for(std::size_t j=i+1;j<present.size();j++) {
517 const std::size_t ij=pair_index(a,present[j],K);
518 both_freq[ij]+=1; both_sum[ij]+=v; both_sumsq[ij]+=v*v;
519 }
520 }
521 }
522
523 // derive the 2x2 cells and the pair indicators
524 _pair_stats.resize(P);
525 std::size_t valid_count=0;
526 for(std::size_t a=0;a<K;a++) for(std::size_t b=a+1;b<K;b++) {
527 const std::size_t ij=pair_index(a,b,K);
528 PairStat &ps=_pair_stats[ij];
529 ps.f1=_pair_features[a]; ps.f2=_pair_features[b];
530 const RETURNTYPE fb=both_freq[ij], sb=both_sum[ij], qb=both_sumsq[ij];
531 const RETURNTYPE f1o=f_freq[a]-fb, s1o=f_sum[a]-sb; // f1 present, f2 absent
532 const RETURNTYPE f2o=f_freq[b]-fb, s2o=f_sum[b]-sb; // f2 present, f1 absent
533 const RETURNTYPE fn=t_freq-f_freq[a]-f_freq[b]+fb; // neither present
534 const RETURNTYPE sn=t_sum-f_sum[a]-f_sum[b]+sb;
535 const RETURNTYPE qn=t_sumsq-f_sumsq[a]-f_sumsq[b]+qb;
536 ps.freq_both=fb; ps.freq_neither=fn;
537 ps.daf0=ps.daf1=ps.synergy=0;
538 ps.valid=(fb>0 && fn>0 && f1o>0 && f2o>0);
539 ps.daf1_valid=false;
540 if(ps.valid) {
541 const RETURNTYPE mb=sb/fb, mn=sn/fn, m1o=s1o/f1o, m2o=s2o/f2o;
542 ps.daf0=mb-mn;
543 ps.synergy=mb+mn-m1o-m2o;
544 RETURNTYPE vb=qb/fb-mb*mb; if(vb<0) vb=0; // guard FP negatives
545 RETURNTYPE vn=qn/fn-mn*mn; if(vn<0) vn=0;
546 const RETURNTYPE denom=(fb/(fb+fn))*sqrt(vb) + (fn/(fb+fn))*sqrt(vn);
547 if(denom>0) {ps.daf1=ps.daf0/denom; ps.daf1_valid=true;}
548 ++valid_count;
549 }
550 }
551
552 // order valid pairs by decreasing pair-DAF0 (deterministic tie-break on feature indices)
553 _pair_order.reserve(valid_count);
554 for(std::size_t ij=0;ij<P;ij++) if(_pair_stats[ij].valid) _pair_order.push_back(ij);
555 std::sort(_pair_order.begin(),_pair_order.end(),[this](const std::size_t x, const std::size_t y)->bool {
556 if(_pair_stats[x].daf0!=_pair_stats[y].daf0) return _pair_stats[x].daf0>_pair_stats[y].daf0;
557 if(_pair_stats[x].f1!=_pair_stats[y].f1) return _pair_stats[x].f1<_pair_stats[y].f1;
558 return _pair_stats[x].f2<_pair_stats[y].f2;
559 });
560
562 std::ostringstream sos;
563 sos << "compute_pair_stats(): pairwise stats over the top " << K << " DAF0-ranked features (" << P << " pairs, " << valid_count << " valid)." << std::endl;
564 if(valid_count<P) sos << "WARNING: " << (P-valid_count) << " pairs have an empty presence cell (insufficient probes); they carry no pair-DAF value." << std::endl;
565 sos << std::flush;
566 syncout::print(os,sos);
567 }
568 return valid_count>0;
569}
570
571template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
573{
574 std::ostringstream sos;
575 if(_pair_order.empty()) {sos << "Result_Tracker_Feature_Stats:: No pairwise stats to print out." << std::endl; syncout::print(os,sos); return false;}
576 const std::size_t count = (top_pairs==0 || top_pairs>_pair_order.size()) ? _pair_order.size() : top_pairs;
577 sos << "Pairwise DAF stats over the top " << _pair_features.size() << " DAF0-ranked features (showing " << count << " of " << _pair_order.size() << " valid pairs, best pair-DAF0 first):" << std::endl;
578 for(std::size_t i=0;i<count;i++) {
579 const PairStat &ps=_pair_stats[_pair_order[i]];
580 sos << " P:("<<ps.f1<<","<<ps.f2<<") pairdaf0 = " << ps.daf0;
581 sos << ", pairdaf1 = "; if(ps.daf1_valid) sos << ps.daf1; else sos << "n/a";
582 sos << ", synergy = " << ps.synergy;
583 sos << ", freq both|neither " << ps.freq_both << "|" << ps.freq_neither << std::endl;
584 }
585 sos << std::endl;
586 syncout::print(os,sos);
587 return true;
588}
589
590template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
591bool Result_Tracker_Feature_Stats<RETURNTYPE, IDXTYPE, DIMTYPE, SUBSET>::getFirstPairDAF(RETURNTYPE &daf0, RETURNTYPE &daf1, bool &daf1_valid, RETURNTYPE &synergy, DIMTYPE &f1, DIMTYPE &f2) const
592{
593#ifdef FST_THREADED
594 std::unique_lock<std::mutex> lock(_itersize_mutex);
595#endif
597 if(!_pair_order.empty()) {
598 const PairStat &ps=_pair_stats[_pair_order[0]];
599 daf0=ps.daf0; daf1=ps.daf1; daf1_valid=ps.daf1_valid; synergy=ps.synergy; f1=ps.f1; f2=ps.f2;
601 return true;
602 } else return false;
603}
604
605template<class RETURNTYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET>
606bool Result_Tracker_Feature_Stats<RETURNTYPE, IDXTYPE, DIMTYPE, SUBSET>::getNextPairDAF(RETURNTYPE &daf0, RETURNTYPE &daf1, bool &daf1_valid, RETURNTYPE &synergy, DIMTYPE &f1, DIMTYPE &f2) const
607{
608#ifdef FST_THREADED
609 std::unique_lock<std::mutex> lock(_itersize_mutex);
610#endif
613 daf0=ps.daf0; daf1=ps.daf1; daf1_valid=ps.daf1_valid; synergy=ps.synergy; f1=ps.f1; f2=ps.f2;
615 return true;
616 }
617 return false;
618}
619
620
621} // namespace
622#endif // FSTRESULTTRACKERFEATURESTATS_H ///:~
CRTP mixin implementing the Clonable protocol for a concrete class.
Definition clonable.hpp:184
Collects multiple results, avoiding duplicates.
Definition result_tracker_dupless.hpp:92
RESULTSITER end()
iterator past the last held result
Definition result_tracker_dupless.hpp:147
parent::ResultRec ResultRec
see Result_Tracker::ResultRec
Definition result_tracker_dupless.hpp:96
std::list< ResultRec > results
held results, sorted descending by value (ties broken toward the smaller subset); see add() for the e...
Definition result_tracker_dupless.hpp:138
const IDXTYPE _capacity_limit
set by the constructor; 0 = unlimited
Definition result_tracker_dupless.hpp:141
std::list< ResultRec >::const_iterator CONSTRESULTSITER
read-only iterator over results, for use by subclasses/friends inspecting the collected results
Definition result_tracker_dupless.hpp:144
RESULTSITER begin()
iterator to the best (first) held result
Definition result_tracker_dupless.hpp:146
virtual std::size_t size() const override
number of results currently held (std::size_t rather than 'long': on LLP64 platforms 'long' is 32 bit...
Definition result_tracker_dupless.hpp:125
Collects evaluated subsets to eventually provide Dependency-Aware Feature Ranking coefficients.
Definition result_tracker_feature_stats.hpp:109
std::vector< DIMTYPE > ORDERTYPE
feature-index ordering vector, as built per DAF variant by compute_stats()
Definition result_tracker_feature_stats.hpp:227
std::vector< std::size_t > _pair_order
indices into _pair_stats, valid pairs only, sorted decreasing pair-DAF0
Definition result_tracker_feature_stats.hpp:248
DIMTYPE _itersize[3]
per DAF variant: getFirstDAF()/getNextDAF() cursor position (index into _order[DAFidx]); 0 = iteratio...
Definition result_tracker_feature_stats.hpp:229
std::vector< SubSizeStat > _dstat
one entry per subset size 1.._n (index 0 unused); filled by compute_stats()
Definition result_tracker_feature_stats.hpp:225
bool getNextDAF(RETURNTYPE &value, DIMTYPE &feature, const unsigned int DAFidx=0) const
Definition result_tracker_feature_stats.hpp:470
std::vector< DIMTYPE > _pair_features
the top-k DAF0-ranked (global) feature indices the pairs are drawn from
Definition result_tracker_feature_stats.hpp:247
bool compute_stats(std::ostream &os=std::cout)
Aggregates DAF ranking statistics (DAF0/DAF1/DAF2) from all probe subsets recorded so far.
Definition result_tracker_feature_stats.hpp:257
bool getFirstDAF(RETURNTYPE &value, DIMTYPE &feature, const unsigned int DAFidx=0) const
Starts an iteration (descending by value) over the feature ordering built by compute_stats() for the ...
Definition result_tracker_feature_stats.hpp:453
parent::ResultRec ResultRec
[subset,criterion value] result record, see Result_Tracker::ResultRec
Definition result_tracker_feature_stats.hpp:113
Result_Tracker_Dupless< RETURNTYPE, IDXTYPE, DIMTYPE, SUBSET > parent
the base tracker: dupless probe storage sorted descending by criterion value; this class adds DAF pos...
Definition result_tracker_feature_stats.hpp:111
std::mutex _itersize_mutex
serializes access to the iteration cursors _itersize AND _pair_itersize across concurrent getFirst/ge...
Definition result_tracker_feature_stats.hpp:231
bool compute_pair_stats(const DIMTYPE top_k, std::ostream &os=std::cout)
Computes pairwise (group) DAF statistics: 2x2 presence-cell contrasts over all pairs of the top top_k...
Definition result_tracker_feature_stats.hpp:487
ORDERTYPE _order[3]
per DAF variant (0=DAF0, 1=DAF1, 2=DAF2): feature indices with a valid DAF value, sorted descending b...
Definition result_tracker_feature_stats.hpp:228
bool print_pair_stats(std::ostream &os=std::cout, const std::size_t top_pairs=0)
Definition result_tracker_feature_stats.hpp:572
static std::size_t pair_index(const std::size_t a, const std::size_t b, const std::size_t k)
Upper-triangle linearization of pair (a,b), a<b<k, into a flat index over PairStat storage (k = the t...
Definition result_tracker_feature_stats.hpp:251
virtual std::ostream & print(std::ostream &os) const override
writes a human-readable identification of the object; base default writes nothing
Definition result_tracker_feature_stats.hpp:198
DIMTYPE _n
Definition result_tracker_feature_stats.hpp:201
ResultRec * PResultRec
raw pointer to a ResultRec, as used by the inherited get_first()/get_next() iteration
Definition result_tracker_feature_stats.hpp:114
bool print_stats(std::ostream &os=std::cout)
Definition result_tracker_feature_stats.hpp:423
std::vector< FeatureStat > _stats
one entry per feature (index 0.._n-1), aggregated over all recorded probes; filled by compute_stats()
Definition result_tracker_feature_stats.hpp:216
bool getFirstPairDAF(RETURNTYPE &daf0, RETURNTYPE &daf1, bool &daf1_valid, RETURNTYPE &synergy, DIMTYPE &f1, DIMTYPE &f2) const
Starts an iteration (decreasing pair-DAF0) over the pairwise statistics built by compute_pair_stats()...
Definition result_tracker_feature_stats.hpp:591
std::shared_ptr< SUBSET > PSubset
Definition result_tracker_feature_stats.hpp:115
bool getNextPairDAF(RETURNTYPE &daf0, RETURNTYPE &daf1, bool &daf1_valid, RETURNTYPE &synergy, DIMTYPE &f1, DIMTYPE &f2) const
Definition result_tracker_feature_stats.hpp:606
Clonable_Impl< Result_Tracker_Feature_Stats, parent, CLONE_INHERIT, CLONE_INHERIT, CLONE_DEEP > parent_impl
implements stateless_clone(); clone()/sharing_clone() throw in Result_Tracker
Definition result_tracker_feature_stats.hpp:112
Result_Tracker_Feature_Stats(const Result_Tracker_Feature_Stats &rtfs)
the stateless_clone() copy: replicates configuration (capacity limit, margin) via the parent copy-con...
Definition result_tracker_feature_stats.hpp:118
std::size_t _pair_itersize
Definition result_tracker_feature_stats.hpp:249
Result_Tracker_Feature_Stats(const IDXTYPE capacity_limit=0)
Definition result_tracker_feature_stats.hpp:117
std::vector< PairStat > _pair_stats
upper-triangle linearization (via pair_index()) over the top-k feature set; filled by compute_pair_st...
Definition result_tracker_feature_stats.hpp:246
bool output_normal() const
true unless output detail is SILENT
Definition result_tracker.hpp:118
static void print(std::ostream &os, std::ostringstream &sos)
Writes sos's buffered content to os, serializing concurrent writers under FST_THREADED via a shared m...
Definition global.hpp:86
FST4 specific error passing class.
Global definitions.
The Feature Selection Toolbox 4 library: every library component – data access, criteria and classifi...
Definition data_accessor.hpp:80
void notify(const std::string msg)
Prints msg followed by a newline via syncout::print(); a no-op unless the preprocessor macro DEBUG is...
Definition global.hpp:112
@ f1
classification, two-class data: F1 of the positive class, which is Metric_Spec::f1_positive (class in...
Definition wrapper_metrics.hpp:63
Enables collecting multiple results.
Structure to gather feature occurrence statistics over probe subset evaluations.
Definition result_tracker_feature_stats.hpp:203
bool daf_valid[3]
per-DAF-variant validity flag; DAF2's entry is always true (see compute_stats())
Definition result_tracker_feature_stats.hpp:214
RETURNTYPE daf[3]
Definition result_tracker_feature_stats.hpp:213
RETURNTYPE mean_is
mean criterion value over probes containing this feature
Definition result_tracker_feature_stats.hpp:206
RETURNTYPE stdev_is
criterion value stdev over probes containing this feature
Definition result_tracker_feature_stats.hpp:208
RETURNTYPE stdev_isnot
Definition result_tracker_feature_stats.hpp:209
RETURNTYPE freq_is
number of recorded probes containing this feature
Definition result_tracker_feature_stats.hpp:204
RETURNTYPE freq_isnot
number of recorded probes not containing this feature
Definition result_tracker_feature_stats.hpp:205
RETURNTYPE mean_isnot
mean criterion value over probes not containing this feature
Definition result_tracker_feature_stats.hpp:207
Structure to hold pairwise feature statistics (2x2 presence-cell contrasts over probe subset evaluati...
Definition result_tracker_feature_stats.hpp:235
RETURNTYPE freq_neither
number of probes containing neither feature
Definition result_tracker_feature_stats.hpp:239
bool valid
all four presence cells non-empty
Definition result_tracker_feature_stats.hpp:243
RETURNTYPE daf0
mean(both present) - mean(both absent)
Definition result_tracker_feature_stats.hpp:240
RETURNTYPE daf1
daf0 normalized by frequency-weighted stdevs of the two cells (0 if daf1_valid==false)
Definition result_tracker_feature_stats.hpp:241
RETURNTYPE synergy
mean_both + mean_neither - mean_f1only - mean_f2only
Definition result_tracker_feature_stats.hpp:242
DIMTYPE f2
global index of the pair's second feature
Definition result_tracker_feature_stats.hpp:237
bool daf1_valid
valid AND the daf1 normalization denominator is positive
Definition result_tracker_feature_stats.hpp:244
RETURNTYPE freq_both
number of probes containing both features
Definition result_tracker_feature_stats.hpp:238
DIMTYPE f1
global index of the pair's first feature
Definition result_tracker_feature_stats.hpp:236
Structure to gather probe subset cardinality statistics.
Definition result_tracker_feature_stats.hpp:219
RETURNTYPE freq
number of recorded probes with this exact subset size (cardinality)
Definition result_tracker_feature_stats.hpp:220
bool valid
true once freq>0 and mean/stdev have been computed (see compute_stats())
Definition result_tracker_feature_stats.hpp:223
RETURNTYPE mean
mean criterion value over probes of this cardinality
Definition result_tracker_feature_stats.hpp:221
RETURNTYPE stdev
criterion value stdev over probes of this cardinality
Definition result_tracker_feature_stats.hpp:222
Copyright © 2000–present ÚTIA, Institute of Information Theory and Automation of the Czech Academy of Sciences · Contacts · This site sets no cookies and uses no analytics.