PCA.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /**
  2. * @file PCA.cpp
  3. * @brief Computation of a PCA by Eigenvalue Decomposition, Karhunen Loewe Transform
  4. * @author Michael Koch
  5. * @date 5/27/2008
  6. */
  7. /** \example testPCA.cpp
  8. * This is an example of how to use the Principal Component Analysis (PCA) class.
  9. */
  10. // #define DEBUG
  11. #undef DEBUG
  12. #include <iostream>
  13. #include <math.h>
  14. #include <vector>
  15. #include <map>
  16. #include "core/algebra/GenericMatrix.h"
  17. #include "core/algebra/EigValues.h"
  18. #include "core/algebra/EigValuesTRLAN.h"
  19. // #include "vislearning/fourier/FourierLibrary.h"
  20. #include "PCA.h"
  21. #include "vislearning/baselib/Gnuplot.h"
  22. using namespace OBJREC;
  23. using namespace std;
  24. using namespace NICE;
  25. PCA::PCA(uint dim, uint maxiteration, double mindelta)
  26. {
  27. init(dim, maxiteration, mindelta);
  28. }
  29. PCA::PCA(void)
  30. {
  31. init();
  32. }
  33. PCA::~PCA()
  34. {
  35. }
  36. void PCA::init(uint dim, uint maxiteration, double mindelta)
  37. {
  38. this->targetDimension = dim;
  39. this->maxiteration = maxiteration;
  40. this->mindelta = mindelta;
  41. }
  42. void PCA::restore(istream & is, int format)
  43. {
  44. is >> basis;
  45. is >> normalization;
  46. is >> mean;
  47. is >> targetDimension;
  48. }
  49. void PCA::store(ostream & os, int format) const
  50. {
  51. os << basis << normalization << mean << targetDimension;
  52. }
  53. void PCA::clear()
  54. {
  55. }
  56. void PCA::calculateBasis(const NICE::Matrix &features,
  57. const uint targetDimension, const uint mode)
  58. {
  59. calculateBasis(features, targetDimension, false);
  60. }
  61. void PCA::calculateMean ( const NICE::Matrix &features, NICE::Vector & mean )
  62. {
  63. // data vectors are put row-wise in the matrix
  64. mean.resize(features.cols());
  65. for ( uint i = 0 ; i < features.rows(); i++ )
  66. mean = mean + features.getRow(i);
  67. }
  68. void PCA::calculateBasis(const NICE::Matrix &features,
  69. const uint targetDimension, const bool adaptive,
  70. const double targetRatio)
  71. {
  72. this->targetDimension = targetDimension;
  73. // dimension of the feature vectors
  74. uint srcFeatureSize = features.cols();
  75. uint mindimension = std::min(this->targetDimension, srcFeatureSize);
  76. NICE::Matrix eigenvectors;
  77. NICE::Vector eigenvalue;
  78. calculateMean(features, mean);
  79. #ifdef NICE_USELIB_TRLAN
  80. EigValues *eig = new EigValuesTRLAN();//fast lanczos TRLAN
  81. #else
  82. EigValues *eig = new EVArnoldi();//Arnoldi for (srcFeatureSize<n)
  83. #endif
  84. NICE::Matrix features_transpose = features.transpose();
  85. GMCovariance C(&features_transpose);
  86. if (adaptive)
  87. {
  88. eig->getEigenvalues(C, eigenvalue, eigenvectors, srcFeatureSize);
  89. }
  90. else
  91. {
  92. eig->getEigenvalues(C, eigenvalue, eigenvectors, mindimension);
  93. }
  94. #ifdef DEBUG
  95. fprintf(stderr, "Eigenvalue Decomposition ready \n");
  96. cerr << eigenvectors << endl;
  97. cerr << eigenvalue << endl;
  98. //sort values
  99. fprintf(stderr, "Eigenvector-Rows:%i Eigenvector-Cols:%i\n", (int)eigenvectors.rows(), (int)eigenvectors.cols());
  100. #endif
  101. multimap<double, NICE::Vector> map;
  102. double sumeigen = 0.0;
  103. NICE::Vector ratio(eigenvectors.cols());
  104. for (uint i = 0; i < eigenvectors.cols(); i++)//every eigenvector
  105. {
  106. NICE::Vector eigenvector(srcFeatureSize);
  107. for (uint k = 0; k < srcFeatureSize; k++)
  108. {
  109. eigenvector[k] = eigenvectors(k, i);
  110. }
  111. map.insert(pair<double, NICE::Vector> (eigenvalue[i], eigenvector));
  112. sumeigen += eigenvalue[i];
  113. }
  114. //compute basis size
  115. if (adaptive)
  116. { //compute target dimension
  117. uint dimensioncount = 0;
  118. double addedratio = 0.0;
  119. multimap<double, NICE::Vector>::reverse_iterator it = map.rbegin();
  120. while (addedratio <= targetRatio && it != map.rend())
  121. {
  122. //calc ratio
  123. ratio[dimensioncount] = (*it).first / sumeigen;
  124. addedratio += ratio[dimensioncount];
  125. dimensioncount++;
  126. it++;
  127. }
  128. this->targetDimension = dimensioncount;
  129. }
  130. mindimension = std::min(this->targetDimension, srcFeatureSize);
  131. this->targetDimension = mindimension;
  132. basis = NICE::Matrix(srcFeatureSize, mindimension);
  133. //get sorted values
  134. uint count = 0;
  135. multimap<double, NICE::Vector>::reverse_iterator it = map.rbegin();
  136. while (count < this->targetDimension && it != map.rend())
  137. {
  138. NICE::Vector eigenvector = (*it).second;
  139. //put eigenvector into column
  140. for (uint k = 0; k < srcFeatureSize; k++)
  141. {
  142. basis(k, count) = eigenvector[k];
  143. }
  144. //calc ratio
  145. ratio[count] = (*it).first / sumeigen;
  146. count++;
  147. it++;
  148. }
  149. //normalization matrix / modify variance to 1 for all eigenvectors
  150. normalization = NICE::Matrix(mindimension, mindimension, 0);
  151. for (uint k = 0; k < mindimension; k++)
  152. {
  153. normalization(k, k) = 1.0 / sqrt(eigenvalue[k]);
  154. }
  155. #ifdef DEBUG
  156. cout << "Eigenvalue-absolute:" << eigenvalue << endl;
  157. cout << "Eigenvalue-ratio:" << ratio << endl;
  158. #endif
  159. }
  160. NICE::Vector PCA::getFeatureVector(const NICE::Vector &data,
  161. const bool normalize)
  162. {
  163. //free data of mean
  164. if (normalize)
  165. {
  166. NICE::Vector meanfree(data);
  167. meanfree -= mean;
  168. //Y=W^t * B^T
  169. if(normbasis.rows() == 0)
  170. normbasis.multiply(normalization, basis, false, true);
  171. NICE::Vector tmp;
  172. tmp.multiply(normbasis, meanfree);
  173. return tmp;
  174. }
  175. else
  176. {
  177. NICE::Vector meanfree(data);
  178. meanfree -= mean;
  179. //Y=W^t * B^T
  180. NICE::Vector tmp;
  181. tmp.multiply(basis, meanfree, true);
  182. return tmp;
  183. }
  184. }
  185. NICE::Vector PCA::getMean()
  186. {
  187. return mean;
  188. }
  189. NICE::Matrix PCA::getBasis()
  190. {
  191. return basis;
  192. }
  193. int PCA::getTargetDim()
  194. {
  195. return targetDimension;
  196. }