Feature Selection Toolbox FST4
UTIA · Czech Academy of Sciences
Loading...
Searching...
No Matches
classifier_knn.hpp
Go to the documentation of this file.
1#ifndef FSTCLASSIFIERKNN_H
2#define FSTCLASSIFIERKNN_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#include <iostream>
52#include <cmath>
53#include <list>
54#include "classifier.hpp"
55#include "error.hpp"
56#include "global.hpp"
57
58/*============== Template parameter type naming conventions ==============
59--------- Numeric types: -------------------------------------------------
60DATATYPE - data sample values - usually real numbers (but may be integers
61 in text processing etc.)
62REALTYPE - must be real numbers - for representing intermediate results of
63 calculations like mean, covariance etc.
64IDXTYPE - index values for enumeration of data samples - (nonnegative) integers,
65 extent depends on numbers of samples in data
66DIMTYPE - index values for enumeration of features (dimensions), or classes (not
67 class sizes) - (nonnegative) integers, usually lower extent than IDXTYPE,
68 but be aware of expressions like _classes*_features*_features !
69 in linearized representations of feature matrices for all classes
70BINTYPE - feature selection marker type - represents ca. <10 different feature
71 states (selected, deselected, sel./desel. temporarily 1st nested loop, 2nd...)
72RETURNTYPE - criterion value: real value, but may be extended in future to support
73 multiple values
74--------- Class types: ---------------------------------------------------
75SUBSET - class of class type Subset
76CLASSIFIER - class implementing interface defined in abstract class Classifier
77EVALUATOR - class implementing interface defined in abstract class Sequential_Step
78DISTANCE - class implementing interface defined in abstract class Distance
79DATAACCESSOR - class implementing interface defined in abstract class Data_Accessor
80INTERVALCONTAINER - class of class type Data_Intervaller
81CONTAINER - STL container of class type Data_Interval
82========================================================================== */
83
84namespace FST {
85
94template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
95class Classifier_kNN : public Clonable_Impl<Classifier_kNN<RETURNTYPE,DATATYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR,DISTANCE>,Classifier<RETURNTYPE,DIMTYPE,SUBSET,DATAACCESSOR> > {
96public:
99 typedef std::shared_ptr<DATAACCESSOR> PDataAccessor;
100 typedef std::shared_ptr<SUBSET> PSubset;
101 typedef typename DATAACCESSOR::PPattern PPattern;
102 Classifier_kNN() {set_k(1); _nns_max_size=1; notify("Classifier_kNN constructor.");}
103 virtual ~Classifier_kNN() {notify("Classifier_kNN destructor.");}
104
105 void set_k(const DIMTYPE k) {assert(k>0); _k=k; _nns_max_size=_k;}
106 DIMTYPE get_k() const {return _k;}
107
108 virtual bool classify(DIMTYPE &cls, const PPattern &pattern) override; // classifies pattern, returns the respective class index
109 virtual bool classify_scores(std::vector<RETURNTYPE> &scores, const PPattern &pattern) override; // per-class vote fractions among the k nearest neighbours for ranking metrics (AUC)
112 virtual bool train(const PDataAccessor da, const PSubset sub) override;
113 // test() = the canonical accuracy loop inherited from Classifier, driven by classify() below
114
115
116
117 virtual std::ostream& print(std::ostream& os) const override;
118private:
119 friend parent_impl;
120 Classifier_kNN(const Classifier_kNN& cknn);
121protected:
122 // NOTE: neighbours at equal distance but of different classes get no special treatment -
123 // see the tie remark in sort_in()
124
126 class Neighbour{
127 public:
128 Neighbour() {}
129 Neighbour(const RETURNTYPE value, const DIMTYPE cls) {_value=value; _cls=cls;}
130 Neighbour(const Neighbour& nei) {_value=nei._value; _cls=nei._cls;}
131 RETURNTYPE _value;
132 DIMTYPE _cls;
133 };
134 DIMTYPE _k;
136 void collect_neighbours(const PPattern &pattern);
139 void sort_in(const RETURNTYPE value, const DIMTYPE cls);
140 typename std::list<Neighbour>::iterator iter;
141 std::list<Neighbour> _nns;
142 std::vector<RETURNTYPE> _cs_sc;
143
144 std::unique_ptr<DISTANCE> _distance;
146};
147
148template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
149Classifier_kNN<RETURNTYPE,DATATYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR,DISTANCE>::Classifier_kNN(const Classifier_kNN& cknn) :
150 _k(cknn._k),
152 _nns(cknn._nns)
153{
154 notify("Classifier_kNN constructor.");
156}
157
158
159
160
161template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
163{
164 assert(da);
165 assert(sub);
166 if(!_distance || _distance->get_n()<sub->get_n_raw()) _distance.reset(new DISTANCE(sub->get_n_raw()));
167 _distance->narrow_to(sub);
168 _da_train=da;
169 return true;
170}
171
172template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
174{
175 // NOTE: iterates training data via its own RAII block range
176 // NOTE: da and _da_train may point to the same instance -> be careful with setClass() etc.
177 assert(_da_train);
178 assert(_distance);
179 assert(_distance->get_n()==_da_train->getNoOfFeatures());
180 assert(_distance->get_d()>0);
181 typename DATAACCESSOR::PPattern p2;
182 IDXTYPE s2,i2;
183 DIMTYPE _feats=_da_train->getNoOfFeatures();
184 RETURNTYPE val;
185
186
187
188 _nns_max_size=_k; // the k closest entries are collected and voted over
189
190 _nns.clear();
191 for(DIMTYPE c_train=0;c_train<_da_train->getNoOfClasses();c_train++)
192 {
193 _da_train->setClass(c_train);
194 for(const auto &blk : _da_train->blocks(TRAIN)) for(i2=0,p2=blk.data,s2=blk.size;i2<s2;i2++)
195 {
196 // p2[i2*_feats] is the beginning of the current pattern
197 val=_distance->distance(pattern,&p2[i2*_feats]);
198 sort_in(val,c_train);
199 }
200 }
201}
202
203template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
205{
206 // the decision rule IS the classify_scores() rule - argmax of the per-class vote
207 // fractions among the k nearest neighbours, first maximum wins (lowest class index
208 // on ties, the convention shared by all score-deriving classifiers)
209 if(!classify_scores(_cs_sc,pattern)) return false;
210 cls=0;
211 const DIMTYPE classes=_da_train->getNoOfClasses();
212 for(DIMTYPE c=1;c<classes;c++) if(_cs_sc[c]>_cs_sc[cls]) cls=c; // first maximum wins
213 return true;
214}
215
216template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
218{
219 // per-class vote fractions among the k nearest training neighbours (coarse but valid
220 // posteriors for ranking metrics); the neighbour list is only read, not consumed
221 collect_neighbours(pattern);
222 const DIMTYPE classes=_da_train->getNoOfClasses();
223 scores.assign(classes,(RETURNTYPE)0.0);
224 DIMTYPE taken=0;
225 for(auto it=_nns.rbegin();it!=_nns.rend() && taken<_k;++it,++taken) // closest neighbour is the last
226 scores[it->_cls]+=1.0;
227 if(taken==0) return false;
228 for(DIMTYPE c=0;c<classes;c++) scores[c]/=(RETURNTYPE)taken;
229 return true;
230}
231
232
233template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
235{
236 iter=_nns.begin();
237 while(iter!=_nns.end() && value < (*iter)._value) iter++;
238 if(_nns.size()<_nns_max_size || iter!=_nns.begin()) {
239 Neighbour tmp(value,cls);
240 _nns.insert(iter,tmp);
241 // NOTE: known limitation: when several neighbours are tied at the k-th distance, the list cap below
242 // drops the excess ones, so the vote depends on training-sample order at the tie boundary.
243 // This is the conventional kNN tie behaviour and is deterministic for a fixed data order.
244 if(_nns.size()>_nns_max_size) _nns.pop_front();
245 }
246}
247
248
249template<class RETURNTYPE, typename DATATYPE, typename IDXTYPE, typename DIMTYPE, class SUBSET, class DATAACCESSOR, class DISTANCE>
251{
252 os << "Classifier_kNN(k=" << _k << ")";
253 if(_distance) os << *_distance;
254 return os;
255}
256
257} // namespace
258#endif // FSTCLASSIFIERKNN_H ///:~
Holds information on distance and data-class membership of neighbors processed in Classifier_kNN.
Definition classifier_knn.hpp:126
RETURNTYPE _value
distance from the pattern being classified to this training neighbour
Definition classifier_knn.hpp:131
Neighbour(const RETURNTYPE value, const DIMTYPE cls)
constructs from a distance value and the neighbour's class cls
Definition classifier_knn.hpp:129
Neighbour(const Neighbour &nei)
copy constructor
Definition classifier_knn.hpp:130
DIMTYPE _cls
the training neighbour's class
Definition classifier_knn.hpp:132
Implements k-Nearest Neighbor classifier.
Definition classifier_knn.hpp:95
virtual bool classify(DIMTYPE &cls, const PPattern &pattern) override
Definition classifier_knn.hpp:204
virtual bool classify_scores(std::vector< RETURNTYPE > &scores, const PPattern &pattern) override
Definition classifier_knn.hpp:217
Clonable_Impl< Classifier_kNN, parent > parent_impl
Definition classifier_knn.hpp:98
std::shared_ptr< DATAACCESSOR > PDataAccessor
Definition classifier_knn.hpp:99
virtual bool train(const PDataAccessor da, const PSubset sub) override
Definition classifier_knn.hpp:162
std::unique_ptr< DIST_L2 > _distance
Definition classifier_knn.hpp:144
void set_k(const DIMTYPE k)
sets the number of nearest neighbours collected and voted over; k must be > 0
Definition classifier_knn.hpp:105
Classifier_kNN(const Classifier_kNN &cknn)
copy-constructor (clones _distance if allocated; _nns/_k/_nns_max_size are value-copied)
Definition classifier_knn.hpp:149
std::list< Neighbour >::iterator iter
Definition classifier_knn.hpp:140
Classifier< RETURNTYPE, DIMTYPE, SUBSET, DATAACCESSOR > parent
Definition classifier_knn.hpp:97
virtual std::ostream & print(std::ostream &os) const override
writes a human-readable identification of the object; base default writes nothing
Definition classifier_knn.hpp:250
void collect_neighbours(const PPattern &pattern)
Definition classifier_knn.hpp:173
DIMTYPE get_k() const
the k set by set_k() (default 1)
Definition classifier_knn.hpp:106
void sort_in(const RETURNTYPE value, const DIMTYPE cls)
Definition classifier_knn.hpp:234
abstract class, defines interface for classifier implementations (mainly to be used in wrappers)
Definition classifier.hpp:97
CRTP mixin implementing the Clonable protocol for a concrete class.
Definition clonable.hpp:184
Defines interface for classifier implementations.
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
@ TRAIN
the split's training part
Definition data_accessor.hpp:85
std::unique_ptr< T > clone_unique(const T &src)
Definition clonable.hpp:234
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.