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

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.

Author
Krishna Vedala

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
311  {
312  // NxF
314  for (size_t i = 0; i < X2.size(); i++)
315  // add Y-intercept -> Nx(F+1)
316  X2[i].push_back(1);
317  // (F+1)xN
319  // (F+1)x(F+1)
320  std::vector<std::vector<T>> tmp = get_inverse(Xt * X2);
321  // (F+1)xN
322  std::vector<std::vector<float>> out = tmp * Xt;
323  // cout << endl
324  // << "Projection matrix: " << X2 * out << endl;
325 
326  // Fx1,1 -> (F+1)^th element is the independent constant
327  return out * Y;
328 }
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
219  {
220  // Assuming A is square matrix
221  size_t N = A.size();
222 
223  std::vector<std::vector<float>> inverse(N);
224  for (size_t row = 0; row < N; row++) {
225  // preallocatae a resultant identity matrix
226  inverse[row] = std::vector<float>(N);
227  for (size_t col = 0; col < N; col++)
228  inverse[row][col] = (row == col) ? 1.f : 0.f;
229  }
230 
231  if (!is_square(A)) {
232  std::cerr << "A must be a square matrix!" << std::endl;
233  return inverse;
234  }
235 
236  // preallocatae a temporary matrix identical to A
238  for (size_t row = 0; row < N; row++) {
239  std::vector<float> v(N);
240  for (size_t col = 0; col < N; col++)
241  v[col] = static_cast<float>(A[row][col]);
242  temp[row] = v;
243  }
244 
245  // start transformations
246  for (size_t row = 0; row < N; row++) {
247  for (size_t row2 = row; row2 < N && temp[row][row] == 0; row2++) {
248  // this to ensure diagonal elements are not 0
249  temp[row] = temp[row] + temp[row2];
250  inverse[row] = inverse[row] + inverse[row2];
251  }
252 
253  for (size_t col2 = row; col2 < N && temp[row][row] == 0; col2++) {
254  // this to further ensure diagonal elements are not 0
255  for (size_t row2 = 0; row2 < N; row2++) {
256  temp[row2][row] = temp[row2][row] + temp[row2][col2];
257  inverse[row2][row] = inverse[row2][row] + inverse[row2][col2];
258  }
259  }
260 
261  if (temp[row][row] == 0) {
262  // Probably a low-rank matrix and hence singular
263  std::cerr << "Low-rank matrix, no inverse!" << std::endl;
264  return inverse;
265  }
266 
267  // set diagonal to 1
268  float divisor = static_cast<float>(temp[row][row]);
269  temp[row] = temp[row] / divisor;
270  inverse[row] = inverse[row] / divisor;
271  // Row transformations
272  for (size_t row2 = 0; row2 < N; row2++) {
273  if (row2 == row)
274  continue;
275  float factor = temp[row2][row];
276  temp[row2] = temp[row2] - factor * temp[row];
277  inverse[row2] = inverse[row2] - factor * inverse[row];
278  }
279  }
280 
281  return inverse;
282 }
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
290  {
291  std::vector<std::vector<T>> result(A[0].size());
292 
293  for (size_t row = 0; row < A[0].size(); row++) {
294  std::vector<T> v(A.size());
295  for (size_t col = 0; col < A.size(); col++) v[col] = A[col][row];
296 
297  result[row] = v;
298  }
299  return result;
300 }

◆ 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
55  {
56  // Assuming A is square matrix
57  size_t N = A.size();
58  for (size_t i = 0; i < N; i++)
59  if (A[i].size() != N)
60  return false;
61  return true;
62 }

◆ main()

int main ( )

main function

358  {
359  size_t N, F;
360 
361  std::cout << "Enter number of features: ";
362  // number of features = columns
363  std::cin >> F;
364  std::cout << "Enter number of samples: ";
365  // number of samples = rows
366  std::cin >> N;
367 
369  std::vector<float> Y(N);
370 
371  std::cout
372  << "Enter training data. Per sample, provide features ad one output."
373  << std::endl;
374 
375  for (size_t rows = 0; rows < N; rows++) {
376  std::vector<float> v(F);
377  std::cout << "Sample# " << rows + 1 << ": ";
378  for (size_t cols = 0; cols < F; cols++)
379  // get the F features
380  std::cin >> v[cols];
381  data[rows] = v;
382  // get the corresponding output
383  std::cin >> Y[rows];
384  }
385 
387  std::cout << std::endl << std::endl << "beta:" << beta << std::endl;
388 
389  size_t T;
390  std::cout << "Enter number of test samples: ";
391  // number of test sample inputs
392  std::cin >> T;
394  // vector<float> Y2(T);
395 
396  for (size_t rows = 0; rows < T; rows++) {
397  std::cout << "Sample# " << rows + 1 << ": ";
398  std::vector<float> v(F);
399  for (size_t cols = 0; cols < F; cols++) std::cin >> v[cols];
400  data2[rows] = v;
401  }
402 
403  std::vector<float> out = predict_OLS_regressor(data2, beta);
404  for (size_t rows = 0; rows < T; rows++) std::cout << out[rows] << std::endl;
405 
406  return 0;
407 }
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
131  {
132  // Number of rows in A
133  size_t N_A = A.size();
134 
135  std::vector<float> result(N_A);
136 
137  for (size_t row = 0; row < N_A; row++) {
138  result[row] += A[row] * static_cast<float>(scalar);
139  }
140 
141  return result;
142 }
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
73  {
74  // Number of rows in A
75  size_t N_A = A.size();
76  // Number of columns in B
77  size_t N_B = B[0].size();
78 
79  std::vector<std::vector<T>> result(N_A);
80 
81  if (A[0].size() != B.size()) {
82  std::cerr << "Number of columns in A != Number of rows in B ("
83  << A[0].size() << ", " << B.size() << ")" << std::endl;
84  return result;
85  }
86 
87  for (size_t row = 0; row < N_A; row++) {
88  std::vector<T> v(N_B);
89  for (size_t col = 0; col < N_B; col++) {
90  v[col] = static_cast<T>(0);
91  for (size_t j = 0; j < B.size(); j++)
92  v[col] += A[row][j] * B[j][col];
93  }
94  result[row] = v;
95  }
96 
97  return result;
98 }
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
106  {
107  // Number of rows in A
108  size_t N_A = A.size();
109 
110  std::vector<T> result(N_A);
111 
112  if (A[0].size() != B.size()) {
113  std::cerr << "Number of columns in A != Number of rows in B ("
114  << A[0].size() << ", " << B.size() << ")" << std::endl;
115  return result;
116  }
117 
118  for (size_t row = 0; row < N_A; row++) {
119  result[row] = static_cast<T>(0);
120  for (size_t j = 0; j < B.size(); j++) result[row] += A[row][j] * B[j];
121  }
122 
123  return result;
124 }
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
149  {
150  // Number of rows in A
151  size_t N_A = A.size();
152 
153  std::vector<float> result(N_A);
154 
155  for (size_t row = 0; row < N_A; row++)
156  result[row] = A[row] * static_cast<float>(scalar);
157 
158  return result;
159 }
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
196  {
197  // Number of rows in A
198  size_t N = A.size();
199 
200  std::vector<T> result(N);
201 
202  if (B.size() != N) {
203  std::cerr << "Vector dimensions shouldbe identical!" << std::endl;
204  return A;
205  }
206 
207  for (size_t row = 0; row < N; row++) result[row] = A[row] + B[row];
208 
209  return result;
210 }
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
175  {
176  // Number of rows in A
177  size_t N = A.size();
178 
179  std::vector<T> result(N);
180 
181  if (B.size() != N) {
182  std::cerr << "Vector dimensions shouldbe identical!" << std::endl;
183  return A;
184  }
185 
186  for (size_t row = 0; row < N; row++) result[row] = A[row] - B[row];
187 
188  return result;
189 }
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
166  {
167  return (1.f / scalar) * A;
168 }

◆ operator<<() [1/2]

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

operator to print a matrix

21  {
22  const int width = 10;
23  const char separator = ' ';
24 
25  for (size_t row = 0; row < v.size(); row++) {
26  for (size_t col = 0; col < v[row].size(); col++)
27  out << std::left << std::setw(width) << std::setfill(separator)
28  << v[row][col];
29  out << std::endl;
30  }
31 
32  return out;
33 }
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

39  {
40  const int width = 15;
41  const char separator = ' ';
42 
43  for (size_t row = 0; row < v.size(); row++)
44  out << std::left << std::setw(width) << std::setfill(separator)
45  << v[row];
46 
47  return out;
48 }
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
342  {
343  std::vector<float> result(X.size());
344 
345  for (size_t rows = 0; rows < X.size(); rows++) {
346  // -> start with constant term
347  result[rows] = beta[X[0].size()];
348  for (size_t cols = 0; cols < X[0].size(); cols++)
349  result[rows] += beta[cols] * X[rows][cols];
350  }
351  // Nx1
352  return result;
353 }
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:55
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:340
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:310
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:218
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:289