PCA.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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 "core/image/ImageT.h"
  13. #include "core/vector/VectorT.h"
  14. #include "core/vector/MatrixT.h"
  15. #include <iostream>
  16. #include <math.h>
  17. #include <vector>
  18. #include <map>
  19. #include "vislearning/math/algebra/AlgebraTools.h"
  20. #include "vislearning/math/algebra/GenericMatrix.h"
  21. #include "vislearning/math/algebra/EigValues.h"
  22. #ifdef NICE_USELIB_TRLAN
  23. #include "vislearning/math/algebra_trlan/EigValuesTRLAN.h"
  24. #endif
  25. // #include "vislearning/fourier/FourierLibrary.h"
  26. #include "PCA.h"
  27. #include "vislearning/baselib/Gnuplot.h"
  28. #ifdef NICE_USELIB_ICE
  29. #include "core/image/ImageT.h"
  30. #include "core/vector/VectorT.h"
  31. #include "core/vector/MatrixT.h"
  32. #include "core/iceconversion/convertice.h"
  33. #include "core/iceconversion/image_convertice.h"
  34. using namespace ice;
  35. #endif
  36. using namespace OBJREC;
  37. using namespace std;
  38. using namespace NICE;
  39. PCA::PCA(uint dim, uint maxiteration, double mindelta)
  40. {
  41. init(dim, maxiteration, mindelta);
  42. }
  43. PCA::PCA(void)
  44. {
  45. init();
  46. }
  47. PCA::~PCA()
  48. {
  49. }
  50. void PCA::init(uint dim, uint maxiteration, double mindelta)
  51. {
  52. this->targetDimension = dim;
  53. this->maxiteration = maxiteration;
  54. this->mindelta = mindelta;
  55. }
  56. void PCA::restore(istream & is, int format)
  57. {
  58. is >> basis;
  59. is >> normalization;
  60. is >> mean;
  61. is >> targetDimension;
  62. }
  63. void PCA::store(ostream & os, int format) const
  64. {
  65. os << basis << normalization << mean << targetDimension;
  66. }
  67. void PCA::clear()
  68. {
  69. }
  70. void PCA::calculateBasis(const NICE::Matrix &features,
  71. const uint targetDimension, const uint mode)
  72. {
  73. calculateBasis(features, targetDimension, mode, false);
  74. }
  75. void PCA::calculateBasis(const NICE::Matrix &features,
  76. const uint targetDimension, const uint mode, const bool adaptive,
  77. const double targetRatio)
  78. {
  79. this->targetDimension = targetDimension;
  80. uint srcFeatureSize = features.cols();
  81. uint mindimension = std::min(this->targetDimension, srcFeatureSize);
  82. #ifdef DEBUG
  83. cout << "calculateBasis ... stay a while and listen ..." << endl;
  84. #endif
  85. NICE::Matrix eigenvectors;
  86. NICE::Vector eigenvalue;
  87. #ifdef DEBUG
  88. cout << "EigenValue Decomposition Working..." << endl;
  89. #endif
  90. //switch mode: svd, lanczos, broken lanczos, arnoldi
  91. //switch eigenvalue decomposition
  92. switch (mode)
  93. {
  94. case 0:
  95. {
  96. #ifndef NICE_USELIB_ICE
  97. fthrow(Exception, "PCA: ICE needed for mode 0");
  98. #else
  99. #ifdef DEBUG
  100. fprintf(stderr, "PCA: warning covariance computation in progress, memory and time consuming ...!\n");
  101. #endif
  102. ice::Matrix sigma;
  103. ice::Matrix eigenvectors_ice;
  104. ice::Vector eigenvalue_ice;
  105. ice::Matrix features_ice(NICE::makeICEMatrix(features));
  106. Statistics st(srcFeatureSize);
  107. #ifdef DEBUG
  108. fprintf(stderr, "Transform Features ... %d %d \n", features_ice.rows(), features_ice.cols());
  109. #endif
  110. Put(st, features_ice);
  111. ice::Vector mean_ice = Mean(st);
  112. mean = makeEVector(mean_ice);
  113. #ifdef DEBUG
  114. cout << "MEAN: " << mean_ice << endl;
  115. #endif
  116. sigma = Covariance(st);
  117. #ifdef DEBUG
  118. fprintf(stderr, "Covariance Ready \n");
  119. fprintf(stderr, "Eigenvalue Computation ... \n");
  120. #endif
  121. Eigenvalue(sigma, eigenvalue_ice, eigenvectors_ice);
  122. NICE::Matrix eigenvectors_tmp;
  123. eigenvectors_tmp = makeDoubleMatrix(eigenvectors_ice); //bad error
  124. eigenvectors.resize(eigenvectors_tmp.rows(), eigenvectors_tmp.cols());
  125. eigenvectors = eigenvectors_tmp;
  126. eigenvalue = makeEVector(eigenvalue_ice);
  127. #endif
  128. break;
  129. }
  130. case 1:
  131. {
  132. #ifdef DEBUG
  133. fprintf(stderr, "Calc mean \n");
  134. #endif
  135. AlgebraTools::calculateMean(features, mean);
  136. #ifdef DEBUG
  137. fprintf(stderr, "fastest available method \n");
  138. // cerr<<"mean:"<<mean<<endl;
  139. #endif
  140. #ifdef NICE_USELIB_TRLAN
  141. EigValues *eig = new EigValuesTRLAN();//fast lanczos TRLAN
  142. #else
  143. EigValues *eig = new EVArnoldi();//Arnoldi for (srcFeatureSize<n)
  144. #endif
  145. NICE::Matrix features_transpose = features.transpose();
  146. GMCovariance C(&features_transpose);
  147. #ifdef DEBUG
  148. fprintf(stderr, "Perform PCA\n");
  149. fprintf(stderr, "Matrix size %d %d %d %d \n", features.rows(), features.cols(), C.rows(), C.cols());
  150. #endif
  151. if (adaptive)
  152. {
  153. eig->getEigenvalues(C, eigenvalue, eigenvectors, srcFeatureSize);
  154. }
  155. else
  156. {
  157. eig->getEigenvalues(C, eigenvalue, eigenvectors, mindimension);
  158. }
  159. #ifdef DEBUG
  160. fprintf(stderr, "PCA: Computation ready \n");
  161. // cerr<<eigenvectors<<endl;
  162. #endif
  163. #ifdef DEBUG
  164. fprintf(stderr, "PCA: Transpose ready \n");
  165. // cerr<<eigenvectors<<endl;
  166. #endif
  167. break;
  168. }
  169. #ifdef USE_BROKEN_LANCZOS
  170. case 2:
  171. {
  172. //Experimental TODO
  173. #ifdef DEBUG
  174. fprintf(stderr, "Calc mean \n");
  175. #endif
  176. AlgebraTools::calculateMean(features, mean);
  177. #ifdef DEBUG
  178. fprintf(stderr, "Lanczos \n");
  179. #endif
  180. EigValues *eig = new EVLanczos(100, 1e-4);
  181. GMCovariance C(&features.transpose());
  182. if(adaptive)
  183. {
  184. eig->getEigenvalues(C, eigenvalue, eigenvectors, srcFeatureSize);
  185. }
  186. else
  187. {
  188. eig->getEigenvalues(C, eigenvalue, eigenvectors, mindimension); //fast lanczos
  189. }
  190. #ifdef DEBUG
  191. fprintf(stderr, "PCA: Computation ready \n");
  192. #endif
  193. break;
  194. }
  195. #endif
  196. case 3:
  197. {
  198. #ifdef DEBUG
  199. fprintf(stderr, "Calc mean \n");
  200. #endif
  201. AlgebraTools::calculateMean(features, mean);
  202. #ifdef DEBUG
  203. fprintf(stderr, "Arnoldi \n");
  204. #endif
  205. EigValues *eig = new EVArnoldi(100, 1e-4);
  206. NICE::Matrix tmppointer = features.transpose();
  207. GMCovariance C(&tmppointer);
  208. if (adaptive)
  209. {
  210. eig->getEigenvalues(C, eigenvalue, eigenvectors, srcFeatureSize);
  211. }
  212. else
  213. {
  214. eig->getEigenvalues(C, eigenvalue, eigenvectors, mindimension); //fast arnoldi
  215. }
  216. #ifdef DEBUG
  217. fprintf(stderr, "PCA: Computation ready \n");
  218. #endif
  219. #ifdef DEBUG
  220. fprintf(stderr, "PCA: Transpose ready \n");
  221. #endif
  222. break;
  223. }
  224. default:
  225. fprintf(stderr, "PCA: Wrong Computation mode: %d!\n", mode);
  226. break;
  227. }
  228. #ifdef DEBUG
  229. fprintf(stderr, "Eigenvalue Decomposition ready \n");
  230. cerr << eigenvectors << endl;
  231. cerr << eigenvalue << endl;
  232. //sort values
  233. fprintf(stderr, "Eigenvector-Rows:%i Eigenvector-Cols:%i\n", (int)eigenvectors.rows(), (int)eigenvectors.cols());
  234. #endif
  235. multimap<double, NICE::Vector> map;
  236. double sumeigen = 0.0;
  237. NICE::Vector ratio(eigenvectors.cols());
  238. for (uint i = 0; i < eigenvectors.cols(); i++)//every eigenvector
  239. {
  240. NICE::Vector eigenvector(srcFeatureSize);
  241. for (uint k = 0; k < srcFeatureSize; k++)
  242. {
  243. eigenvector[k] = eigenvectors(k, i);
  244. }
  245. map.insert(pair<double, NICE::Vector> (eigenvalue[i], eigenvector));
  246. sumeigen += eigenvalue[i];
  247. }
  248. //compute basis size
  249. if (adaptive)
  250. { //compute target dimension
  251. uint dimensioncount = 0;
  252. double addedratio = 0.0;
  253. multimap<double, NICE::Vector>::reverse_iterator it = map.rbegin();
  254. while (addedratio <= targetRatio && it != map.rend())
  255. {
  256. //calc ratio
  257. ratio[dimensioncount] = (*it).first / sumeigen;
  258. addedratio += ratio[dimensioncount];
  259. dimensioncount++;
  260. it++;
  261. }
  262. this->targetDimension = dimensioncount;
  263. }
  264. mindimension = std::min(this->targetDimension, srcFeatureSize);
  265. this->targetDimension = mindimension;
  266. basis = NICE::Matrix(srcFeatureSize, mindimension);
  267. //get sorted values
  268. uint count = 0;
  269. multimap<double, NICE::Vector>::reverse_iterator it = map.rbegin();
  270. while (count < this->targetDimension && it != map.rend())
  271. {
  272. NICE::Vector eigenvector = (*it).second;
  273. //put eigenvector into column
  274. for (uint k = 0; k < srcFeatureSize; k++)
  275. {
  276. basis(k, count) = eigenvector[k];
  277. }
  278. //calc ratio
  279. ratio[count] = (*it).first / sumeigen;
  280. count++;
  281. it++;
  282. }
  283. //normalization matrix / modify variance to 1 for all eigenvectors
  284. normalization = NICE::Matrix(mindimension, mindimension, 0);
  285. for (uint k = 0; k < mindimension; k++)
  286. {
  287. normalization(k, k) = 1.0 / sqrt(eigenvalue[k]);
  288. }
  289. #ifdef DEBUG
  290. cerr << basis << endl;
  291. // if (mode == 0)
  292. // {
  293. // cout << eigenvectors << endl;
  294. // cout << basis << endl;
  295. // cout << mean << endl;
  296. cout << "Eigenvalue-absolute:" << eigenvalue << endl;
  297. cout << "Eigenvalue-ratio:" << ratio << endl;
  298. // }
  299. #endif
  300. }
  301. NICE::Vector PCA::getFeatureVector(const NICE::Vector &data,
  302. const bool normalize)
  303. {
  304. //free data of mean
  305. if (normalize)
  306. {
  307. NICE::Vector meanfree(data);
  308. meanfree -= mean;
  309. //Y=W^t * B^T
  310. if(normbasis.rows() == 0)
  311. normbasis.multiply(normalization, basis, false, true);
  312. NICE::Vector tmp;
  313. tmp.multiply(normbasis, meanfree);
  314. return tmp;
  315. }
  316. else
  317. {
  318. NICE::Vector meanfree(data);
  319. meanfree -= mean;
  320. //Y=W^t * B^T
  321. NICE::Vector tmp;
  322. tmp.multiply(basis, meanfree, true);
  323. return tmp;
  324. }
  325. }
  326. NICE::Vector PCA::getMean()
  327. {
  328. return mean;
  329. }
  330. NICE::Matrix PCA::getBasis()
  331. {
  332. return basis;
  333. }
  334. int PCA::getTargetDim()
  335. {
  336. return targetDimension;
  337. }