SpectralCluster.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /**
  2. * @file SpectralCluster.cpp
  3. * @brief spectral clustering by kmeans-clustering of eigenvectors
  4. * @author Erik Rodner
  5. * @date 11/13/2007
  6. */
  7. #include <iostream>
  8. #include <core/vector/Distance.h>
  9. #include <core/vector/Eigen.h>
  10. #include <map>
  11. #include "vislearning/math/cluster/SpectralCluster.h"
  12. using namespace OBJREC;
  13. using namespace std;
  14. using namespace NICE;
  15. SpectralCluster::SpectralCluster ( int _noClasses, double alpha ) : noClasses(_noClasses), kmeans(_noClasses)
  16. {
  17. this->alpha = alpha;
  18. }
  19. SpectralCluster::~SpectralCluster()
  20. {
  21. }
  22. void SpectralCluster::getSimilarityMatrix ( const VVector & features,
  23. NICE::Matrix & laplacian,
  24. double alpha )
  25. {
  26. NICE::Matrix distances ( laplacian );
  27. double mindist = numeric_limits<double>::max();
  28. double maxdist = - numeric_limits<double>::max();
  29. long int count = 0;
  30. double mean = 0.0;
  31. double stddev = 0.0;
  32. NICE::EuclidianDistance<double> distance;
  33. for ( int i = 0 ; i < (int)features.size() ; i++ )
  34. {
  35. const NICE::Vector & xi = features[i];
  36. for ( int j = i ; j < (int)features.size() ; j++ )
  37. {
  38. const NICE::Vector & xj = features[j];
  39. // double sim = xi * xj;
  40. double dist = distance.calculate ( xi, xj );
  41. distances(i, j) = dist;
  42. if ( dist < mindist )
  43. mindist = dist;
  44. if ( dist > maxdist )
  45. maxdist = dist;
  46. count++;
  47. mean += dist;
  48. }
  49. }
  50. mean /= count;
  51. for ( int i = 0 ; i < (int)features.size() ; i++ )
  52. for ( int j = i ; j < (int)features.size() ; j++ )
  53. {
  54. double d = ( mean - distances(i, j) );
  55. stddev += d*d;
  56. }
  57. stddev /= count;
  58. double norm = alpha / (2.0 * stddev);
  59. for ( int i = 0 ; i < (int)features.size() ; i++ )
  60. for ( int j = i ; j < (int)features.size() ; j++ )
  61. {
  62. double sim = exp(-distances(i, j) * norm );
  63. laplacian(i, j) = - sim;
  64. laplacian(j, i) = - sim;
  65. }
  66. }
  67. void SpectralCluster::computeLaplacian ( const VVector & features,
  68. NICE::Matrix & laplacian, int method, double alpha )
  69. {
  70. laplacian.set(0.0);
  71. getSimilarityMatrix(features, laplacian, alpha);
  72. NICE::Vector d ( laplacian.rows() );
  73. d.set(0.0);
  74. for ( int i = 0 ; i < (int)laplacian.rows(); i++ )
  75. {
  76. for ( int j = 0 ; j < (int)laplacian.cols(); j++ )
  77. d[i] -=laplacian(i, j);
  78. }
  79. // Now we got the negative weight matrix laplacian : -W
  80. // and the degree matrix : D
  81. // calculate normalization
  82. // D^-1 * L
  83. if ( method == L_RW_NORMALIZED )
  84. {
  85. // L = D^-1 L_unnormalized = I - D^-1*W
  86. for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
  87. for ( int j = 0 ; j < (int)laplacian.cols() ; j++ )
  88. laplacian(i, j) *= (1.0/d[i]);
  89. for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
  90. laplacian(i, i) += 1.0;
  91. } else if ( method == L_UNNORMALIZED ) {
  92. // unnormalized version
  93. // L = D - W
  94. for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
  95. laplacian(i, i) += d[i];
  96. }
  97. }
  98. void SpectralCluster::cluster ( const VVector & features,
  99. VVector & prototypes,
  100. std::vector<double> & weights,
  101. std::vector<int> & assignment )
  102. {
  103. if ( features.size() <= 0 ) {
  104. fprintf (stderr, "FATAL ERROR: not enough features vectors provided\n");
  105. exit(-1);
  106. }
  107. const NICE::Vector & x = features[0];
  108. int dimension = x.size();
  109. NICE::Matrix laplacian ( features.size(), features.size() );
  110. computeLaplacian ( features, laplacian, L_RW_NORMALIZED, alpha );
  111. //computeLaplacian ( features, laplacian, L_UNNORMALIZED, alpha );
  112. NICE::Matrix eigvect;
  113. NICE::Vector eigvals;
  114. NICE::eigenvectorvalues ( laplacian, eigvect, eigvals );
  115. std::map<double, int> eigvals_sorted;
  116. for ( int i = 0 ; i < (int)eigvals.size(); i++ )
  117. {
  118. eigvals_sorted.insert ( make_pair( eigvals[i], i ) );
  119. }
  120. VVector spectral_features;
  121. for ( int i = 0 ; i < (int)eigvect.rows() ; i++ )
  122. {
  123. NICE::Vector eigvec_k ( noClasses );
  124. map<double, int>::const_iterator k = eigvals_sorted.begin();
  125. for ( int j = 0 ; j < noClasses ; j++ )
  126. {
  127. int eigval_index = k->second;
  128. eigvec_k[j] = eigvect(i, eigval_index ) ;
  129. k++;
  130. }
  131. spectral_features.push_back ( eigvec_k );
  132. }
  133. kmeans.cluster ( spectral_features, prototypes, weights, assignment );
  134. // recompute prototypes
  135. for ( int k = 0 ; k < noClasses ; k++ )
  136. {
  137. prototypes[k].resize( dimension );
  138. prototypes[k].set(0);
  139. weights[k] = 0;
  140. }
  141. int j = 0;
  142. for ( VVector::const_iterator i = features.begin();
  143. i != features.end();
  144. i++, j++ )
  145. {
  146. int k = assignment[j];
  147. NICE::Vector & p = prototypes[k];
  148. const NICE::Vector & x = *i;
  149. p += x;
  150. weights[k]++;
  151. }
  152. for ( int k = 0 ; k < noClasses ; k++ )
  153. {
  154. NICE::Vector & p = prototypes[k];
  155. if ( weights[k] <= 0 ) {
  156. fprintf (stderr, "FATAL ERROR: spectral clustering produced empty cluster !\n");
  157. exit(-1);
  158. }
  159. p *= ( 1.0 / weights[k] );
  160. weights[k] = weights[k] / features.size();
  161. }
  162. }