PCA.cpp 5.2 KB

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