Algorithms_in_C++  1.0.0
Set of algorithms implemented in C++.
ordinary_least_squares_regressor.cpp File Reference

Linear regression example using Ordinary least squares More...

#include <iomanip>
#include <iostream>
#include <vector>
Include dependency graph for ordinary_least_squares_regressor.cpp:

Functions

template<typename T >
std::ostreamoperator<< (std::ostream &out, std::vector< std::vector< T >> const &v)
 
template<typename T >
std::ostreamoperator<< (std::ostream &out, std::vector< T > const &v)
 
template<typename T >
bool is_square (std::vector< std::vector< T >> const &A)
 
template<typename T >
std::vector< std::vector< T > > operator* (std::vector< std::vector< T >> const &A, std::vector< std::vector< T >> const &B)
 
template<typename T >
std::vector< T > operator* (std::vector< std::vector< T >> const &A, std::vector< T > const &B)
 
template<typename T >
std::vector< float > operator* (float const scalar, std::vector< T > const &A)
 
template<typename T >
std::vector< float > operator* (std::vector< T > const &A, float const scalar)
 
template<typename T >
std::vector< float > operator/ (std::vector< T > const &A, float const scalar)
 
template<typename T >
std::vector< T > operator- (std::vector< T > const &A, std::vector< T > const &B)
 
template<typename T >
std::vector< T > operator+ (std::vector< T > const &A, std::vector< T > const &B)
 
template<typename T >
std::vector< std::vector< float > > get_inverse (std::vector< std::vector< T >> const &A)
 
template<typename T >
std::vector< std::vector< T > > get_transpose (std::vector< std::vector< T >> const &A)
 
template<typename T >
std::vector< float > fit_OLS_regressor (std::vector< std::vector< T >> const &X, std::vector< T > const &Y)
 
template<typename T >
std::vector< float > predict_OLS_regressor (std::vector< std::vector< T >> const &X, std::vector< float > const &beta)
 
int main ()
 

Detailed Description

Linear regression example using Ordinary least squares

Author
Krishna Vedala Program that gets the number of data samples and number of features per sample along with output per sample. It applies OLS regression to compute the regression output for additional test data samples.

Function Documentation

◆ fit_OLS_regressor()

template<typename T >
std::vector<float> fit_OLS_regressor ( std::vector< std::vector< T >> const &  X,
std::vector< T > const &  Y 
)

Perform Ordinary Least Squares curve fit. This operation is defined as

\[\beta = \left(X^TXX^T\right)Y\]

Parameters
Xfeature matrix with rows representing sample vector of features
Yknown regression value for each sample
Returns
fitted regression model polynomial coefficients
310  {
311  // NxF
313  for (size_t i = 0; i < X2.size(); i++)
314  // add Y-intercept -> Nx(F+1)
315  X2[i].push_back(1);
316  // (F+1)xN
318  // (F+1)x(F+1)
319  std::vector<std::vector<T>> tmp = get_inverse(Xt * X2);
320  // (F+1)xN
321  std::vector<std::vector<float>> out = tmp * Xt;
322  // cout << endl
323  // << "Projection matrix: " << X2 * out << endl;
324 
325  // Fx1,1 -> (F+1)^th element is the independent constant
326  return out * Y;
327 }
Here is the call graph for this function:

◆ get_inverse()

template<typename T >
std::vector<std::vector<float> > get_inverse ( std::vector< std::vector< T >> const &  A)

Get matrix inverse using Row-trasnformations. Given matrix must be a square and non-singular.

Returns
inverse matrix
218  {
219  // Assuming A is square matrix
220  size_t N = A.size();
221 
222  std::vector<std::vector<float>> inverse(N);
223  for (size_t row = 0; row < N; row++) {
224  // preallocatae a resultant identity matrix
225  inverse[row] = std::vector<float>(N);
226  for (size_t col = 0; col < N; col++)
227  inverse[row][col] = (row == col) ? 1.f : 0.f;
228  }
229 
230  if (!is_square(A)) {
231  std::cerr << "A must be a square matrix!" << std::endl;
232  return inverse;
233  }
234 
235  // preallocatae a temporary matrix identical to A
237  for (size_t row = 0; row < N; row++) {
238  std::vector<float> v(N);
239  for (size_t col = 0; col < N; col++)
240  v[col] = static_cast<float>(A[row][col]);
241  temp[row] = v;
242  }
243 
244  // start transformations
245  for (size_t row = 0; row < N; row++) {
246  for (size_t row2 = row; row2 < N && temp[row][row] == 0; row2++) {
247  // this to ensure diagonal elements are not 0
248  temp[row] = temp[row] + temp[row2];
249  inverse[row] = inverse[row] + inverse[row2];
250  }
251 
252  for (size_t col2 = row; col2 < N && temp[row][row] == 0; col2++) {
253  // this to further ensure diagonal elements are not 0
254  for (size_t row2 = 0; row2 < N; row2++) {
255  temp[row2][row] = temp[row2][row] + temp[row2][col2];
256  inverse[row2][row] = inverse[row2][row] + inverse[row2][col2];
257  }
258  }
259 
260  if (temp[row][row] == 0) {
261  // Probably a low-rank matrix and hence singular
262  std::cerr << "Low-rank matrix, no inverse!" << std::endl;
263  return inverse;
264  }
265 
266  // set diagonal to 1
267  float divisor = static_cast<float>(temp[row][row]);
268  temp[row] = temp[row] / divisor;
269  inverse[row] = inverse[row] / divisor;
270  // Row transformations
271  for (size_t row2 = 0; row2 < N; row2++) {
272  if (row2 == row)
273  continue;
274  float factor = temp[row2][row];
275  temp[row2] = temp[row2] - factor * temp[row];
276  inverse[row2] = inverse[row2] - factor * inverse[row];
277  }
278  }
279 
280  return inverse;
281 }
Here is the call graph for this function:

◆ get_transpose()

template<typename T >
std::vector<std::vector<T> > get_transpose ( std::vector< std::vector< T >> const &  A)

matrix transpose

Returns
resultant matrix
289  {
290  std::vector<std::vector<T>> result(A[0].size());
291 
292  for (size_t row = 0; row < A[0].size(); row++) {
293  std::vector<T> v(A.size());
294  for (size_t col = 0; col < A.size(); col++) v[col] = A[col][row];
295 
296  result[row] = v;
297  }
298  return result;
299 }

◆ is_square()

template<typename T >
bool is_square ( std::vector< std::vector< T >> const &  A)
inline

function to check if given matrix is a square matrix

Returns
1 if true, 0 if false
54  {
55  // Assuming A is square matrix
56  size_t N = A.size();
57  for (size_t i = 0; i < N; i++)
58  if (A[i].size() != N)
59  return false;
60  return true;
61 }

◆ main()

int main ( )

main function

357  {
358  size_t N, F;
359 
360  std::cout << "Enter number of features: ";
361  // number of features = columns
362  std::cin >> F;
363  std::cout << "Enter number of samples: ";
364  // number of samples = rows
365  std::cin >> N;
366 
368  std::vector<float> Y(N);
369 
370  std::cout
371  << "Enter training data. Per sample, provide features ad one output."
372  << std::endl;
373 
374  for (size_t rows = 0; rows < N; rows++) {
375  std::vector<float> v(F);
376  std::cout << "Sample# " << rows + 1 << ": ";
377  for (size_t cols = 0; cols < F; cols++)
378  // get the F features
379  std::cin >> v[cols];
380  data[rows] = v;
381  // get the corresponding output
382  std::cin >> Y[rows];
383  }
384 
386  std::cout << std::endl << std::endl << "beta:" << beta << std::endl;
387 
388  size_t T;
389  std::cout << "Enter number of test samples: ";
390  // number of test sample inputs
391  std::cin >> T;
393  // vector<float> Y2(T);
394 
395  for (size_t rows = 0; rows < T; rows++) {
396  std::cout << "Sample# " << rows + 1 << ": ";
397  std::vector<float> v(F);
398  for (size_t cols = 0; cols < F; cols++) std::cin >> v[cols];
399  data2[rows] = v;
400  }
401 
402  std::vector<float> out = predict_OLS_regressor(data2, beta);
403  for (size_t rows = 0; rows < T; rows++) std::cout << out[rows] << std::endl;
404 
405  return 0;
406 }
Here is the call graph for this function:

◆ operator*() [1/4]

template<typename T >
std::vector<float> operator* ( float const  scalar,
std::vector< T > const &  A 
)

pre-multiplication of a vector by a scalar

Returns
resultant vector
130  {
131  // Number of rows in A
132  size_t N_A = A.size();
133 
134  std::vector<float> result(N_A);
135 
136  for (size_t row = 0; row < N_A; row++) {
137  result[row] += A[row] * static_cast<float>(scalar);
138  }
139 
140  return result;
141 }
Here is the call graph for this function:

◆ operator*() [2/4]

template<typename T >
std::vector<std::vector<T> > operator* ( std::vector< std::vector< T >> const &  A,
std::vector< std::vector< T >> const &  B 
)

Matrix multiplication such that if A is size (mxn) and B is of size (pxq) then the multiplication is defined only when n = p and the resultant matrix is of size (mxq)

Returns
resultant matrix
72  {
73  // Number of rows in A
74  size_t N_A = A.size();
75  // Number of columns in B
76  size_t N_B = B[0].size();
77 
78  std::vector<std::vector<T>> result(N_A);
79 
80  if (A[0].size() != B.size()) {
81  std::cerr << "Number of columns in A != Number of rows in B ("
82  << A[0].size() << ", " << B.size() << ")" << std::endl;
83  return result;
84  }
85 
86  for (size_t row = 0; row < N_A; row++) {
87  std::vector<T> v(N_B);
88  for (size_t col = 0; col < N_B; col++) {
89  v[col] = static_cast<T>(0);
90  for (size_t j = 0; j < B.size(); j++)
91  v[col] += A[row][j] * B[j][col];
92  }
93  result[row] = v;
94  }
95 
96  return result;
97 }
Here is the call graph for this function:

◆ operator*() [3/4]

template<typename T >
std::vector<T> operator* ( std::vector< std::vector< T >> const &  A,
std::vector< T > const &  B 
)

multiplication of a matrix with a column vector

Returns
resultant vector
105  {
106  // Number of rows in A
107  size_t N_A = A.size();
108 
109  std::vector<T> result(N_A);
110 
111  if (A[0].size() != B.size()) {
112  std::cerr << "Number of columns in A != Number of rows in B ("
113  << A[0].size() << ", " << B.size() << ")" << std::endl;
114  return result;
115  }
116 
117  for (size_t row = 0; row < N_A; row++) {
118  result[row] = static_cast<T>(0);
119  for (size_t j = 0; j < B.size(); j++) result[row] += A[row][j] * B[j];
120  }
121 
122  return result;
123 }
Here is the call graph for this function:

◆ operator*() [4/4]

template<typename T >
std::vector<float> operator* ( std::vector< T > const &  A,
float const  scalar 
)

post-multiplication of a vector by a scalar

Returns
resultant vector
148  {
149  // Number of rows in A
150  size_t N_A = A.size();
151 
152  std::vector<float> result(N_A);
153 
154  for (size_t row = 0; row < N_A; row++)
155  result[row] = A[row] * static_cast<float>(scalar);
156 
157  return result;
158 }
Here is the call graph for this function:

◆ operator+()

template<typename T >
std::vector<T> operator+ ( std::vector< T > const &  A,
std::vector< T > const &  B 
)

addition of two vectors of identical lengths

Returns
resultant vector
195  {
196  // Number of rows in A
197  size_t N = A.size();
198 
199  std::vector<T> result(N);
200 
201  if (B.size() != N) {
202  std::cerr << "Vector dimensions shouldbe identical!" << std::endl;
203  return A;
204  }
205 
206  for (size_t row = 0; row < N; row++) result[row] = A[row] + B[row];
207 
208  return result;
209 }
Here is the call graph for this function:

◆ operator-()

template<typename T >
std::vector<T> operator- ( std::vector< T > const &  A,
std::vector< T > const &  B 
)

subtraction of two vectors of identical lengths

Returns
resultant vector
174  {
175  // Number of rows in A
176  size_t N = A.size();
177 
178  std::vector<T> result(N);
179 
180  if (B.size() != N) {
181  std::cerr << "Vector dimensions shouldbe identical!" << std::endl;
182  return A;
183  }
184 
185  for (size_t row = 0; row < N; row++) result[row] = A[row] - B[row];
186 
187  return result;
188 }
Here is the call graph for this function:

◆ operator/()

template<typename T >
std::vector<float> operator/ ( std::vector< T > const &  A,
float const  scalar 
)

division of a vector by a scalar

Returns
resultant vector
165  {
166  return (1.f / scalar) * A;
167 }

◆ operator<<() [1/2]

template<typename T >
std::ostream& operator<< ( std::ostream out,
std::vector< std::vector< T >> const &  v 
)

operator to print a matrix

20  {
21  const int width = 10;
22  const char separator = ' ';
23 
24  for (size_t row = 0; row < v.size(); row++) {
25  for (size_t col = 0; col < v[row].size(); col++)
26  out << std::left << std::setw(width) << std::setfill(separator)
27  << v[row][col];
28  out << std::endl;
29  }
30 
31  return out;
32 }
Here is the call graph for this function:

◆ operator<<() [2/2]

template<typename T >
std::ostream& operator<< ( std::ostream out,
std::vector< T > const &  v 
)

operator to print a vector

38  {
39  const int width = 15;
40  const char separator = ' ';
41 
42  for (size_t row = 0; row < v.size(); row++)
43  out << std::left << std::setw(width) << std::setfill(separator)
44  << v[row];
45 
46  return out;
47 }
Here is the call graph for this function:

◆ predict_OLS_regressor()

template<typename T >
std::vector<float> predict_OLS_regressor ( std::vector< std::vector< T >> const &  X,
std::vector< float > const &  beta 
)

Given data and OLS model coeffficients, predict regression estimates. This operation is defined as

\[y_{\text{row}=i} = \sum_{j=\text{columns}}\beta_j\cdot X_{i,j}\]

Parameters
Xfeature matrix with rows representing sample vector of features
betafitted regression model
Returns
vector with regression values for each sample
341  {
342  std::vector<float> result(X.size());
343 
344  for (size_t rows = 0; rows < X.size(); rows++) {
345  // -> start with constant term
346  result[rows] = beta[X[0].size()];
347  for (size_t cols = 0; cols < X[0].size(); cols++)
348  result[rows] += beta[cols] * X[rows][cols];
349  }
350  // Nx1
351  return result;
352 }
f
uint64_t f[MAX]
Definition: fibonacci_fast.cpp:27
std::vector
STL class.
std::vector::size
T size(T... args)
std::setfill
T setfill(T... args)
is_square
bool is_square(std::vector< std::vector< T >> const &A)
Definition: ordinary_least_squares_regressor.cpp:54
std::cerr
predict_OLS_regressor
std::vector< float > predict_OLS_regressor(std::vector< std::vector< T >> const &X, std::vector< float > const &beta)
Definition: ordinary_least_squares_regressor.cpp:339
data
int data[MAX]
test data
Definition: hash_search.cpp:24
fit_OLS_regressor
std::vector< float > fit_OLS_regressor(std::vector< std::vector< T >> const &X, std::vector< T > const &Y)
Definition: ordinary_least_squares_regressor.cpp:309
std::endl
T endl(T... args)
get_inverse
std::vector< std::vector< float > > get_inverse(std::vector< std::vector< T >> const &A)
Definition: ordinary_least_squares_regressor.cpp:217
std::left
T left(T... args)
std::setw
T setw(T... args)
std::cin
get_transpose
std::vector< std::vector< T > > get_transpose(std::vector< std::vector< T >> const &A)
Definition: ordinary_least_squares_regressor.cpp:288