UFJF - Machine Learning Toolkit  0.51.8
OneVsOne.hpp
1 //
2 // Created by mateus558 on 30/03/2020.
3 //
4 
5 #ifndef UFJF_MLTK_ONEVSONE_HPP
6 #define UFJF_MLTK_ONEVSONE_HPP
7 #pragma once
8 
9 #include "PrimalClassifier.hpp"
10 #include "DualClassifier.hpp"
11 #include "ufjfmltk/core/Sampling.hpp"
12 
13 namespace mltk{
14  namespace classifier {
18  template<typename T>
19  class OneVsOne : public PrimalClassifier<T>, public DualClassifier<T> {
20  private:
21  using LearnerPointer = std::shared_ptr<Learner<T> >;
23  std::vector<std::vector<LearnerPointer> > base_learners;
25  OverSampling<T> *samp_method;
26 
27  public:
28  OneVsOne() = default;
29 
30  template<template<typename> class ClassifierType>
31  OneVsOne(const Data<T> &samples, ClassifierType<T> &classifier, OverSampling<T> *samp_method = nullptr,
32  int _verbose = 0) {
33  this->samples = mltk::make_data<double>(samples);
34  this->verbose = _verbose;
35  this->samp_method = samp_method;
36 
37  auto classes = this->samples->classes();
38  // initialize the m_learners matrix is samples were given
39  if (base_learners.size() == 0) {
40  base_learners.resize(classes.size());
41 
42  for (size_t i = 0; i < classes.size(); ++i) {
43  base_learners[i].resize(classes.size());
44 
45  for (size_t j = 0; j < base_learners[i].size(); ++j) {
46  if (classes[i] != classes[j]) {
47  base_learners[i][j] = std::make_shared<ClassifierType<T> >(classifier);
48  }
49  }
50  }
51  }
52  }
53 
54  template<template<typename> class ClassifierType>
55  explicit OneVsOne(ClassifierType<T> &classifier, OverSampling<T> *samp_method = nullptr,
56  int _verbose = 0) {
57  this->samples = classifier.getSamples();
58  this->verbose = _verbose;
59  this->samp_method = samp_method;
60 
61  auto classes = this->samples->classes();
62  // initialize the m_learners matrix is samples were given
63  if (base_learners.size() == 0) {
64  base_learners.resize(classes.size());
65 
66  for (size_t i = 0; i < classes.size(); ++i) {
67  base_learners[i].resize(classes.size());
68 
69  for (size_t j = 0; j < base_learners[i].size(); ++j) {
70  if (classes[i] != classes[j]) {
71  base_learners[i][j] = std::make_shared<ClassifierType<T> >(classifier);
72  }
73  }
74  }
75  }
76  }
77 
78  bool train() override;
79 
80  double evaluate(const Point<T> &p, bool raw_value = false) override;
81 
82  std::string getFormulationString() override;
83  };
84 
85  template<typename T>
87  auto classes = this->samples->classes();
88  size_t n_classes = classes.size();
89 
90  for (size_t i = 0; i < n_classes; ++i) {
91  for (size_t j = 0; j < n_classes; ++j) {
92  if (classes[i] != classes[j]) {
93  Data<T> temp_samples;
94  auto learner = base_learners[i][j];
95  std::vector<int> current_classes = {classes[i], classes[j]};
96 
97  // Copy the points with the classes being trained
98  temp_samples.classesCopy(*this->samples, current_classes);
99  temp_samples.setClasses({-1, 1});
100  // Transform the classes for binary classification
101  for (size_t k = 0; k < temp_samples.size(); k++) {
102  temp_samples[k]->Y() = (temp_samples[k]->Y() == classes[i]) ? 1 : -1;
103  }
104 
105  // If a over sampling algorithm was given, apply it to the samples
106  if (samp_method) {
107  temp_samples.computeClassesDistribution();
108  (*samp_method)(temp_samples);
109  }
110 
111  // train the current binary learner
112  learner->setSamples(temp_samples);
113  learner->train();
114  }
115  }
116  }
117 
118  return true;
119  }
120 
121  template<typename T>
122  double OneVsOne<T>::evaluate(const Point<T> &p, bool raw_value) {
123  auto classes = this->samples->classes();
124  std::vector<size_t> class_votes(classes.size(), 0);
125 
126  // classify the given point as the class with maximum votes
127  for (size_t i = 0; i < base_learners.size(); ++i) {
128  for (size_t j = 0; j < base_learners[i].size(); ++j) {
129  if (classes[i] != classes[j]) {
130  if (base_learners[i][j]->evaluate(p) == 1) {
131  class_votes[i]++;
132  } else {
133  class_votes[j]++;
134  }
135  }
136  }
137  }
138 
139  auto max_index = std::max_element(class_votes.begin(), class_votes.end()) - class_votes.begin();
140 
141  return classes[max_index];
142  }
143 
144  template<typename T>
146  return this->base_learners[0][1]->getFormulationString();
147  }
148  }
149 }
150 
151 #endif //UFJF_MLTK_ONEVSONE_HPP
void classesCopy(const Data< T > &_data, std::vector< int > &classes)
Makes a deep copy from another data object.
Definition: Data.hpp:1520
size_t size() const
Returns the size of the dataset.
Definition: Data.hpp:208
const std::vector< int > classes() const
Returns a vector containing the numeric values of the classes.
Definition: Data.hpp:1831
void setClasses(const std::vector< int > &classes)
Set the classes to use in the dataset.
Definition: Data.hpp:1836
void computeClassesDistribution()
Compute the frequency of each class in the dataset.
Definition: Data.hpp:1843
std::shared_ptr< Data< T > > samples
Samples used in the model training.
Definition: Learner.hpp:21
int verbose
Verbose level of the output.
Definition: Learner.hpp:42
Base class for the implementation of over sampling methods.
Definition: Sampling.hpp:110
Definition: DualClassifier.hpp:16
Wrapper for the implementation of the one vs one multi class classification algorithm.
Definition: OneVsOne.hpp:19
std::string getFormulationString() override
getFormulationString Returns a string that represents the formulation of the learner (Primal or Dual)...
Definition: OneVsOne.hpp:145
double evaluate(const Point< T > &p, bool raw_value=false) override
Returns the class of a feature point based on the trained Learner.
Definition: OneVsOne.hpp:122
bool train() override
Function that execute the training phase of a Learner.
Definition: OneVsOne.hpp:86
Definition: PrimalClassifier.hpp:14
UFJF-MLTK main namespace for core functionalities.
Definition: classifier/Classifier.hpp:11