TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
k_nearest_neighbors.cpp
Go to the documentation of this file.
1
12#include <algorithm>
13#include <cassert>
14#include <cmath>
15#include <iostream>
16#include <numeric>
17#include <unordered_map>
18#include <vector>
19
24namespace machine_learning {
25
31namespace k_nearest_neighbors {
32
42template <typename T>
43double euclidean_distance(const std::vector<T>& a, const std::vector<T>& b) {
44 std::vector<double> aux;
45 std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(aux),
46 [](T x1, T x2) { return std::pow((x1 - x2), 2); });
47 aux.shrink_to_fit();
48 return std::sqrt(std::accumulate(aux.begin(), aux.end(), 0.0));
49}
50
55class Knn {
56 private:
57 std::vector<std::vector<double>> X_{};
58 std::vector<int> Y_{};
59
60 public:
67 explicit Knn(std::vector<std::vector<double>>& X, std::vector<int>& Y)
68 : X_(X), Y_(Y){};
69
75 Knn(const Knn& model) = default;
76
80 Knn& operator=(const Knn& model) = default;
81
85 Knn(Knn&&) = default;
86
90 Knn& operator=(Knn&&) = default;
91
95 ~Knn() = default;
96
103 int predict(std::vector<double>& sample, int k) {
104 std::vector<int> neighbors;
105 std::vector<std::pair<double, int>> distances;
106 for (size_t i = 0; i < this->X_.size(); ++i) {
107 auto current = this->X_.at(i);
108 auto label = this->Y_.at(i);
109 auto distance = euclidean_distance(current, sample);
110 distances.emplace_back(distance, label);
111 }
112 std::sort(distances.begin(), distances.end());
113 for (int i = 0; i < k; i++) {
114 auto label = distances.at(i).second;
115 neighbors.push_back(label);
116 }
117 std::unordered_map<int, int> frequency;
118 for (auto neighbor : neighbors) {
119 ++frequency[neighbor];
120 }
121 std::pair<int, int> predicted;
122 predicted.first = -1;
123 predicted.second = -1;
124 for (auto& kv : frequency) {
125 if (kv.second > predicted.second) {
126 predicted.second = kv.second;
127 predicted.first = kv.first;
128 }
129 }
130 return predicted.first;
131 }
132};
133} // namespace k_nearest_neighbors
134} // namespace machine_learning
135
140static void test() {
141 std::cout << "------- Test 1 -------" << std::endl;
142 std::vector<std::vector<double>> X1 = {{0.0, 0.0}, {0.25, 0.25},
143 {0.0, 0.5}, {0.5, 0.5},
144 {1.0, 0.5}, {1.0, 1.0}};
145 std::vector<int> Y1 = {1, 1, 1, 1, 2, 2};
146 auto model1 = machine_learning::k_nearest_neighbors::Knn(X1, Y1);
147 std::vector<double> sample1 = {1.2, 1.2};
148 std::vector<double> sample2 = {0.1, 0.1};
149 std::vector<double> sample3 = {0.1, 0.5};
150 std::vector<double> sample4 = {1.0, 0.75};
151 assert(model1.predict(sample1, 2) == 2);
152 assert(model1.predict(sample2, 2) == 1);
153 assert(model1.predict(sample3, 2) == 1);
154 assert(model1.predict(sample4, 2) == 2);
155 std::cout << "... Passed" << std::endl;
156 std::cout << "------- Test 2 -------" << std::endl;
157 std::vector<std::vector<double>> X2 = {
158 {0.0, 0.0, 0.0}, {0.25, 0.25, 0.0}, {0.0, 0.5, 0.0}, {0.5, 0.5, 0.0},
159 {1.0, 0.5, 0.0}, {1.0, 1.0, 0.0}, {1.0, 1.0, 1.0}, {1.5, 1.5, 1.0}};
160 std::vector<int> Y2 = {1, 1, 1, 1, 2, 2, 3, 3};
161 auto model2 = machine_learning::k_nearest_neighbors::Knn(X2, Y2);
162 std::vector<double> sample5 = {1.2, 1.2, 0.0};
163 std::vector<double> sample6 = {0.1, 0.1, 0.0};
164 std::vector<double> sample7 = {0.1, 0.5, 0.0};
165 std::vector<double> sample8 = {1.0, 0.75, 1.0};
166 assert(model2.predict(sample5, 2) == 2);
167 assert(model2.predict(sample6, 2) == 1);
168 assert(model2.predict(sample7, 2) == 1);
169 assert(model2.predict(sample8, 2) == 3);
170 std::cout << "... Passed" << std::endl;
171 std::cout << "------- Test 3 -------" << std::endl;
172 std::vector<std::vector<double>> X3 = {{0.0}, {1.0}, {2.0}, {3.0},
173 {4.0}, {5.0}, {6.0}, {7.0}};
174 std::vector<int> Y3 = {1, 1, 1, 1, 2, 2, 2, 2};
175 auto model3 = machine_learning::k_nearest_neighbors::Knn(X3, Y3);
176 std::vector<double> sample9 = {0.5};
177 std::vector<double> sample10 = {2.9};
178 std::vector<double> sample11 = {5.5};
179 std::vector<double> sample12 = {7.5};
180 assert(model3.predict(sample9, 3) == 1);
181 assert(model3.predict(sample10, 3) == 1);
182 assert(model3.predict(sample11, 3) == 2);
183 assert(model3.predict(sample12, 3) == 2);
184 std::cout << "... Passed" << std::endl;
185}
186
193int main(int argc, char* argv[]) {
194 test(); // run self-test implementations
195 return 0;
196}
K-Nearest Neighbors (Knn) class using Euclidean distance as distance metric.
Knn & operator=(const Knn &model)=default
std::vector< std::vector< double > > X_
attributes vector
Knn(std::vector< std::vector< double > > &X, std::vector< int > &Y)
Construct a new Knn object.
int predict(std::vector< double > &sample, int k)
Classify sample.
~Knn()=default
Destroy the Knn object.
int main()
Main function.
static void test()
Self-test implementations.
double euclidean_distance(const std::vector< T > &a, const std::vector< T > &b)
Compute the Euclidean distance between two vectors.
Functions for the [K-Nearest Neighbors algorithm] (https://en.wikipedia.org/wiki/K-nearest_neighbors_...
A* search algorithm