PCA.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. mean.set(0);
  66. for ( uint i = 0 ; i < features.rows(); i++ )
  67. mean = mean + features.getRow ( i );
  68. }
  69. void PCA::calculateBasis ( const NICE::Matrix &features,
  70. const uint targetDimension, const bool adaptive,
  71. const double targetRatio )
  72. {
  73. this->targetDimension = targetDimension;
  74. // dimension of the feature vectors
  75. uint srcFeatureSize = features.cols();
  76. uint mindimension = std::min ( this->targetDimension, srcFeatureSize );
  77. NICE::Matrix eigenvectors;
  78. NICE::Vector eigenvalue;
  79. calculateMean ( features, mean );
  80. #ifdef NICE_USELIB_TRLAN
  81. EigValues *eig;
  82. if(mindimension < 4)
  83. eig = new EVArnoldi();//Arnoldi for (srcFeatureSize<n)
  84. else
  85. eig = new EigValuesTRLAN();//fast lanczos TRLAN
  86. #else
  87. EigValues *eig = new EVArnoldi();//Arnoldi for (srcFeatureSize<n)
  88. #endif
  89. NICE::Matrix features_transpose = features.transpose();
  90. GMCovariance C ( &features_transpose );
  91. if ( adaptive )
  92. {
  93. eig->getEigenvalues ( C, eigenvalue, eigenvectors, srcFeatureSize );
  94. }
  95. else
  96. {
  97. eig->getEigenvalues ( C, eigenvalue, eigenvectors, mindimension );
  98. }
  99. #ifdef DEBUG
  100. fprintf ( stderr, "Eigenvalue Decomposition ready \n" );
  101. cerr << eigenvectors << endl;
  102. cerr << eigenvalue << endl;
  103. //sort values
  104. fprintf ( stderr, "Eigenvector-Rows:%i Eigenvector-Cols:%i\n", ( int ) eigenvectors.rows(), ( int ) eigenvectors.cols() );
  105. #endif
  106. multimap<double, NICE::Vector> map;
  107. double sumeigen = 0.0;
  108. NICE::Vector ratio ( eigenvectors.cols() );
  109. for ( uint i = 0; i < eigenvectors.cols(); i++ ) //every eigenvector
  110. {
  111. NICE::Vector eigenvector ( srcFeatureSize );
  112. for ( uint k = 0; k < srcFeatureSize; k++ )
  113. {
  114. eigenvector[k] = eigenvectors ( k, i );
  115. }
  116. map.insert ( pair<double, NICE::Vector> ( eigenvalue[i], eigenvector ) );
  117. sumeigen += eigenvalue[i];
  118. }
  119. //compute basis size
  120. if ( adaptive )
  121. { //compute target dimension
  122. uint dimensioncount = 0;
  123. double addedratio = 0.0;
  124. multimap<double, NICE::Vector>::reverse_iterator it = map.rbegin();
  125. while ( addedratio <= targetRatio && it != map.rend() )
  126. {
  127. //calc ratio
  128. ratio[dimensioncount] = ( *it ).first / sumeigen;
  129. addedratio += ratio[dimensioncount];
  130. dimensioncount++;
  131. it++;
  132. }
  133. this->targetDimension = dimensioncount;
  134. }
  135. mindimension = std::min ( this->targetDimension, srcFeatureSize );
  136. this->targetDimension = mindimension;
  137. basis = NICE::Matrix ( srcFeatureSize, mindimension );
  138. //get sorted values
  139. uint count = 0;
  140. multimap<double, NICE::Vector>::reverse_iterator it = map.rbegin();
  141. while ( count < this->targetDimension && it != map.rend() )
  142. {
  143. NICE::Vector eigenvector = ( *it ).second;
  144. //put eigenvector into column
  145. for ( uint k = 0; k < srcFeatureSize; k++ )
  146. {
  147. basis ( k, count ) = eigenvector[k];
  148. }
  149. //calc ratio
  150. ratio[count] = ( *it ).first / sumeigen;
  151. count++;
  152. it++;
  153. }
  154. //normalization matrix / modify variance to 1 for all eigenvectors
  155. normalization = NICE::Matrix ( mindimension, mindimension, 0 );
  156. for ( uint k = 0; k < mindimension; k++ )
  157. {
  158. normalization ( k, k ) = 1.0 / sqrt ( eigenvalue[k] );
  159. }
  160. #ifdef DEBUG
  161. cout << "Eigenvalue-absolute:" << eigenvalue << endl;
  162. cout << "Eigenvalue-ratio:" << ratio << endl;
  163. #endif
  164. }
  165. NICE::Vector PCA::getFeatureVector ( const NICE::Vector &data,
  166. const bool normalize )
  167. {
  168. //free data of mean
  169. if ( normalize )
  170. {
  171. NICE::Vector meanfree ( data );
  172. meanfree -= mean;
  173. //Y=W^t * B^T
  174. if ( normbasis.rows() == 0 )
  175. normbasis.multiply ( normalization, basis, false, true );
  176. NICE::Vector tmp;
  177. tmp.multiply ( normbasis, meanfree );
  178. return tmp;
  179. }
  180. else
  181. {
  182. NICE::Vector meanfree ( data );
  183. meanfree -= mean;
  184. //Y=W^t * B^T
  185. NICE::Vector tmp;
  186. tmp.multiply ( basis, meanfree, true );
  187. return tmp;
  188. }
  189. }
  190. NICE::Vector PCA::getMean()
  191. {
  192. return mean;
  193. }
  194. NICE::Matrix PCA::getBasis()
  195. {
  196. return basis;
  197. }
  198. int PCA::getTargetDim()
  199. {
  200. return targetDimension;
  201. }